diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..81f58f53282286779c545691e22ab1ba63b2ac3b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,85 @@ +language: cpp + +os: + - linux + - osx + +env: + global: + # make variables + - OCAMLC=ocamlc.opt + - OCAMLOPT=ocamlopt.opt + - ADD_REVISION=1 + # SAUCE_USERNAME + - secure: SjyKefmjUEXi0IKHGGpcbLAajU0mLHONg8aA8LoY7Q9nAkSN6Aql+fzS38Boq7w1jWn+2FOpr+4jy0l6wVd/bftsF+huFfYpFJmdh8BlKmE0K71zZAral0H1c7YxkuQpPiJCIFGXqtkvev7SWTy0z31u7kuuQeEyW27boXe5cDA= + # SAUCE_ACCESS_KEY + - secure: sUvWUjCyPuWht4seNa4f2VG9DkvXkhZyLZfjJO9TUAHB2JndS16E2j/qrvKEjycyH6w8tU/B9vnjDRvvGrYXxEXcBEwsJVfkorFnRl9uwGCGIYrzjMhssEl3fMYZK7P304f+gAp5ULrDBX2gIaKeSa8lUNRtz2PsZOieE4kMdhk= + matrix: + - TEST=third-party + - TEST=macro + - TEST=neko + - TEST=js + - TEST=php + - TEST=cpp + - TEST=flash9 + - TEST=as3 + - TEST=java + - TEST=cs + - TEST=python + +matrix: + # fast_finish: true #https://github.com/travis-ci/travis-ci/issues/1696 + +before_script: + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + mysql -u root -e "CREATE DATABASE haxe_test;"; + fi + +install: + # For our forks that do not have mult-os enabled... + - if [ -z "${TRAVIS_OS_NAME}" ]; then + export TRAVIS_OS_NAME=linux; + fi + # Install haxe and neko dependencies + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + travis_retry sudo apt-get update -qq; + travis_retry sudo apt-get install ocaml-native-compilers zlib1g-dev libgc-dev -qq; + fi + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + travis_retry brew update; + travis_retry brew install caskroom/cask/brew-cask; + travis_retry brew install ocaml camlp4; + fi + # Install neko + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + travis_retry git clone https://github.com/HaxeFoundation/neko.git ~/neko; + cd ~/neko && make os=${TRAVIS_OS_NAME} -s && sudo make install -s; + cd $TRAVIS_BUILD_DIR; + fi + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + travis_retry brew install neko --HEAD; + fi + +script: + - make -s + - make tools -s + - sudo make install -s + - cd tests/ + - mkdir ~/haxelib && haxelib setup ~/haxelib + - haxe -version + - haxe RunCi.hxml + - neko RunCi.n + +branches: + except: + # A hack to prevent building for tags, assuming they all start with a number. + # https://github.com/travis-ci/travis-ci/issues/1532 + - /^[0-9]/ + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/95a5fa471c27beee8e7c + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..1420963034c4d1208433163db9769da38912ab5d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,12 @@ +Things to check before/while filing an issue: + +- Check if you actually suspect that there's an issue in the Haxe code. If you find yourself writing "How do I..." you may want to consider a different communication channel. Refer to http://haxe.org/community/community-support.html for more information. +- Reduce your code to a minimal example (see http://sscce.org/). In particular avoid library dependencies: If you cannot reproduce your issue without using a specific library, it might not be a Haxe issue to begin with. +- Check if your problems are already resolved in the Haxe development version (for builds see http://builds.haxe.org/). +- Most targets produce readable code. If you suspect the generated code to be wrong, try checking the output. Note that you can add `-D dump=pretty` to your compilation parameters and find the code which is passed to the generators in a `dump` sub directory. + +Other remarks: + +- Sometimes people try to be particularly helpful by not only including broken parts in their code, but also "similar" code which is working. More often than not this is more distracting than helpful. If you want to highlight something like this, consider adding the working code commented out. +- We do not require a classic "What do you see/what do you expect?" form, but in some cases it is hard to figure out where you think the actual problem is otherwise. +- We're keeping this page quite short so there's a higher chance that people actually read it. diff --git a/Makefile b/Makefile index eb8d60ffc9aa0108eb52d5a3b4f47a0db6b2e9df..e912e15a7a8156d712c4d3a40ccd87273c3172a9 100644 --- a/Makefile +++ b/Makefile @@ -1,171 +1,226 @@ -# Haxe compiler Makefile -# -# - use 'make' to build all -# - use 'make haxe' to build only the compiler (not the libraries) -# - if you want to build quickly, install 'ocamlopt.opt' and change OCAMLOPT=ocamlopt.top -# -# Windows users : -# - use 'make -f Makefile.win' to build for Windows -# - use 'make MSVC=1 -f Makefile.win' to build for Windows with OCaml/MSVC -# -.SUFFIXES : .ml .mli .cmo .cmi .cmx .mll .mly - -INSTALL_DIR=/usr - -OUTPUT=haxe -EXTENSION= -OCAMLOPT=ocamlopt - -CFLAGS= -g -I libs/extlib -I libs/extc -I libs/neko -I libs/javalib -I libs/ziplib -I libs/swflib -I libs/xml-light -I libs/ttflib - -CC_CMD = $(OCAMLOPT) $(CFLAGS) -c $< -CC_PARSER_CMD = $(OCAMLOPT) -pp camlp4o $(CFLAGS) -c parser.ml - -LIBS=unix.cmxa str.cmxa libs/extlib/extLib.cmxa libs/xml-light/xml-light.cmxa libs/swflib/swflib.cmxa \ - libs/extc/extc.cmxa libs/neko/neko.cmxa libs/javalib/java.cmxa libs/ziplib/zip.cmxa libs/ttflib/ttf.cmxa - -NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib -lz - -RELDIR=../../.. - -EXPORT=../../../projects/motionTools/haxe - -MODULES=ast type lexer common genxml parser typecore optimizer typeload \ -codegen gencommon genas3 gencpp genjs genneko genphp genswf8 \ - genswf9 genswf genjava gencs interp typer matcher dce main - -export HAXE_STD_PATH=$(CURDIR)/std - -all: libs haxe - -libs: - make -C libs/extlib opt - make -C libs/extc native - make -C libs/neko - make -C libs/javalib - make -C libs/ziplib - make -C libs/swflib - make -C libs/xml-light xml-light.cmxa - make -C libs/ttflib - -haxe: $(MODULES:=.cmx) - $(OCAMLOPT) -o $(OUTPUT) $(NATIVE_LIBS) $(LIBS) $(MODULES:=.cmx) - -haxelib: - $(CURDIR)/$(OUTPUT) --cwd "$(CURDIR)/std/tools/haxelib" haxelib.hxml - cp std/tools/haxelib/haxelib$(EXTENSION) haxelib$(EXTENSION) - -haxedoc: - $(CURDIR)/$(OUTPUT) --cwd "$(CURDIR)/std/tools/haxedoc" haxedoc.hxml - cp std/tools/haxedoc/haxedoc$(EXTENSION) haxedoc$(EXTENSION) - -tools: haxelib haxedoc - -install: - cp haxe $(INSTALL_DIR)/bin/haxe - rm -rf $(INSTALL_DIR)/lib/haxe/std - -mkdir -p $(INSTALL_DIR)/lib/haxe - svn export std/ $(INSTALL_DIR)/lib/haxe/std - -mkdir -p $(INSTALL_DIR)/lib/haxe/lib - chmod -R a+rx $(INSTALL_DIR)/lib/haxe - chmod 777 $(INSTALL_DIR)/lib/haxe/lib - cp std/tools/haxelib/haxelib.sh $(INSTALL_DIR)/bin/haxelib - cp std/tools/haxedoc/haxedoc.sh $(INSTALL_DIR)/bin/haxedoc - chmod a+rx $(INSTALL_DIR)/bin/haxe $(INSTALL_DIR)/bin/haxelib $(INSTALL_DIR)/bin/haxedoc - -# will install native version of the tools instead of script ones -install_tools: tools - cp haxelib ${INSTALL_DIR}/bin/haxelib - cp haxedoc ${INSTALL_DIR}/bin/haxedoc - chmod a+rx $(INSTALL_DIR)/bin/haxelib $(INSTALL_DIR)/bin/haxedoc - -uninstall: - rm -rf $(INSTALL_DIR)/bin/haxe $(INSTALL_DIR)/bin/haxelib $(INSTALL_DIR)/lib/haxe - -export: - cp haxe*.exe doc/CHANGES.txt $(EXPORT) - rsync -a --exclude .svn --exclude *.n --exclude std/libs --delete std $(EXPORT) - -codegen.cmx: optimizer.cmx typeload.cmx typecore.cmx type.cmx genxml.cmx common.cmx ast.cmx - -common.cmx: type.cmx ast.cmx - -dce.cmx: ast.cmx common.cmx type.cmx - -genas3.cmx: type.cmx common.cmx codegen.cmx ast.cmx - -gencommon.cmx: type.cmx common.cmx codegen.cmx ast.cmx - -gencpp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx - -gencs.cmx: type.cmx lexer.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx - -genjava.cmx: type.cmx gencommon.cmx common.cmx codegen.cmx ast.cmx - -genjs.cmx: type.cmx optimizer.cmx lexer.cmx common.cmx codegen.cmx ast.cmx - -genneko.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx - -genphp.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx - -genswf.cmx: type.cmx genswf9.cmx genswf8.cmx common.cmx ast.cmx - -genswf8.cmx: type.cmx lexer.cmx common.cmx codegen.cmx ast.cmx - -genswf9.cmx: type.cmx lexer.cmx genswf8.cmx common.cmx codegen.cmx ast.cmx - -genxml.cmx: type.cmx lexer.cmx common.cmx ast.cmx - -interp.cmx: typecore.cmx type.cmx lexer.cmx genneko.cmx common.cmx codegen.cmx ast.cmx genswf.cmx parser.cmx - -matcher.cmx: optimizer.cmx codegen.cmx typecore.cmx type.cmx typer.cmx common.cmx ast.cmx - -main.cmx: dce.cmx matcher.cmx typer.cmx typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genxml.cmx genswf.cmx genphp.cmx genneko.cmx genjs.cmx gencpp.cmx genas3.cmx common.cmx codegen.cmx ast.cmx gencommon.cmx genjava.cmx gencs.cmx - -optimizer.cmx: typecore.cmx type.cmx parser.cmx common.cmx ast.cmx - -parser.cmx: parser.ml lexer.cmx common.cmx ast.cmx - $(CC_PARSER_CMD) - -type.cmx: ast.cmx - -typecore.cmx: type.cmx common.cmx ast.cmx - -typeload.cmx: typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx common.cmx ast.cmx - -typer.cmx: typeload.cmx typecore.cmx type.cmx parser.cmx optimizer.cmx lexer.cmx interp.cmx genneko.cmx genjs.cmx common.cmx codegen.cmx ast.cmx - -lexer.cmx: lexer.ml - -lexer.cmx: ast.cmx - - -clean: clean_libs clean_haxe clean_tools - -clean_libs: - make -C libs/extlib clean - make -C libs/extc clean - make -C libs/neko clean - make -C libs/ziplib clean - make -C libs/javalib clean - make -C libs/swflib clean - make -C libs/xml-light clean - make -C libs/ttflib clean - -clean_haxe: - rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) lexer.ml - -clean_tools: - rm -f $(OUTPUT) haxelib haxedoc - -# SUFFIXES -.ml.cmx: - $(CC_CMD) - -.mli.cmi: - $(CC_CMD) - -.mll.ml: - ocamllex $< - -.PHONY: haxe libs +# Haxe compiler Makefile +# +# - use 'make' to build all +# - use 'make haxe' to build only the compiler (not the libraries) +# - if you want to build quickly, install 'ocamlopt.opt' and change OCAMLOPT=ocamlopt.opt +# +# Windows users : +# - use 'make -f Makefile.win' to build for Windows +# - use 'make MSVC=1 -f Makefile.win' to build for Windows with OCaml/MSVC +# +.SUFFIXES : .ml .mli .cmo .cmi .cmx .mll .mly + +INSTALL_DIR=/usr +INSTALL_BIN_DIR=$(INSTALL_DIR)/bin +INSTALL_LIB_DIR=$(INSTALL_DIR)/lib/haxe + +OUTPUT=haxe +EXTENSION= +OCAMLOPT?=ocamlopt +OCAMLC?=ocamlc +LFLAGS= + +CFLAGS= -g -I libs/extlib -I libs/extc -I libs/neko -I libs/javalib -I libs/ziplib -I libs/swflib -I libs/xml-light -I libs/ttflib -I libs/ilib -I libs/objsize + +LIBS=unix str libs/extlib/extLib libs/xml-light/xml-light libs/swflib/swflib \ + libs/extc/extc libs/neko/neko libs/javalib/java libs/ziplib/zip \ + libs/ttflib/ttf libs/ilib/il libs/objsize/objsize + +NATIVE_LIBS=-cclib libs/extc/extc_stubs.o -cclib libs/extc/process_stubs.o -cclib -lz -cclib libs/objsize/c_objsize.o + +ifeq ($(BYTECODE),1) + TARGET_FLAG = bytecode + COMPILER = $(OCAMLC) + LIB_EXT = cma + MODULE_EXT = cmo + NATIVE_LIB_FLAG = -custom +else + TARGET_FLAG = native + COMPILER = $(OCAMLOPT) + LIB_EXT = cmxa + MODULE_EXT = cmx +endif + +CC_CMD = $(COMPILER) $(CFLAGS) -c $< + +CC_PARSER_CMD = $(COMPILER) -pp camlp4o $(CFLAGS) -c parser.ml + +RELDIR=../../.. + +MODULES=ast type lexer common genxml parser typecore optimizer typeload \ + codegen gencommon genas3 gencpp genjs genneko genphp \ + genswf9 genswf genjava gencs genpy interp dce analyzer filters typer matcher version main + +ADD_REVISION?=0 + +BRANCH=$(shell echo $$APPVEYOR_REPO_NAME | grep -q /haxe && echo $$APPVEYOR_REPO_BRANCH || echo $$TRAVIS_REPO_SLUG | grep -q /haxe && echo $$TRAVIS_BRANCH || git rev-parse --abbrev-ref HEAD) +COMMIT_SHA=$(shell git rev-parse --short HEAD) +COMMIT_DATE=$(shell git show -s --format=%ci HEAD | grep -oh ....-..-..) +PACKAGE_FILE_NAME=haxe_$(COMMIT_DATE)_$(BRANCH)_$(COMMIT_SHA) + +# 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 + +all: libs haxe + +libs: + make -C libs/extlib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/extc OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/neko OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/javalib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/ilib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/ziplib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/swflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/xml-light OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/ttflib OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + make -C libs/objsize OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + +haxe: $(MODULES:=.$(MODULE_EXT)) + $(COMPILER) -o $(OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(LIBS:=.$(LIB_EXT)) $(MODULES:=.$(MODULE_EXT)) + +haxelib: + (cd $(CURDIR)/extra/haxelib_src && $(CURDIR)/$(OUTPUT) haxelib.hxml && nekotools boot bin/haxelib.n) + cp extra/haxelib_src/bin/haxelib$(EXTENSION) haxelib$(EXTENSION) + +tools: haxelib + +install: + -rm -f $(INSTALL_LIB_DIR) + -mkdir -p $(INSTALL_LIB_DIR) + rm -rf $(INSTALL_LIB_DIR)/std + cp -rf std $(INSTALL_LIB_DIR)/std + cp -rf extra $(INSTALL_LIB_DIR) + -mkdir -p $(INSTALL_LIB_DIR)/lib + rm -f $(INSTALL_BIN_DIR)/haxe + cp haxe $(INSTALL_LIB_DIR) + ln -s $(INSTALL_LIB_DIR)/haxe $(INSTALL_BIN_DIR)/haxe + chmod -R a+rx $(INSTALL_LIB_DIR) + chmod 777 $(INSTALL_LIB_DIR)/lib + # cp extra/haxelib_src/haxelib_script.sh $(INSTALL_DIR)/bin/haxelib + echo "#!/bin/sh" > $(INSTALL_BIN_DIR)/haxelib + echo "exec haxe -cp $(INSTALL_LIB_DIR)/extra/haxelib_src/src --run tools.haxelib.Main \"\$$@\"" >> $(INSTALL_BIN_DIR)/haxelib + chmod a+rx $(INSTALL_BIN_DIR)/haxe $(INSTALL_BIN_DIR)/haxelib + +# will install native version of the tools instead of script ones +install_tools: tools + cp haxelib ${INSTALL_BIN_DIR}/haxelib + chmod a+rx $(INSTALL_BIN_DIR)/haxelib + +uninstall: + rm -rf $(INSTALL_BIN_DIR)/haxe $(INSTALL_BIN_DIR)/haxelib $(INSTALL_LIB_DIR) + +# Modules + +analyzer.$(MODULE_EXT): ast.$(MODULE_EXT) type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) + +codegen.$(MODULE_EXT): optimizer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) genxml.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +common.$(MODULE_EXT): type.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) + +dce.$(MODULE_EXT): ast.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) type.$(MODULE_EXT) + +filters.$(MODULE_EXT): ast.$(MODULE_EXT) analyzer.$(MODULE_EXT) common.$(MODULE_EXT) type.$(MODULE_EXT) dce.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT) + +genas3.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +gencommon.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) + +gencpp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) gencommon.$(MODULE_EXT) + +gencs.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) + +genjava.$(MODULE_EXT): type.$(MODULE_EXT) gencommon.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genjs.$(MODULE_EXT): type.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genneko.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genphp.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genpy.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genswf.$(MODULE_EXT): type.$(MODULE_EXT) genswf9.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +genswf9.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) + +genxml.$(MODULE_EXT): type.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +interp.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) lexer.$(MODULE_EXT) genneko.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) genswf.$(MODULE_EXT) genjava.$(MODULE_EXT) gencs.$(MODULE_EXT) parser.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) + +matcher.$(MODULE_EXT): optimizer.$(MODULE_EXT) codegen.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) typer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +main.$(MODULE_EXT): filters.$(MODULE_EXT) matcher.$(MODULE_EXT) typer.$(MODULE_EXT) typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genxml.$(MODULE_EXT) genswf.$(MODULE_EXT) genphp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) gencpp.$(MODULE_EXT) genas3.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) gencommon.$(MODULE_EXT) genjava.$(MODULE_EXT) gencs.$(MODULE_EXT) genpy.$(MODULE_EXT) version.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT) + +optimizer.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +parser.$(MODULE_EXT): parser.ml lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + $(CC_PARSER_CMD) + +type.$(MODULE_EXT): ast.$(MODULE_EXT) + +typecore.$(MODULE_EXT): type.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +typeload.$(MODULE_EXT): typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) common.$(MODULE_EXT) ast.$(MODULE_EXT) + +typer.$(MODULE_EXT): typeload.$(MODULE_EXT) typecore.$(MODULE_EXT) type.$(MODULE_EXT) parser.$(MODULE_EXT) optimizer.$(MODULE_EXT) lexer.$(MODULE_EXT) interp.$(MODULE_EXT) genneko.$(MODULE_EXT) genjs.$(MODULE_EXT) common.$(MODULE_EXT) codegen.$(MODULE_EXT) ast.$(MODULE_EXT) filters.$(MODULE_EXT) gencommon.$(MODULE_EXT) + +lexer.$(MODULE_EXT): lexer.ml + +lexer.$(MODULE_EXT): ast.$(MODULE_EXT) + +ast.$(MODULE_EXT): + +version.$(MODULE_EXT): + $(MAKE) -f Makefile.version_extra -s ADD_REVISION=$(ADD_REVISION) BRANCH=$(BRANCH) COMMIT_SHA=$(COMMIT_SHA) COMMIT_DATE=$(COMMIT_DATE) > version.ml + $(COMPILER) $(CFLAGS) -c version.ml + +# Package + +package_bin: + mkdir -p out + rm -rf $(PACKAGE_FILE_NAME) $(PACKAGE_FILE_NAME).tar.gz + # Copy the package contents to $(PACKAGE_FILE_NAME) + mkdir -p $(PACKAGE_FILE_NAME) + cp -r $(OUTPUT) haxelib$(EXTENSION) std extra/LICENSE.txt extra/CONTRIB.txt extra/CHANGES.txt $(PACKAGE_FILE_NAME) + # archive + tar -zcf out/$(PACKAGE_FILE_NAME).tar.gz $(PACKAGE_FILE_NAME) + rm -r $(PACKAGE_FILE_NAME) + +# Clean + +clean: clean_libs clean_haxe clean_tools + +clean_libs: + make -C libs/extlib clean + make -C libs/extc clean + make -C libs/neko clean + make -C libs/ziplib clean + make -C libs/javalib clean + make -C libs/ilib clean + make -C libs/swflib clean + make -C libs/xml-light clean + make -C libs/ttflib clean + make -C libs/objsize clean + +clean_haxe: + rm -f $(MODULES:=.obj) $(MODULES:=.o) $(MODULES:=.cmx) $(MODULES:=.cmi) $(MODULES:=.cmo) lexer.ml $(OUTPUT) + +clean_tools: + rm -f $(OUTPUT) haxelib + +# SUFFIXES + +.ml.cmx: + $(CC_CMD) + +.ml.cmo: + $(CC_CMD) + +.mll.ml: + ocamllex $< + +.PHONY: haxe libs version.cmx version.cmo haxelib diff --git a/Makefile.version_extra b/Makefile.version_extra new file mode 100644 index 0000000000000000000000000000000000000000..991233b6d5698d399daa2c78e991c74f805281f5 --- /dev/null +++ b/Makefile.version_extra @@ -0,0 +1,11 @@ +# 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 4064979391be99769738d8335111dc777b268937..d00c42c4c88e5025d491883cd10f672ed14d0a8a 100644 --- a/Makefile.win +++ b/Makefile.win @@ -6,15 +6,20 @@ EXTENSION=.exe OCAMLOPT=ocamlopt.opt kill: - -@taskkill /F /IM haxe.exe 2>/dev/null + -@taskkill /F /IM haxe.exe # allow Ocaml/Mingw as well NATIVE_LIBS += -I "c:/program files/mingw/lib/" +# use make WODI=wodi32 -f Makefile.win to build using WODI 32bit +ifdef WODI +NATIVE_LIBS += -I "/opt/${WODI}/lib" +endif + # use make MSVC=1 -f Makefile.win to build for OCaml/MSVC ifeq (${MSVC}, 1) -NATIVE_LIBS = shell32.lib libs/extc/extc_stubs.obj libs/extc/zlib/zlib.lib +NATIVE_LIBS = shell32.lib libs/extc/extc_stubs.obj libs/extc/process_stubs.obj libs/extc/zlib/zlib.lib libs/objsize/c_objsize.obj endif ifeq (${MSVC_OUTPUT}, 1) @@ -28,4 +33,19 @@ endif ifdef FILTER CC_CMD=($(OCAMLOPT) $(CFLAGS) -c $< 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1) CC_PARSER_CMD=($(OCAMLOPT) -pp camlp4o $(CFLAGS) -c parser.ml 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1) -endif \ No newline at end of file +endif + +package_bin: + mkdir -p out + rm -rf $(PACKAGE_FILE_NAME) $(PACKAGE_FILE_NAME).zip temp.zip + # Copy the package contents to $(PACKAGE_FILE_NAME) + # Using poor man's cp (zip then unzip), because cp in cygwin is quite broken + mkdir -p $(PACKAGE_FILE_NAME) + 7za a -y -tzip -mx0 temp.zip $(OUTPUT) haxelib$(EXTENSION) std > log.txt || type log.txt + cd extra && 7za a -y -tzip -mx0 ../temp.zip LICENSE.txt CONTRIB.txt CHANGES.txt > log.txt || type log.txt + 7za x -y temp.zip -o$(PACKAGE_FILE_NAME) > log.txt || type log.txt + rm temp.zip + # archive + 7za a -r -tzip out/$(PACKAGE_FILE_NAME).zip $(PACKAGE_FILE_NAME) > log.txt || type log.txt + rm -r $(PACKAGE_FILE_NAME) + rm log.txt extra/log.txt \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..51bf386e446eb2de4b9b499699356a4ae832fb8f --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ + +# [Haxe logo](http://haxe.org) - [The Cross-Platform Toolkit](http://haxe.org) +[![TravisCI Build Status](https://travis-ci.org/HaxeFoundation/haxe.svg?branch=development)](https://travis-ci.org/HaxeFoundation/haxe) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HaxeFoundation/haxe?branch=development&svg=true)](https://ci.appveyor.com/project/HaxeFoundation/haxe) +[![SauceLabs Test Status](https://saucelabs.com/buildstatus/haxe)](https://saucelabs.com/u/haxe) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/HaxeFoundation/haxe?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +Haxe is an open source toolkit that allows you to easily build cross-platform tools and applications that target many mainstream platforms. The Haxe toolkit includes: + + * **The Haxe programming language**, a modern, high-level, strictly-typed programming language + * **The Haxe cross-compiler**, a state-of-the-art, lightning-speed compiler for many targets + * **The Haxe standard library**, a complete, cross-platform library of common functionality + +Haxe allows you to compile for the following targets: + + * ActionScript 3 + * C++ + * C# + * Flash + * Java + * JavaScript + * NekoVM + * PHP + * Python + +You can try Haxe directly from your browser at [try.haxe.org](http://try.haxe.org)! + +For more information about Haxe, head to the [offical Haxe website](http://haxe.org). + +## License + +The Haxe project has several licenses, covering different parts of the projects. + + * The Haxe compiler is released under the GNU General Public License version 2 or any later version. + * The Haxe libraries are released under a "two-clause" BSD license. + * The Neko runtime is licensed under the GNU Lesser General Public License version 2.1 or any later version. + +For the complete Haxe licenses, please see http://haxe.org/foundation/open-source.html or [extra/LICENSE.txt](extra/LICENSE.txt). + +## Installing Haxe + +The latest stable release is [Haxe 3.2.0-rc2](http://haxe.org/download/version/3.2.0-rc.2/). Pre-built binaries are available for your platform: + + * **[Windows installer](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-win.exe)** + * **[Windows binaries](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-win.zip)** + * **[OSX installer](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-osx-installer.pkg)** + * **[OSX binaries](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-osx.tar.gz)** + * **[Linux 32-bit binaries](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-linux32.tar.gz)** + * **[Linux 64-bit binaries](http://haxe.org/download/file/3.2.0-rc.2/haxe-3.2.0-rc2-linux64.tar.gz)** + +Automated development builds are available from [build.haxe.org](http://build.haxe.org). + +## Building from source + + 1. Clone the repository using git. Be sure to initialize and fetch the submodules. + + git clone --recursive git://github.com/HaxeFoundation/haxe.git + cd haxe + + 2. Follow the [documentation on building Haxe for your platform](http://haxe.org/documentation/introduction/building-haxe.html). + +## Using Haxe + +For information on on using Haxe, consult the [Haxe documentation](http://haxe.org/documentation): + + * [Haxe Introduction](http://haxe.org/documentation/introduction), an introduction to the Haxe toolkit + * [The Haxe Manual](http://haxe.org/manual), the reference manual for the Haxe language + * [Haxe API](http://api.haxe.org), documentation for the Haxe standard and native APIs + * [Haxelib](http://lib.haxe.org), a repository of Haxe libraries for a variety of needs + +## Community + +You can get help and talk with fellow Haxers from around the world via: + + * the [official Haxe Google Group](https://groups.google.com/forum/#!forum/haxelang) + * the [Haxe IRC chatroom](http://unic0rn.github.io/tiramisu/haxe), #haxe on chat.freenode.net + +## Version compatibility + +Haxe | neko +---- | ----- +2.* | 1.* +3.0.0 | 2.0.0 +3.1.3 | 2.0.0 diff --git a/analyzer.ml b/analyzer.ml new file mode 100644 index 0000000000000000000000000000000000000000..e5933e37734879a422a8c014f66f6e10e4524194 --- /dev/null +++ b/analyzer.ml @@ -0,0 +1,1667 @@ +open Ast +open Type +open Common +open Typecore + +let s_expr = s_expr (s_type (print_context())) +let s_expr_pretty = s_expr_pretty "" (s_type (print_context())) +let debug e = print_endline (s_expr e) +let debug_pretty s e = Printf.printf "%s %s\n" s (s_expr_pretty e) + +let flag_no_check = "no_check" +let flag_check = "check" +let flag_no_const_propagation = "no_const_propagation" +let flag_const_propagation = "const_propagation" +let flag_no_local_dce = "no_local_dce" +let flag_local_dce = "local_dce" +let flag_ignore = "ignore" +let flag_no_simplification = "no_simplification" +let flag_check_has_effect = "check_has_effect" +let flag_no_check_has_effect = "no_check_has_effect" + +let has_analyzer_option meta s = + try + let rec loop ml = match ml with + | (Meta.Analyzer,el,_) :: ml -> + if List.exists (fun (e,p) -> + match e with + | EConst(Ident s2) when s = s2 -> true + | _ -> false + ) el then + true + else + loop ml + | _ :: ml -> + loop ml + | [] -> + false + in + loop meta + with Not_found -> + false + +let is_ignored meta = + try + let rec loop ml = match ml with + | (Meta.Analyzer,el,_) :: ml -> + if List.exists (fun (e,p) -> + match e with + | EConst(Ident s2) when flag_ignore = s2 -> true + | _ -> false + ) el then + true + else + loop ml + | (Meta.HasUntyped,_,_) :: _ -> + true + | _ :: ml -> + loop ml + | [] -> + false + in + loop meta + with Not_found -> + false + +let rec get_type_meta t = match t with + | TMono r -> + begin match !r with + | None -> raise Not_found + | Some t -> get_type_meta t + end + | TLazy f -> + get_type_meta (!f()) + | TInst(c,_) -> + c.cl_meta + | TEnum(en,_) -> + en.e_meta + | TAbstract(a,_) -> + a.a_meta + | TType(t,_) -> + t.t_meta + | TAnon _ | TFun _ | TDynamic _ -> + raise Not_found + +let type_has_analyzer_option t s = + try + has_analyzer_option (get_type_meta t) s + with Not_found -> + false + +let is_enum_type t = match follow t with + | TEnum(_) -> true + | _ -> false + +let rec awkward_get_enum_index com e = match e.eexpr with + | TArray(e1,{eexpr = TConst(TInt i)}) when com.platform = Js && Int32.to_int i = 1 && is_enum_type e1.etype -> + e1 + | TCall({eexpr = TField(e1, FDynamic "__Index")},[]) when com.platform = Cpp && is_enum_type e1.etype -> + e1 + | TField(e1,FDynamic "index") when com.platform = Neko && is_enum_type e1.etype -> + e1 + | TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) -> + awkward_get_enum_index com e1 + | _ -> + raise Not_found + +(* + This module simplifies the AST by introducing temporary variables for complex expressions in many places. + In particular, it ensures that no branching can occur in value-places so that we can later insert SSA PHI + nodes without worrying about their placement. +*) +module Simplifier = struct + let mk_block_context com = + let block_el = ref [] in + let push e = block_el := e :: !block_el in + let assign ev e = + let mk_assign e2 = match e2.eexpr with + | TBreak | TContinue | TThrow _ | TReturn _ -> e2 + | _ -> mk (TBinop(OpAssign,ev,e2)) e2.etype e2.epos + in + let rec loop e = match e.eexpr with + | TBlock el -> + begin match List.rev el with + | e1 :: el -> + let el = List.rev ((loop e1) :: el) in + {e with eexpr = TBlock el} + | _ -> + mk_assign e + end + | TIf(e1,e2,eo) -> + let e2 = loop e2 in + let eo = match eo with None -> None | Some e3 -> Some (loop e3) in + {e with eexpr = TIf(e1,e2,eo)} + | TSwitch(e1,cases,edef) -> + let cases = List.map (fun (el,e) -> + let e = loop e in + el,e + ) cases in + let edef = match edef with None -> None | Some edef -> Some (loop edef) in + {e with eexpr = TSwitch(e1,cases,edef)} + | TTry(e1,catches) -> + let e1 = loop e1 in + let catches = List.map (fun (v,e) -> + let e = loop e in + v,e + ) catches in + {e with eexpr = TTry(e1,catches)} + | TParenthesis e1 | TMeta(_,e1) -> + loop e1 (* this is still weird, have to review *) +(* | TBinop(OpAssign,({eexpr = TLocal _} as e1),e2) -> + push e; + mk_assign e1 *) +(* | TBinop(OpAssignOp op,({eexpr = TLocal _} as e1),e2) -> + push e; + mk_assign e1 *) + | _ -> + mk_assign e + in + loop e + in + let declare_temp t eo p = + let v = alloc_var "tmp" t in + v.v_meta <- [Meta.CompilerGenerated,[],p]; + let e_v = mk (TLocal v) t p in + let declare e_init = + let e = mk (TVar (v,e_init)) com.basic.tvoid p in + push e; + in + let e_v = match eo with + | None -> + declare None; + e_v + | Some e1 -> + begin match e1.eexpr with + | TThrow _ | TReturn _ | TBreak | TContinue -> + e1 + | _ -> + let rec loop e_v e = match e.eexpr with + | TParenthesis e1 -> + loop {e_v with eexpr = TParenthesis e_v} e1 + | TMeta(m,e1) -> + loop {e_v with eexpr = TMeta(m,e_v)} e1 + | _ -> + e_v,e + in + let e_v',e1 = loop e_v e1 in + let e1 = assign e_v e1 in + begin match e1.eexpr with + | TBinop(OpAssign,{eexpr = TLocal v1},e2) when v == v1 -> + declare (Some e2) + | _ -> + declare None; + push e1 + end; + e_v' + end + in + e_v + in + let rec push_block () = + let cur = !block_el in + block_el := []; + fun () -> + let added = !block_el in + block_el := cur; + List.rev added + and block f el = + let close = push_block() in + List.iter (fun e -> + push (f e) + ) el; + close() + in + block,declare_temp,fun () -> !block_el + + let apply com e = + let block,declare_temp,close_block = mk_block_context com in + let skip_binding ?(allow_tlocal=false) e = + let rec loop e = + match e.eexpr with + | TConst _ | TTypeExpr _ | TFunction _ -> () + | TLocal _ when allow_tlocal -> () + | TParenthesis e1 | TCast(e1,None) -> Type.iter loop e + | TField(_,(FStatic(c,cf) | FInstance(c,_,cf))) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> () + | TField({eexpr = TLocal _},_) when allow_tlocal -> () + | TCall({eexpr = TField(_,(FStatic(c,cf) | FInstance(c,_,cf)))},el) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> () + | TCall({eexpr = TLocal { v_name = "__cpp__" } },_) -> () + | TField(_,FEnum _) -> () + | TField(_,FDynamic _) -> () + | _ when (try ignore(awkward_get_enum_index com e); true with Not_found -> false) -> () + | _ -> raise Exit + in + try + loop e; + true + with Exit -> + begin match follow e.etype with + | TAbstract({a_path = [],"Void"},_) -> true + | TInst ({ cl_path = [],"Array" }, _) when com.platform = Cpp -> true + | _ -> false + end + in + let has_unbound = ref false in + let rec loop e = match e.eexpr with + | TCall({eexpr = TLocal v | TField({eexpr = TLocal v},_)},_) | TField({eexpr = TLocal v},_) | TLocal v when Meta.has Meta.Unbound v.v_meta && v.v_name <> "`trace" -> + has_unbound := true; + e + | TBlock el -> + {e with eexpr = TBlock (block loop el)} + | TCall({eexpr = TField(_,(FStatic(c,cf) | FInstance(c,_,cf)))},el) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> + e + | TField(_,(FStatic(c,cf) | FInstance(c,_,cf))) when has_analyzer_option cf.cf_meta flag_no_simplification || has_analyzer_option c.cl_meta flag_no_simplification -> + e + | TCall(e1,el) -> + let rec is_valid_call_target e = match e.eexpr with + | TFunction _ | TField _ | TLocal _ | TConst (TSuper) -> + true + | TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) -> + is_valid_call_target e1 + | _ -> + false + in + let e1 = if is_valid_call_target e1 then + loop e1 + else + bind e1 + in + let check e t = + if type_has_analyzer_option t flag_no_simplification then e + else bind e + in + let el = match e1.eexpr,follow e1.etype with + | TConst TSuper,_ when com.platform = Java || com.platform = Cs -> + (* they hate you if you mess up the super call *) + el + | _,TFun _ | TConst TSuper,_ -> + Codegen.UnificationCallback.check_call check el e1.etype + | _ -> + (* too dangerous *) + List.map loop el + in + {e with eexpr = TCall(e1,el)} + | TNew(c,tl,el) -> + {e with eexpr = TNew(c,tl,ordered_list el)} + | TArrayDecl el -> + {e with eexpr = TArrayDecl (ordered_list el)} + | TObjectDecl fl -> + let el = ordered_list (List.map snd fl) in + {e with eexpr = TObjectDecl (List.map2 (fun (n,_) e -> n,e) fl el)} + | TBinop(OpBoolAnd | OpBoolOr as op,e1,e2) -> + let e1 = loop e1 in + let e_then = mk (TBlock (block loop [e2])) e2.etype e2.epos in + let e_if,e_else = if op = OpBoolOr then + mk (TUnop(Not,Prefix,e1)) com.basic.tbool e.epos,mk (TConst (TBool(true))) com.basic.tbool e.epos + else + e1,mk (TConst (TBool(false))) com.basic.tbool e.epos + in + loop (mk (TIf(e_if,e_then,Some e_else)) com.basic.tbool e.epos) + | TBinop((OpAssign | OpAssignOp _) as op,{eexpr = TArray(e11,e12)},e2) -> + let e1 = match ordered_list [e11;e12] with + | [e1;e2] -> + {e with eexpr = TArray(e1,e2)} + | _ -> + assert false + in + let e2 = bind e2 in + {e with eexpr = TBinop(op,e1,e2)} + | TBinop((OpAssign | OpAssignOp _) as op,e1,e2) -> + let e2 = bind ~allow_tlocal:true e2 in + let e1 = loop e1 in + {e with eexpr = TBinop(op,e1,e2)} + | TBinop(op,e1,e2) -> + begin match ordered_list [e1;e2] with + | [e1;e2] -> + {e with eexpr = TBinop(op,e1,e2)} + | _ -> + assert false + end + | TArray(e1,e2) -> + begin match ordered_list [e1;e2] with + | [e1;e2] -> + {e with eexpr = TArray(e1,e2)} + | _ -> + assert false + end + | TWhile(e1,e2,flag) when (match e1.eexpr with TConst(TBool true) | TParenthesis {eexpr = TConst(TBool true)} -> false | _ -> true) -> + let p = e.epos in + let e_break = mk TBreak t_dynamic p in + let e_not = mk (TUnop(Not,Prefix,Codegen.mk_parent e1)) e1.etype e1.epos in + let e_if eo = mk (TIf(e_not,e_break,eo)) com.basic.tvoid p in + let rec map_continue e = match e.eexpr with + | TContinue -> + (e_if (Some e)) + | TWhile _ | TFor _ -> + e + | _ -> + Type.map_expr map_continue e + in + let e2 = if flag = NormalWhile then e2 else map_continue e2 in + let e_if = e_if None in + let e_if = mk (TMeta((Meta.Custom ":whileCond",[],e_if.epos), e_if)) e_if.etype e_if.epos in + let e_block = if flag = NormalWhile then Type.concat e_if e2 else Type.concat e2 e_if in + let e_true = mk (TConst (TBool true)) com.basic.tbool p in + let e = mk (TWhile(Codegen.mk_parent e_true,e_block,NormalWhile)) e.etype p in + loop e + | TFor(v,e1,e2) -> + let e1 = bind e1 in + let e2 = loop e2 in + {e with eexpr = TFor(v,e1,e2)} + | TIf(e1,e2,eo) -> + let e1 = bind e1 in + let e2 = loop e2 in + let eo = match eo with None -> None | Some e -> Some (loop e) in + {e with eexpr = TIf(e1,e2,eo)} + | TSwitch (e1,cases,eo) -> + let e1 = bind e1 in + let cases = List.map (fun (el,e) -> + let el = List.map loop el in + let e = loop e in + el,e + ) cases in + let eo = match eo with None -> None | Some e -> Some (loop e) in + {e with eexpr = TSwitch(e1,cases,eo)} + | TVar(v,Some e1) -> + let e1 = match e1.eexpr with + | TFunction _ -> loop e1 + | TArrayDecl [{eexpr = TFunction _}] -> loop e1 + | _ -> bind ~allow_tlocal:true e1 + in + {e with eexpr = TVar(v,Some e1)} + | TUnop((Neg | NegBits | Not) as op,flag,e1) -> + let e1 = bind e1 in + {e with eexpr = TUnop(op,flag,e1)} + | TField(e1,fa) -> + let e1 = bind ~allow_tlocal:true e1 in + {e with eexpr = TField(e1,fa)} + | TReturn (Some ({eexpr = TThrow _ | TReturn _} as e1)) -> + loop e1 (* this is a bit hackish *) + | TReturn (Some e1) -> + let e1 = bind e1 in + {e with eexpr = TReturn (Some e1)} + | TThrow e1 -> + let e1 = bind e1 in + {e with eexpr = TThrow e1} + | TCast(e1,mto) -> + let e1 = bind ~allow_tlocal:true e1 in + {e with eexpr = TCast(e1,mto)} + | _ -> + Type.map_expr loop e + and bind ?(allow_tlocal=false) e = + let e = loop e in + if skip_binding ~allow_tlocal e then + e + else + declare_temp e.etype (Some e) e.epos + and ordered_list el = + if List.for_all (skip_binding ~allow_tlocal:true) el then + List.map loop el + else + List.map bind el + in + let e = loop e in + !has_unbound,match close_block() with + | [] -> + e + | el -> + mk (TBlock (List.rev (e :: el))) e.etype e.epos + + let unapply com e = + let var_map = ref IntMap.empty in + let rec get_assignment_to v e = match e.eexpr with + | TBinop(OpAssign,{eexpr = TLocal v2},e2) when v == v2 -> Some e2 + | TBlock [e] -> get_assignment_to v e + | TIf(e1,e2,Some e3) -> + begin match get_assignment_to v e2,get_assignment_to v e3 with + | Some e2,Some e3 -> Some ({e with eexpr = TIf(e1,e2,Some e3)}) + | _ -> None + end + | _ -> None + in + let if_or_op e e1 e2 e3 = match e1.eexpr,e3.eexpr with + | TUnop(Not,Prefix,e1),TConst (TBool true) -> {e with eexpr = TBinop(OpBoolOr,e1,e2)} + | _,TConst (TBool false) -> {e with eexpr = TBinop(OpBoolAnd,e1,e2)} + | _ -> {e with eexpr = TIf(e1,e2,Some e3)} + in + let rec loop e = match e.eexpr with + | TBlock el -> + let rec loop2 el = match el with + | e :: el -> + begin match e.eexpr with + | TVar(v,Some e1) when Meta.has Meta.CompilerGenerated v.v_meta -> + if el = [] then + [loop e1] + else begin + var_map := IntMap.add v.v_id (loop e1) !var_map; + loop2 el + end + | TVar(v,None) when not (com.platform = Php) -> + begin match el with + | {eexpr = TBinop(OpAssign,{eexpr = TLocal v2},e2)} :: el when v == v2 -> + let e = {e with eexpr = TVar(v,Some e2)} in + loop2 (e :: el) + | ({eexpr = TIf(e1,e2,Some e3)} as e_if) :: el -> + let e1 = loop e1 in + let e2 = loop e2 in + let e3 = loop e3 in + begin match get_assignment_to v e2,get_assignment_to v e3 with + | Some e2,Some e3 -> + let e_if = if_or_op e_if (loop e1) (loop e2) (loop e3) in + let e = {e with eexpr = TVar(v,Some e_if)} in + loop2 (e :: el) + | _ -> + let e_if = {e_if with eexpr = TIf(e1,e2,Some e3)} in + e :: e_if :: loop2 el + end + | _ -> + let e = loop e in + e :: loop2 el + end + | TReturn (Some e1) when (match follow e1.etype with TAbstract({a_path=[],"Void"},_) -> true | _ -> false) -> + [(loop e1);{e with eexpr = TReturn None}] + | _ -> + let e = loop e in + e :: loop2 el + end + | [] -> + [] + in + let el = loop2 el in + {e with eexpr = TBlock el} + | TLocal v when Meta.has Meta.CompilerGenerated v.v_meta -> + begin try IntMap.find v.v_id !var_map + with Not_found -> e end + | TWhile(e1,e2,flag) -> + let e1 = loop e1 in + let e2 = loop e2 in + let extract_cond e = match e.eexpr with + | TIf({eexpr = TUnop(Not,_,e1)},_,_) -> e1 + | TBreak -> raise Exit (* can happen due to optimization, not so easy to deal with because there might be other breaks/continues *) + | _ -> assert false + in + let e1,e2,flag = try + begin match e2.eexpr with + | TBlock el -> + begin match el with + | {eexpr = TMeta((Meta.Custom ":whileCond",_,_),e1)} :: el -> + let e1 = extract_cond e1 in + e1,{e2 with eexpr = TBlock el},NormalWhile + | _ -> + e1,e2,flag + (* issue 3844 *) +(* begin match List.rev el with + | {eexpr = TMeta((Meta.Custom ":whileCond",_,_),e1)} :: el -> + let e1 = extract_cond e1 in + e1,{e2 with eexpr = TBlock (List.rev el)},DoWhile + | _ -> + e1,e2,flag + end *) + end + | _ -> + e1,e2,flag + end with Exit -> + e1,e2,flag + in + {e with eexpr = TWhile(e1,e2,flag)} + | TIf(e1,e2,Some e3) -> + let e1 = loop e1 in + let e2 = loop e2 in + let e3 = loop e3 in + if_or_op e e1 e2 e3 + | _ -> + Type.map_expr loop e + in + loop e +end + +module Ssa = struct + + type var_map = tvar IntMap.t + + type condition = + | Equal of tvar * texpr + | NotEqual of tvar * texpr + + type node_data = { + nd_pos: pos; + mutable nd_var_map : var_map; + mutable nd_terminates : bool; + } + + type join_node = { + mutable branches : node_data list; + } + + type ssa_context = { + com : Common.context; + mutable cleanup : (unit -> unit) list; + mutable cur_data : node_data; + mutable var_conds : (condition list) IntMap.t; + mutable loop_stack : (join_node * join_node) list; + mutable exception_stack : join_node list; + mutable block_depth : int; + } + + let s_cond = function + | Equal(v,e) -> Printf.sprintf "%s == %s" v.v_name (s_expr_pretty e) + | NotEqual(v,e) -> Printf.sprintf "%s != %s" v.v_name (s_expr_pretty e) + + let s_conds conds = + String.concat " && " (List.map s_cond conds) + + let mk_loc v p = mk (TLocal v) v.v_type p + + let mk_phi = + let v_phi = alloc_var "__ssa_phi__" t_dynamic in + (fun vl p -> + let e = mk (TCall(mk_loc v_phi p,(List.map (fun (v,p) -> mk_loc v p) vl))) t_dynamic p in + e + ) + + (* TODO: make sure this is conservative *) + let can_throw e = + let rec loop e = match e.eexpr with + | TConst _ | TLocal _ | TTypeExpr _ | TFunction _ | TBlock _ -> () + | TCall _ | TNew _ | TThrow _ | TCast(_,Some _) -> raise Exit + | _ -> Type.iter loop e + in + try + loop e; false + with Exit -> + true + + let mk_join_node() = { + branches = [] + } + + let mk_node_data p = { + nd_pos = p; + nd_var_map = IntMap.empty; + nd_terminates = false; + } + + let add_branch join branch p = + join.branches <- {branch with nd_pos = p} :: join.branches + + let branch ctx p = + let old_map = ctx.cur_data.nd_var_map in + let old_term = ctx.cur_data.nd_terminates in + ctx.cur_data.nd_terminates <- false; + (fun join -> + add_branch join ctx.cur_data p; + ctx.cur_data.nd_var_map <- old_map; + ctx.cur_data.nd_terminates <- old_term; + ) + + let terminate ctx = + ctx.cur_data.nd_terminates <- true + + let set_loop_join ctx join_top join_bottom = + ctx.loop_stack <- (join_top,join_bottom) :: ctx.loop_stack; + (fun () -> + ctx.loop_stack <- List.tl ctx.loop_stack + ) + + let set_exception_join ctx join = + ctx.exception_stack <- join :: ctx.exception_stack; + (fun () -> + ctx.exception_stack <- List.tl ctx.exception_stack; + ) + + let create_v_extra v = + match v.v_extra with + | Some (_,Some _) -> + () + | Some (tl,None) -> + let e_extra = mk (TObjectDecl []) t_dynamic null_pos in + v.v_extra <- Some (tl,Some e_extra) + | None -> + let e_extra = mk (TObjectDecl []) t_dynamic null_pos in + v.v_extra <- Some ([],Some e_extra) + + let set_v_extra_value v s e = match v.v_extra with + | Some (tl, Some {eexpr = TObjectDecl fl}) -> + let rec loop fl = match fl with + | (s',_) :: fl when s' = s -> + (s,e) :: fl + | f1 :: fl -> + f1 :: loop fl + | [] -> + [s,e] + in + let e_extra = mk (TObjectDecl (loop fl)) t_dynamic null_pos in + v.v_extra <- Some (tl, Some e_extra) + | _ -> + assert false + + let get_origin_var v = match v.v_extra with + | Some (_,Some {eexpr = TObjectDecl fl}) -> + begin match List.assoc "origin_var" fl with + | {eexpr = TLocal v'} -> v' + | _ -> raise Not_found + end + | _ -> + raise Not_found + + let set_origin_var v v_origin p = + let ev = mk_loc v_origin p in + set_v_extra_value v "origin_var" ev + + let get_var_value v = match v.v_extra with + | Some (_,Some {eexpr = TObjectDecl fl}) -> + List.assoc "var_value" fl + | _ -> + raise Not_found + + let set_var_value v e = + set_v_extra_value v "var_value" e + + let get_var_usage_count v = match v.v_extra with + | Some (_,Some {eexpr = TObjectDecl fl}) -> + begin try + begin match List.assoc "usage_count" fl with + | {eexpr = TConst (TInt i32)} -> Int32.to_int i32 + | _ -> 0 + end + with Not_found -> + 0 + end + | _ -> + raise Not_found + + let set_var_usage_count v i = + let e = mk (TConst (TInt (Int32.of_int i))) t_dynamic null_pos in + set_v_extra_value v "usage_count" e + + let declare_var ctx v p = + let old = v.v_extra in + ctx.cleanup <- (fun () -> + v.v_extra <- old + ) :: ctx.cleanup; + ctx.cur_data.nd_var_map <- IntMap.add v.v_id v ctx.cur_data.nd_var_map; + v.v_meta <- ((Meta.Custom ":blockDepth",[EConst (Int (string_of_int ctx.block_depth)),p],p)) :: v.v_meta; + v.v_extra <- None; + create_v_extra v; + set_origin_var v v p + + let assign_var ctx v e p = + if v.v_capture then + v + else begin + let i = match v.v_extra with + | Some (l,eo) -> + v.v_extra <- Some (("",t_dynamic) :: l,eo); + List.length l + 1 + | _ -> + error "Something went wrong" p + in + let v' = alloc_var (Printf.sprintf "%s<%i>" v.v_name i) v.v_type in + create_v_extra v'; + v'.v_meta <- [(Meta.Custom ":ssa"),[],p]; + set_origin_var v' v p; + ctx.cur_data.nd_var_map <- IntMap.add v.v_id v' ctx.cur_data.nd_var_map; + set_var_value v' e; + v' + end + + let get_var ctx v p = + try + IntMap.find v.v_id ctx.cur_data.nd_var_map + with Not_found -> + if not (has_meta Meta.Unbound v.v_meta) then + error (Printf.sprintf "Unbound variable %s" v.v_name) p; + v + + let close_join_node ctx node p = + let terminates = ref true in + let branches = List.filter (fun branch -> + if branch.nd_terminates then false + else begin + terminates := false; + true + end + ) node.branches in + match branches with + | [] -> + () + | branch :: branches -> + let vars = ref (IntMap.map (fun v -> [v,branch.nd_pos]) branch.nd_var_map) in + let rec handle_branch branch = + IntMap.iter (fun i v -> + try + let vl = IntMap.find i !vars in + if not (List.exists (fun (v',_) -> v == v') vl) then + vars := IntMap.add i ((v,p) :: vl) !vars + with Not_found -> + () + ) branch.nd_var_map; + in + List.iter handle_branch branches; + ctx.cur_data.nd_terminates <- !terminates; + IntMap.iter (fun i vl -> match vl with + | [v,p] -> + ctx.cur_data.nd_var_map <- IntMap.add i v ctx.cur_data.nd_var_map; + | (v',_) :: _ -> + let v = get_origin_var v' in + ignore(assign_var ctx v (mk_phi vl p) p) + | _ -> + assert false + ) !vars + + let invert_cond = function + | Equal(v,e) -> NotEqual(v,e) + | NotEqual(v,e) -> Equal(v,e) + + let invert_conds = + List.map invert_cond + + let rec eval_cond ctx e = match e.eexpr with + | TBinop(OpNotEq,{eexpr = TLocal v},e1) -> + [NotEqual(v,e1)] + | TBinop(OpEq,{eexpr = TLocal v},e1) -> + [Equal(v,e1)] + | TUnop(Not,_,e1) -> + invert_conds (eval_cond ctx e1) + | TLocal v -> + begin try eval_cond ctx (get_var_value v) + with Not_found -> [] end + | _ -> + [] + + let append_cond ctx v cond p = + begin try + let conds = IntMap.find v.v_id ctx.var_conds in + ctx.var_conds <- IntMap.add v.v_id (cond :: conds) ctx.var_conds + with Not_found -> + ctx.var_conds <- IntMap.add v.v_id [cond] ctx.var_conds + end + +(* let apply_cond ctx = function + | Equal({v_extra = Some(_,Some {eexpr = TLocal v})} as v0,e1) -> + let v' = assign_var ctx v (mk_loc v0 e1.epos) e1.epos in + append_cond ctx v' (Equal(v',e1)) e1.epos + | NotEqual({v_extra = Some(_,Some {eexpr = TLocal v})} as v0,e1) -> + let v' = assign_var ctx v (mk_loc v0 e1.epos) e1.epos in + append_cond ctx v' (NotEqual(v',e1)) e1.epos + | _ -> () + + let apply_not_null_cond ctx v p = + apply_cond ctx (NotEqual(v,(mk (TConst TNull) t_dynamic p))) *) + + let apply com e = + let rec handle_if ctx f econd eif eelse = + let econd = loop ctx econd in + (* let cond = eval_cond ctx econd in *) + let join = mk_join_node() in + let close = branch ctx eif.epos in + (* List.iter (apply_cond ctx) cond; *) + let eif = loop ctx eif in + close join; + let eelse = match eelse with + | None -> + (* let cond = invert_conds cond in *) + (* List.iter (apply_cond ctx) cond; *) + add_branch join ctx.cur_data e.epos; + None + | Some e -> + let close = branch ctx e.epos in + (* let cond = invert_conds cond in *) + (* List.iter (apply_cond ctx) cond; *) + let eelse = loop ctx e in + close join; + Some eelse + in + close_join_node ctx join e.epos; + f econd eif eelse + and handle_loop_body ctx e = + let join_top = mk_join_node() in + let join_bottom = mk_join_node() in + let unset = set_loop_join ctx join_top join_bottom in + let close = branch ctx e.epos in + ignore(loop ctx e); (* TODO: I don't know if this is sane. *) + close join_top; + add_branch join_top ctx.cur_data e.epos; + close_join_node ctx join_top e.epos; + let ebody = loop ctx e in + ctx.cur_data.nd_terminates <- false; + unset(); + close_join_node ctx join_bottom e.epos; + ebody + and loop ctx e = match e.eexpr with + (* var declarations *) + | TVar(v,eo) -> + declare_var ctx v e.epos; + let eo = match eo with + | None -> None + | Some e -> + let e = loop ctx e in + set_var_value v e; + Some e + in + {e with eexpr = TVar(v,eo)} + | TFunction tf -> + let close = branch ctx e.epos in + List.iter (fun (v,co) -> + declare_var ctx v e.epos; +(* match co with + | Some TNull when (match v.v_type with TType({t_path=["haxe"],"PosInfos"},_) -> false | _ -> true) -> () + | _ -> apply_not_null_cond ctx v e.epos *) + ) tf.tf_args; + let e' = loop ctx tf.tf_expr in + close (mk_join_node()); + {e with eexpr = TFunction {tf with tf_expr = e'}} + (* var modifications *) + | TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) when v.v_name <> "this" -> + let e2 = loop ctx e2 in + let _ = assign_var ctx v e2 e1.epos in + {e with eexpr = TBinop(OpAssign,e1,e2)} + | TBinop(OpAssignOp op,({eexpr = TLocal v} as e1),e2) -> + let e1 = loop ctx e1 in + let e2 = loop ctx e2 in + let e_op = mk (TBinop(op,e1,e2)) e.etype e.epos in + let _ = assign_var ctx v e_op e1.epos in + {e with eexpr = TBinop(OpAssignOp op,e1,e2)} + | TUnop((Increment | Decrement as op),flag,({eexpr = TLocal v} as e1)) -> + let op = match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false in + let e_one = mk (TConst (TInt (Int32.of_int 1))) com.basic.tint e.epos in + let e1 = loop ctx e1 in + let e_op = mk (TBinop(op,e1,e_one)) e.etype e.epos in + let _ = assign_var ctx v e_op e1.epos in + e + (* var user *) + | TLocal v -> + let v = get_var ctx v e.epos in + {e with eexpr = TLocal v} + (* control flow *) + | TIf(econd,eif,eelse) -> + let f econd eif eelse = {e with eexpr = TIf(econd,eif,eelse)} in + handle_if ctx f econd eif eelse + | TSwitch(e1,cases,edef) -> + let e1 = loop ctx e1 in + let join = mk_join_node() in + let cases = List.map (fun (el,e) -> + let close = branch ctx e.epos in + let el = List.map (loop ctx) el in + let e = loop ctx e in + close join; + el,e + ) cases in + let edef = match edef with + | Some e -> + let close = branch ctx e.epos in + let e = loop ctx e in + close join; + Some e + | None -> + begin match e1.eexpr with + | TMeta((Meta.Exhaustive,_,_),_) + | TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) -> + () + | _ -> + add_branch join ctx.cur_data e.epos; + end; + None + in + close_join_node ctx join e.epos; + let e = {e with eexpr = TSwitch(e1,cases,edef)} in + e + | TWhile(econd,ebody,mode) -> + let econd = loop ctx econd in + let ebody = handle_loop_body ctx ebody in + let e = {e with eexpr = TWhile(econd,ebody,mode)} in + e + | TFor(v,e1,ebody) -> + declare_var ctx v e.epos; + (* apply_not_null_cond ctx v e1.epos; *) + let v' = IntMap.find v.v_id ctx.cur_data.nd_var_map in + let e1 = loop ctx e1 in + let ebody = handle_loop_body ctx ebody in + let e = {e with eexpr = TFor(v',e1,ebody)} in + e + | TTry(e1,catches) -> + let join_ex = mk_join_node() in + let join_bottom = mk_join_node() in + let unset = set_exception_join ctx join_ex in + let e1 = loop ctx e1 in + unset(); + add_branch join_bottom ctx.cur_data e.epos; + close_join_node ctx join_ex e.epos; + let catches = List.map (fun (v,e) -> + declare_var ctx v e.epos; + (* apply_not_null_cond ctx v e.epos; *) + let close = branch ctx e.epos in + let e = loop ctx e in + close join_bottom; + v,e + ) catches in + close_join_node ctx join_bottom e.epos; + let e = {e with eexpr = TTry(e1,catches)} in + e + | TBreak -> + begin match ctx.loop_stack with + | [] -> error "Break outside loop" e.epos + | (_,join) :: _ -> add_branch join ctx.cur_data e.epos + end; + terminate ctx; + e + | TContinue -> + begin match ctx.loop_stack with + | [] -> error "Continue outside loop" e.epos + | (join,_) :: _ -> add_branch join ctx.cur_data e.epos + end; + terminate ctx; + e + | TThrow e1 -> + let e1 = loop ctx e1 in + begin match ctx.exception_stack with + | join :: _ -> add_branch join ctx.cur_data e.epos + | _ -> () + end; + terminate ctx; + {e with eexpr = TThrow e1} + | TReturn eo -> + let eo = match eo with None -> None | Some e -> Some (loop ctx e) in + terminate ctx; + {e with eexpr = TReturn eo} + | TBlock el -> + let rec loop2 el = match el with + | [] -> + [] + | e :: el -> + if ctx.cur_data.nd_terminates then begin + (* ctx.com.warning (Printf.sprintf "Unreachable code: %s" (s_expr_pretty e)) e.epos; *) + [] + end else + let e = loop ctx e in + e :: (loop2 el) + in + ctx.block_depth <- ctx.block_depth + 1; + let el = loop2 el in + ctx.block_depth <- ctx.block_depth - 1; + {e with eexpr = TBlock(el)} + | _ -> + begin match ctx.exception_stack with + | join :: _ when can_throw e -> add_branch join ctx.cur_data e.epos + | _ -> () + end; + Type.map_expr (loop ctx) e + in + let ctx = { + com = com; + cur_data = mk_node_data e.epos; + var_conds = IntMap.empty; + loop_stack = []; + exception_stack = []; + cleanup = []; + block_depth = 0; + } in + let e = loop ctx e in + e,ctx + + let unapply com e = + let rec loop e = match e.eexpr with + | TFor(v,e1,e2) when Meta.has (Meta.Custom ":ssa") v.v_meta -> + let v' = get_origin_var v in + let e1 = loop e1 in + let e2 = loop e2 in + {e with eexpr = TFor(v',e1,e2)} + | TLocal v when Meta.has (Meta.Custom ":ssa") v.v_meta -> + let v' = get_origin_var v in + {e with eexpr = TLocal v'} + | TBlock el -> + let rec filter e = match e.eexpr with + | TMeta((Meta.Custom ":ssa",_,_),_) -> + false + | _ -> + true + in + let el = List.filter filter el in + let el = List.map loop el in + {e with eexpr = TBlock el} + | _ -> + Type.map_expr loop e + in + loop e +end + +module ConstPropagation = struct + open Ssa + + let expr_eq e1 e2 = match e1.eexpr,e2.eexpr with + | TConst ct1, TConst ct2 -> + ct1 = ct2 + | _ -> + false + + let get_block_depth v = try + let i = match Meta.get (Meta.Custom ":blockDepth") v.v_meta with + | _,[EConst(Int s),_],_ -> int_of_string s + | _ -> raise Not_found + in + i + with Not_found -> + -1 + + let can_be_inlined com v0 e = type_iseq v0.v_type e.etype && match e.eexpr with + | TConst ct -> + begin match ct with + | TThis | TSuper -> false + (* Some targets don't like seeing null in certain places and won't even compile. We have to detect `if (x != null) + in order for this to work. *) + | TNull when (match com.platform with Php | Cpp -> true | _ -> false) -> false + | _ -> true + end + | TLocal v -> + not (Meta.has Meta.CompilerGenerated v.v_meta) && + begin try + let v' = Ssa.get_origin_var v in + begin match v'.v_extra with + | Some ([],_) -> get_block_depth v <= get_block_depth v0 + | _ -> false + end + with Not_found -> + false + end + | TEnumParameter _ when not (com.platform = Php) -> + Ssa.get_var_usage_count v0 <= 1 + | _ -> + false + + let semi_awkward_enum_value ssa e i = match e.eexpr with + | TCall({eexpr = TField(_,FEnum _)},el) -> (try List.nth el i with Failure _ -> raise Not_found) + | _ -> raise Not_found + + let rec local ssa force v e = + begin try + if v.v_capture then raise Not_found; + if type_has_analyzer_option v.v_type flag_no_const_propagation then raise Not_found; + begin match follow v.v_type with + | TDynamic _ -> raise Not_found + | _ -> () + end; + let e = Ssa.get_var_value v in + let old = v.v_extra in + v.v_extra <- None; + let e = value ssa force e in + v.v_extra <- old; + Ssa.set_var_value v e; + e + with Not_found -> + e + end + + (* force must only be true if the value is not used in the output *) + and value ssa force e = match e.eexpr with + | TUnop((Increment | Decrement),_,_) + | TBinop(OpAssignOp _,_,_) + | TBinop(OpAssign,_,_) -> + e + | TBinop(op,e1,e2) -> + let e1 = value ssa force e1 in + let e2 = value ssa force e2 in + let e = {e with eexpr = TBinop(op,e1,e2)} in + let e' = Optimizer.optimize_binop e op e1 e2 in + if e == e' then + e + else + value ssa force e' + | TUnop(op,flag,e1) -> + let e1 = value ssa force e1 in + let e = {e with eexpr = TUnop(op,flag,e1)} in + let e' = Optimizer.optimize_unop e op flag e1 in + if e == e' then + e + else + value ssa force e' + | TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}} as ephi),el) -> + let el = List.map (value ssa force) el in + begin match el with + | [] -> assert false + | e1 :: el -> + if List.for_all (fun e2 -> expr_eq e1 e2) el then + value ssa force e1 + else + {e with eexpr = TCall(ephi, e1 :: el)} + end + | TParenthesis e1 | TMeta(_,e1) -> + value ssa force e1 + | TLocal v -> + let e' = local ssa force v e in + if force || can_be_inlined ssa.com v e' then + e' + else + e + | TEnumParameter(e1,ef,i) -> + let ev = value ssa true e1 in + begin try + value ssa force (semi_awkward_enum_value ssa ev i) + with Not_found -> + e + end + | _ -> + e + + (* TODO: the name is quite accurate *) + let awkward_get_enum_index ssa e = + let e = awkward_get_enum_index ssa.com e in + let ev = (value ssa true e) in + match ev.eexpr with + | TField(_,FEnum(_,ef)) -> TInt (Int32.of_int ef.ef_index) + | TCall({eexpr = TField(_,FEnum(_,ef))},_) -> TInt (Int32.of_int ef.ef_index) + | _ -> raise Not_found + + let apply ssa e = + let rec loop e = match e.eexpr with + | TLocal v when not (Meta.has Meta.Unbound v.v_meta) -> + set_var_usage_count v (get_var_usage_count v + 1); + | _ -> + Type.iter loop e + in + loop e; + let had_function = ref false in + let rec loop e = match e.eexpr with + | TFunction _ when !had_function -> + e + | TFunction tf -> + had_function := true; + {e with eexpr = TFunction {tf with tf_expr = loop tf.tf_expr}} + | TLocal v -> + let e' = local ssa false v e in + if can_be_inlined ssa.com v e' then + e' + else + e + | TCall({eexpr = TField(_,(FStatic(_,cf) | FInstance(_,_,cf) | FAnon cf))},el) when has_analyzer_option cf.cf_meta flag_no_const_propagation -> + e + | TCall(e1,el) -> + let e1 = loop e1 in + let check e t = + if type_has_analyzer_option t flag_no_const_propagation then e + else loop e + in + let el = Codegen.UnificationCallback.check_call check el e1.etype in + {e with eexpr = TCall(e1,el)} +(* | TField(e1,fa) -> + let e1' = loop e1 in + let fa = if e1' != e1 then + begin try quick_field e1'.etype (field_name fa) + with Not_found -> fa end + else + fa + in + {e with eexpr = TField(e1',fa)} *) + | TUnop((Increment | Decrement),_,_) -> + e + | TBinop(OpAssignOp op,e1,e2) -> + let e2 = loop e2 in + {e with eexpr = TBinop(OpAssignOp op,e1,e2)} + | TBinop(OpAssign,({eexpr = TLocal _} as e1),e2) -> + let e2 = loop e2 in + {e with eexpr = TBinop(OpAssign,e1,e2)} + | TBinop(op,e1,e2) -> + let e1 = loop e1 in + let e2 = loop e2 in + let e = {e with eexpr = TBinop(op,e1,e2)} in + let e' = Optimizer.optimize_binop e op e1 e2 in + e' + | TUnop(op,flag,e1) -> + let e1 = loop e1 in + let e = {e with eexpr = TUnop(op,flag,e1)} in + let e' = Optimizer.optimize_unop e op flag e1 in + e' + | TIf(e1,e2,eo) -> + let e1 = loop e1 in + let e2 = loop e2 in + let rec check_const e1 = match e1.eexpr with + | TConst (TBool true) -> + e2 + | TConst (TBool false) -> + begin match eo with + | None -> + mk (TConst TNull) t_dynamic e.epos + | Some e -> + loop e + end + | TParenthesis e1 -> + check_const e1 + | _ -> + let eo = match eo with None -> None | Some e -> Some (loop e) in + {e with eexpr = TIf(e1,e2,eo)} + in + check_const e1 + | TSwitch(e1,cases,edef) -> + let e1 = loop e1 in + let rec check_constant e = match e.eexpr with + | TConst ct -> ct + | TParenthesis e1 | TCast(e1,None) | TMeta(_,e1) -> check_constant e1 + | _ -> awkward_get_enum_index ssa e + in + begin try + let ct = check_constant e1 in + begin try + let _,e = List.find (fun (el,_) -> + List.exists (fun e -> match e.eexpr with + | TConst ct2 -> ct = ct2 + | _ -> false + ) el + ) cases in + loop e + with Not_found -> + begin match edef with None -> raise Not_found | Some e -> loop e end + end + with Not_found -> + let cases = List.map (fun (el,e) -> el,loop e) cases in + let edef = match edef with None -> None | Some e -> Some (loop e) in + {e with eexpr = TSwitch(e1,cases,edef)} + end + | _ -> + Type.map_expr loop e + in + loop e +end + +module EffectChecker = struct + let run com is_var_expression e = + let has_effect e = match e.eexpr with + | TVar _ -> true + | _ -> Optimizer.has_side_effect e + in + let e = if is_var_expression then + (* var initialization expressions are like assignments, so let's cheat a bit here *) + snd (Simplifier.apply com (Codegen.binop OpAssign (mk (TConst TNull) t_dynamic e.epos) e e.etype e.epos)) + else e + in + let rec loop e = match e.eexpr with + | TBlock el -> + List.iter (fun e -> + if not (has_effect e) then com.warning "This expression has no effect" e.epos + ) el + | _ -> + Type.iter loop e + in + loop e +end + +module Checker = struct + open Ssa + + let apply ssa e = + let given_warnings = ref PMap.empty in + let add_pos p = + given_warnings := PMap.add p true !given_warnings + in + let resolve_value v = + let e' = Ssa.get_var_value v in + begin match e'.eexpr with + | TLocal v' when v == v' -> e' + | _ -> e' + end + in + let rec is_null_expr e = match e.eexpr with + | TConst TNull -> + true + | TLocal v -> + (try is_null_expr (resolve_value v) with Not_found -> false) + | _ -> + false + in + let can_be_null v = + not (has_meta Meta.NotNull v.v_meta) + && try not (List.exists (fun cond -> match cond with + | NotEqual(v',e) when v == v' && is_null_expr e -> true + | _ -> false + ) (IntMap.find v.v_id ssa.var_conds)) with Not_found -> true + in + let return b p = + if b then add_pos p; + b + in + let rec can_be_null_expr vstack e = + if PMap.mem e.epos !given_warnings then + false + else match e.eexpr with + | TConst TNull -> + add_pos e.epos; + true + | TBinop((OpAssign | OpAssignOp _),_,e1) -> + can_be_null_expr vstack e1 + | TBinop _ | TUnop _ -> + false + | TConst _ | TTypeExpr _ | TNew _ | TObjectDecl _ | TArrayDecl _ | TEnumParameter _ | TFunction _ | TVar _ -> + false + | TFor _ | TWhile _ | TIf _ | TSwitch _ | TTry _ | TReturn _ | TBreak | TContinue | TThrow _ -> + assert false + | TField _ | TBlock _ | TArray _ -> + false (* TODO *) + | TCall ({eexpr = TLocal {v_name = "__ssa_phi__"}},el) -> + List.exists (can_be_null_expr vstack) el + | TLocal v -> + if List.mem v.v_id vstack then + false (* not really, but let's not be a nuisance *) + else + return (can_be_null v && (try can_be_null_expr (v.v_id :: vstack) (resolve_value v) with Not_found -> true)) e.epos; + | TMeta(_,e1) | TParenthesis e1 | TCast(e1,_) -> + can_be_null_expr vstack e1 + | TCall(e1,_) -> + begin match follow e1.etype with + | TFun(_,r) -> return (is_explicit_null r) e1.epos + | _ -> false + end + in + let check_null e p = + if can_be_null_expr [] e then begin + ssa.com.warning "Possible null exception" p; + end + in + let rec loop e = match e.eexpr with + | TField(e1,fa) -> + let e1 = loop e1 in + check_null e1 e.epos; + {e with eexpr = TField(e1,fa)} + | TMeta((Meta.Analyzer,[EConst(Ident "testIsNull"),_],_),e1) -> + if not (can_be_null_expr [] e) then error "Analyzer did not find a possible null exception" e.epos; + e + | TMeta((Meta.Analyzer,[EConst(Ident "testIsNotNull"),_],_),e1) -> + if (can_be_null_expr [] e) then error "Analyzer found a possible null exception" e.epos; + e + | _ -> + Type.map_expr loop e + in + loop e; +end + +let rec lrev_iter f el = match el with + | e :: el -> + lrev_iter f el; + f e + | [] -> + () + +let rev_iter f e = match e.eexpr with + | TConst _ + | TLocal _ + | TBreak + | TContinue + | TTypeExpr _ -> + () + | TArray (e1,e2) + | TBinop (_,e1,e2) + | TFor (_,e1,e2) + | TWhile (e1,e2,_) -> + f e2; + f e1; + | TThrow e + | TField (e,_) + | TEnumParameter (e,_,_) + | TParenthesis e + | TCast (e,_) + | TUnop (_,_,e) + | TMeta(_,e) -> + f e + | TArrayDecl el + | TNew (_,_,el) + | TBlock el -> + lrev_iter f el + | TObjectDecl fl -> + lrev_iter (fun (_,e) -> f e) fl + | TCall (e,el) -> + f e; + lrev_iter f el + | TVar (v,eo) -> + (match eo with None -> () | Some e -> f e) + | TFunction fu -> + f fu.tf_expr + | TIf (e,e1,e2) -> + (match e2 with None -> () | Some e -> f e); + f e1; + f e; + | TSwitch (e,cases,def) -> + (match def with None -> () | Some e -> f e); + lrev_iter (fun (el,e2) -> lrev_iter f el; f e2) cases; + f e; + | TTry (e,catches) -> + lrev_iter (fun (_,e) -> f e) catches; + f e; + | TReturn eo -> + (match eo with None -> () | Some e -> f e) + +module LocalDce = struct + let apply e = + let is_used v = Meta.has Meta.Used v.v_meta || type_has_analyzer_option v.v_type flag_no_local_dce || v.v_capture in + let is_ref_type t = match t with + | TType({t_path = ["cs"],("Ref" | "Out")},_) -> true + | _ -> false + in + let rec use v = + if not (Meta.has Meta.Used v.v_meta) then begin + v.v_meta <- (Meta.Used,[],Ast.null_pos) :: v.v_meta; + try use (Ssa.get_origin_var v) with Not_found -> () + end + in + let rec has_side_effect e = + let rec loop e = + match e.eexpr with + | TLocal v when Meta.has Meta.CompilerGenerated v.v_meta -> (try loop (Ssa.get_var_value v) with Not_found -> ()) + | TBinop((OpAssign | OpAssignOp _),{eexpr = TLocal v},e2) when is_used v || has_side_effect e2 || is_ref_type v.v_type -> raise Exit + | TVar(v,None) when is_used v -> raise Exit + | TVar(v,Some e1) when is_used v || has_side_effect e1 -> raise Exit + | TConst _ | TLocal _ | TTypeExpr _ | TFunction _ -> () + | TCall ({ eexpr = TField(_,FStatic({ cl_path = ([],"Std") },{ cf_name = "string" })) },args) -> Type.iter loop e + | TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}}),el) -> () + | TCall ({eexpr = TField(_,FEnum _)},_) -> Type.iter loop e + | TNew _ | TCall _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit + | TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit + | TFor _ -> raise Exit + | TArray _ | TEnumParameter _ | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _ + | TField _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TBlock _ | TObjectDecl _ | TVar _ -> Type.iter loop e + in + try + loop e; + false + with Exit -> + true + in + let rec collect e = match e.eexpr with + | TLocal v -> + use v + | TVar(v,_) when not (is_used v) -> + (* TODO: this is probably dangerous *) + () + | _ -> + rev_iter collect e + in + let rec loop need_val e = + match e.eexpr with + | TLocal v -> + use v; + e + | TBinop(OpAssign,({eexpr = TLocal v} as e1),e2) -> + let e2 = loop false e2 in + if not (is_used v) && not (is_ref_type v.v_type) then + e2 + else + {e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v},e2)} + | TVar(v,Some e1) when not (is_used v) -> + let e1 = if has_side_effect e1 then loop true e1 else e1 in + e1 + | TWhile(e1,e2,flag) -> + collect e2; + let e2 = loop false e2 in + let e1 = loop false e1 in + {e with eexpr = TWhile(e1,e2,flag)} + | TFor(v,e1,e2) -> + collect e2; + let e2 = loop false e2 in + let e1 = loop false e1 in + {e with eexpr = TFor(v,e1,e2)} + | TBlock el -> + let rec block el = match el with + | e :: el -> + let el = block el in + if not need_val && not (has_side_effect e) then + el + else begin + let e = loop false e in + e :: el + end + | [] -> + [] + in + {e with eexpr = TBlock (block el)} + | TCall(e1, el) -> + let el = List.rev_map (loop true) (List.rev el) in + let e1 = loop false e1 in + {e with eexpr = TCall(e1,el)} + | TIf(e1,e2,e3) -> + let e3 = match e3 with None -> None | Some e -> Some (loop need_val e) in + let e2 = loop need_val e2 in + let e1 = loop false e1 in + {e with eexpr = TIf(e1,e2,e3)} + | TArrayDecl el -> + let el = List.rev_map (loop true) (List.rev el) in + {e with eexpr = TArrayDecl el} + | TObjectDecl fl -> + let fl = List.rev_map (fun (s,e) -> s,loop true e) (List.rev fl) in + {e with eexpr = TObjectDecl fl} + | _ -> + Type.map_expr (loop false) e + in + loop false e +end + +module Config = struct + + type analyzer_config = { + analyzer_use : bool; + simplifier_apply : bool; + ssa_apply : bool; + const_propagation : bool; + check : bool; + check_has_effect : bool; + local_dce : bool; + ssa_unapply : bool; + simplifier_unapply : bool; + } + + let get_base_config com = + { + analyzer_use = true; + simplifier_apply = true; + ssa_apply = true; + const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation"); + check_has_effect = (Common.raw_defined com "analyzer-check-has-effect"); + check = not (Common.raw_defined com "analyzer-no-check"); + local_dce = not (Common.raw_defined com "analyzer-no-local-dce") && not (Common.defined com Define.As3); + ssa_unapply = not (Common.raw_defined com "analyzer-no-ssa-unapply"); + simplifier_unapply = not (Common.raw_defined com "analyzer-no-simplify-unapply"); + } + + let update_config_from_meta config meta = + List.fold_left (fun config meta -> match meta with + | (Meta.Analyzer,el,_) -> + List.fold_left (fun config e -> match fst e with + | EConst (Ident s) when s = flag_no_check -> { config with check = false} + | EConst (Ident s) when s = flag_check -> { config with check = true} + | EConst (Ident s) when s = flag_no_const_propagation -> { config with const_propagation = false} + | EConst (Ident s) when s = flag_const_propagation -> { config with const_propagation = true} + | EConst (Ident s) when s = flag_no_local_dce -> { config with local_dce = false} + | EConst (Ident s) when s = flag_local_dce -> { config with local_dce = true} + | EConst (Ident s) when s = flag_no_check_has_effect -> { config with check_has_effect = false} + | EConst (Ident s) when s = flag_check_has_effect -> { config with check_has_effect = true} + | _ -> config + ) config el + | _ -> + config + ) config meta + + let get_class_config com c = + let config = get_base_config com in + update_config_from_meta config c.cl_meta + + let get_field_config com c cf = + let config = get_class_config com c in + update_config_from_meta config cf.cf_meta +end + +module Run = struct + + open Config + + let run_on_expr com config is_var_expression e = + let do_simplify = (not (Common.defined com Define.NoSimplify) ) && match com.platform with + | Cpp when Common.defined com Define.Cppia -> false + | Cpp | Python -> true + | _ -> false + in + let with_timer s f = + let timer = timer s in + let r = f() in + timer(); + r + in + try + let has_unbound,e = if do_simplify || config.analyzer_use then + with_timer "analyzer-simplify-apply" (fun () -> Simplifier.apply com e) + else + false,e + in + let e = if config.analyzer_use && not has_unbound then begin + if config.check_has_effect then EffectChecker.run com is_var_expression e; + let e,ssa = with_timer "analyzer-ssa-apply" (fun () -> Ssa.apply com e) in + let e = if config.const_propagation then with_timer "analyzer-const-propagation" (fun () -> ConstPropagation.apply ssa e) else e in + (* let e = if config.check then with_timer "analyzer-checker" (fun () -> Checker.apply ssa e) else e in *) + let e = if config.local_dce && config.analyzer_use && not has_unbound && not is_var_expression then with_timer "analyzer-local-dce" (fun () -> LocalDce.apply e) else e in + let e = if config.ssa_unapply then with_timer "analyzer-ssa-unapply" (fun () -> Ssa.unapply com e) else e in + List.iter (fun f -> f()) ssa.Ssa.cleanup; + e + end else + e + in + let e = if not do_simplify && not (Common.raw_defined com "analyzer-no-simplify-unapply") then + with_timer "analyzer-simplify-unapply" (fun () -> Simplifier.unapply com e) + else + e + in + e + with Exit -> + e + + let run_on_field ctx config cf = + match cf.cf_expr with + | Some e when not (is_ignored cf.cf_meta) && not (Codegen.is_removable_field ctx cf) -> + let config = update_config_from_meta config cf.cf_meta in + let is_var_expression = match cf.cf_kind with + | Var _ -> true + | _ -> false + in + cf.cf_expr <- Some (run_on_expr ctx.com config is_var_expression e); + | _ -> () + + let run_on_class ctx config c = + let config = update_config_from_meta config c.cl_meta in + let process_field cf = run_on_field ctx config cf in + List.iter process_field c.cl_ordered_fields; + List.iter process_field c.cl_ordered_statics; + (match c.cl_constructor with + | None -> () + | Some f -> process_field f); + (match c.cl_init with + | None -> () + | Some e -> + (* never optimize init expressions (too messy) *) + c.cl_init <- Some (run_on_expr ctx.com {config with analyzer_use = false} false e)) + + let run_on_type ctx config t = + match t with + | TClassDecl c when (is_ignored c.cl_meta) -> () + | TClassDecl c -> run_on_class ctx config c + | TEnumDecl _ -> () + | TTypeDecl _ -> () + | TAbstractDecl _ -> () + + let run_on_types ctx types = + let com = ctx.com in + let config = get_base_config com in + List.iter (run_on_type ctx config) types + +end diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..53b1b519339476dde708c395fc79bbd9dd2ffa48 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,68 @@ +version: "{build}" + +os: unstable #http://help.appveyor.com/discussions/suggestions/427-pre-install-cygwin + +platform: + - Win32 + +environment: + global: + NEKO_ROOT: C:/projects/neko + HAXELIB_ROOT: C:/projects/haxelib + CYG_ARCH: x86 + CYG_ROOT: C:/cygwin + CYG_SETUP: C:/cygwin/setup-x86.exe + MINGW_ARCH: i686 + WODI: wodi32 + ADD_REVISION: 1 + OCAMLOPT: ocamlopt.opt + matrix: + - TEST: "neko,cs,java,macro" + - TEST: "cpp" + +skip_tags: true + +install: + - 'git submodule update --init --recursive' + - cinst 7zip.commandline -y + # Install ocaml using wodi + - appveyor DownloadFile "http://cygwin.com/setup-%CYG_ARCH%.exe" -FileName "%CYG_ROOT%\setup.exe" + - '%CYG_ROOT%/setup.exe -g -q -R "%CYG_ROOT%" -P dos2unix -P diffutils -P cpio -P make -P patch -P mingw64-%MINGW_ARCH%-gcc-core -P mingw64-%MINGW_ARCH%-gcc-g++ > log.txt || type log.txt' + - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin" > log.txt || type log.txt' + # The archive is a dropbox hosted version of https://github.com/fdopen/godi-repo/issues/7#issuecomment-98480339 + - '%CYG_ROOT%/bin/bash -lc "wget -q https://dl.dropboxusercontent.com/u/2661116/wodi/%WODI%.tar.xz -O /tmp/%WODI%.tar.xz" > log.txt || type log.txt' + - '%CYG_ROOT%/bin/bash -lc "cd /tmp && rm -rf %WODI% && tar -xf %WODI%.tar.xz && bash %WODI%/install.sh" > log.txt || type log.txt' + - '%CYG_ROOT%/bin/bash -lc "godi_add godi-zip" > log.txt || type log.txt' + - 'set PATH=%PATH%;%CYG_ROOT%/opt/%WODI%/bin' + # Install neko + - cinst make -y + - 'git clone --recursive https://github.com/HaxeFoundation/neko.git %NEKO_ROOT%' + - 'cd %NEKO_ROOT%' + - set PATH=%PATH%;%NEKO_ROOT%/bin + - msbuild neko_vc10.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" > log.txt || type log.txt + - msbuild libs/libs_vc10.sln /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" > log.txt || type log.txt + - copy /y libs\include\gc\gc.dll bin + - cd %NEKO_ROOT%/src + - neko ../boot/nekoc tools/install.neko + - neko tools/install -nolibs > log.txt || type log.txt + - neko -version + +build_script: + - 'cd %APPVEYOR_BUILD_FOLDER%' + - 'set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%' + - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win"' + - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win tools"' + - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && make -s -f Makefile.win package_bin"' + - dir %APPVEYOR_BUILD_FOLDER%\out + - cd %APPVEYOR_BUILD_FOLDER%/tests/ + - mkdir "%HAXELIB_ROOT%" + - haxelib setup "%HAXELIB_ROOT%" + +test_script: + - cd %APPVEYOR_BUILD_FOLDER%/tests/ + - haxe -version + - haxe RunCi.hxml + - neko RunCi.n + +artifacts: + - path: out/haxe_*.zip diff --git a/ast.ml b/ast.ml old mode 100755 new mode 100644 index 1017568718bfe02287e91872def138c63b08faec..bcd6b95ec7e710629ccc9fe8582443e4b0bec4ac --- a/ast.ml +++ b/ast.ml @@ -26,18 +26,26 @@ type pos = { pmax : int; } +module IntMap = Map.Make(struct type t = int let compare a b = a - b end) + module Meta = struct type strict_meta = + | Abi | Abstract | Access + | Accessor | Allow + | Analyzer | Annotation | ArrayAccess + | Ast | AutoBuild | Bind | Bitmap + | BridgeProperties | Build | BuildXml + | Callable | Class | ClassCode | Commutative @@ -45,54 +53,78 @@ module Meta = struct | CoreApi | CoreType | CppFileCode + | CppInclude | CppNamespaceCode + | CsNative + | Dce | Debug | Decl | DefParam + | Delegate | Depend | Deprecated + | DirectlyUsed | DynamicObject | Enum | EnumConstructorParam + | Event + | Exhaustive | Expose | Extern | FakeEnum | File | Final + | FlatEnum | Font + | Forward | From | FunctionCode | FunctionTailCode | Generic + | GenericBuild + | GenericInstance | Getter | Hack + | HasUntyped | HaxeGeneric | HeaderClassCode | HeaderCode + | HeaderInclude | HeaderNamespaceCode | HxGen | IfFeature | Impl + | PythonImport + | ImplicitCast | Include | InitPackage | Internal | IsVar + | JavaCanonical | JavaNative + | JsRequire | Keep | KeepInit | KeepSub + | LibType | Meta | Macro | MaybeUsed + | MergeBlock | MultiType | Native + | NativeChildren | NativeGen | NativeGeneric + | NativeProperty | NoCompletion | NoDebug | NoDoc + | NoExpr | NoImportGlobal + | NonVirtual | NoPackageRestrict + | NoPrivateAccess | NoStack | NotNull | NoUsing @@ -101,34 +133,47 @@ module Meta = struct | Optional | Overload | PrivateAccess + | Property | Protected | Public | PublicFields + | QuotedField | ReadOnly | RealPath | Remove | Require + | RequiresAssign + (* | Resolve *) | ReplaceReflection | Rtti | Runtime | RuntimeValue + | SelfCall | Setter | SkipCtor | SkipReflection | Sound + | SourceFile + | StoredTypedExpr + | Strict | Struct + | StructAccess | SuppressWarnings + | This | Throws | To | ToString | Transient | ValueUsed | Volatile + | Unbound | UnifyMinDynamic | Unreflective | Unsafe | Usage | Used + | Value + | Void | Last (* do not put any custom metadata after Last *) | Dollar of string @@ -136,6 +181,9 @@ module Meta = struct let has m ml = List.exists (fun (m2,_,_) -> m = m2) ml let get m ml = List.find (fun (m2,_,_) -> m = m2) ml + + let to_string_ref = ref (fun _ -> assert false) + let to_string (m : strict_meta) : string = !to_string_ref m end type keyword = @@ -270,7 +318,7 @@ and complex_type = | CTFunction of complex_type list * complex_type | CTAnonymous of class_field list | CTParent of complex_type - | CTExtend of type_path * class_field list + | CTExtend of type_path list * class_field list | CTOptional of complex_type and func = { @@ -401,6 +449,8 @@ type type_decl = type_def * pos type package = string list * type_decl list +exception Error of string * pos + let is_lower_ident i = let rec loop p = match String.unsafe_get i p with @@ -412,8 +462,8 @@ let is_lower_ident i = let pos = snd -let is_postfix (e,_) = function - | Increment | Decrement -> (match e with EConst _ | EField _ | EArray _ -> true | _ -> false) +let rec is_postfix (e,_) op = match op with + | Increment | Decrement -> true | Not | Neg | NegBits -> false let is_prefix = function @@ -446,7 +496,7 @@ let parse_path s = | [] -> failwith "Invalid empty path" | x :: l -> List.rev l, x -let s_escape s = +let s_escape ?(hex=true) s = let b = Buffer.create (String.length s) in for i = 0 to (String.length s) - 1 do match s.[i] with @@ -455,6 +505,7 @@ let s_escape s = | '\r' -> Buffer.add_string b "\\r" | '"' -> Buffer.add_string b "\\\"" | '\\' -> Buffer.add_string b "\\\\" + | c when int_of_char c < 32 && hex -> Buffer.add_string b (Printf.sprintf "\\x%.2X" (int_of_char c)) | c -> Buffer.add_char b c done; Buffer.contents b @@ -598,6 +649,23 @@ let unescape s = let c = (try char_of_int (int_of_string ("0x" ^ String.sub s (i+1) 2)) with _ -> raise Exit) in Buffer.add_char b c; inext := !inext + 2; + | 'u' -> + let (u, a) = + try + (int_of_string ("0x" ^ String.sub s (i+1) 4), 4) + with _ -> try + assert (s.[i+1] = '{'); + let l = String.index_from s (i+3) '}' - (i+2) in + let u = int_of_string ("0x" ^ String.sub s (i+2) l) in + assert (u <= 0x10FFFF); + (u, l+2) + with _ -> + raise Exit + in + let ub = UTF8.Buf.create 0 in + UTF8.Buf.add_char ub (UChar.uchar_of_int u); + Buffer.add_string b (UTF8.Buf.contents ub); + inext := !inext + a; | _ -> raise Exit); loop false !inext; @@ -630,7 +698,7 @@ let map_expr loop (e,p) = | CTFunction (cl,c) -> CTFunction (List.map ctype cl, ctype c) | CTAnonymous fl -> CTAnonymous (List.map cfield fl) | CTParent t -> CTParent (ctype t) - | CTExtend (t,fl) -> CTExtend (tpath t, List.map cfield fl) + | CTExtend (tl,fl) -> CTExtend (List.map tpath tl, List.map cfield fl) | CTOptional t -> CTOptional (ctype t) and tparamdecl t = { tp_name = t.tp_name; tp_constraints = List.map ctype t.tp_constraints; tp_params = List.map tparamdecl t.tp_params } @@ -676,3 +744,29 @@ let map_expr loop (e,p) = | EMeta (m,e) -> EMeta(m, loop e) ) in (e,p) + +let rec s_expr (e,_) = + match e with + | EConst c -> s_constant c + | EParenthesis e -> "(" ^ (s_expr e) ^ ")" + | EArrayDecl el -> "[" ^ (String.concat "," (List.map s_expr el)) ^ "]" + | EObjectDecl fl -> "{" ^ (String.concat "," (List.map (fun (n,e) -> n ^ ":" ^ (s_expr e)) fl)) ^ "}" + | EBinop (op,e1,e2) -> s_expr e1 ^ s_binop op ^ s_expr e2 + | ECall (e,el) -> s_expr e ^ "(" ^ (String.concat ", " (List.map s_expr el)) ^ ")" + | EField (e,f) -> s_expr e ^ "." ^ f + | _ -> "'???'" + +let get_value_meta meta = + try + begin match Meta.get Meta.Value meta with + | (_,[EObjectDecl values,_],_) -> List.fold_left (fun acc (s,e) -> PMap.add s e acc) PMap.empty values + | _ -> raise Not_found + end + with Not_found -> + PMap.empty + +let rec string_list_of_expr_path_raise (e,p) = + match e with + | EConst (Ident i) -> [i] + | EField (e,f) -> f :: string_list_of_expr_path_raise e + | _ -> raise Exit diff --git a/codegen.ml b/codegen.ml index 078b8c545e20c26ec86154e09643682651b4351d..7b51b2afcab6f65b7179652a824599e587f5ed8e 100644 --- a/codegen.ml +++ b/codegen.ml @@ -47,14 +47,12 @@ let binop op a b t p = let index com e index t p = mk (TArray (e,mk (TConst (TInt (Int32.of_int index))) com.basic.tint p)) t p -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 maybe_cast e t = + try + type_eq EqDoNotFollowNull e.etype t; + e + with + Unify_error _ -> mk (TCast(e,None)) t e.epos let type_constant com c p = let t = com.basic in @@ -89,17 +87,21 @@ let rec has_properties c = match f.cf_kind with | Var { v_read = AccCall } -> true | Var { v_write = AccCall } -> true + | _ when Meta.has Meta.Accessor f.cf_meta -> true | _ -> false ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false) let get_properties fields = List.fold_left (fun acc f -> - let acc = (match f.cf_kind with - | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc - | _ -> acc) in - match f.cf_kind with - | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc - | _ -> acc + if Meta.has Meta.Accessor f.cf_meta then + (f.cf_name, f.cf_name) :: acc + else + let acc = (match f.cf_kind with + | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc + | _ -> acc) in + match f.cf_kind with + | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc + | _ -> acc ) [] fields let add_property_field com c = @@ -119,6 +121,22 @@ let add_property_field com c = c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics; c.cl_ordered_statics <- cf :: c.cl_ordered_statics +let is_removable_field ctx f = + Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta + || (match f.cf_kind with + | Var {v_read = AccRequire (s,_)} -> true + | Method MethMacro -> not ctx.in_macro + | _ -> false) + +let escape_res_name name allow_dirs = + ExtString.String.replace_chars (fun chr -> + if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then + Char.escaped chr + else if chr = '/' && allow_dirs then + "/" + else + "-x" ^ (string_of_int (Char.code chr))) name + (* -------------------------------------------------------------------------- *) (* REMOTING PROXYS *) @@ -196,7 +214,7 @@ let extend_remoting ctx c t p async prot = error ("Module " ^ s_type_path path ^ " does not define type " ^ t.tname) p ) in match t with - | TClassDecl c2 when c2.cl_types = [] -> c2.cl_build(); c.cl_super <- Some (c2,[]); + | TClassDecl c2 when c2.cl_params = [] -> ignore(c2.cl_build()); c.cl_super <- Some (c2,[]); | _ -> error "Remoting proxy must be a class without parameters" p (* -------------------------------------------------------------------------- *) @@ -222,16 +240,19 @@ let make_generic ctx ps pt p = in let name = String.concat "_" (List.map2 (fun (s,_) t -> - let path = (match follow t with - | TInst (ct,_) -> ct.cl_path - | TEnum (e,_) -> e.e_path - | TAbstract (a,_) when Meta.has Meta.RuntimeValue a.a_meta -> a.a_path + 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 + | TInst(c,tl) -> (s_type_path_underscore c.cl_path) ^ (loop_tl tl) + | TEnum(en,tl) -> (s_type_path_underscore en.e_path) ^ (loop_tl tl) + | 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)) | t -> raise (Generic_Exception (("Type parameter must be a class or enum instance (found " ^ (s_type (print_context()) t) ^ ")"), p)) - ) in - match path with - | [] , name -> name - | l , name -> String.concat "_" l ^ "_" ^ name + and loop_tl tl = match tl with + | [] -> "" + | tl -> "_" ^ String.concat "_" (List.map (loop false) tl) + in + loop true t ) ps pt) in { @@ -251,7 +272,10 @@ let rec generic_substitute_type gctx t = (match follow t,gctx.mg with TInst(c,_), Some m -> add_dependency m c.cl_module | _ -> ()); t | _ -> - try List.assq t gctx.subst with Not_found -> Type.map (generic_substitute_type gctx) t + try + generic_substitute_type gctx (List.assq t gctx.subst) + with Not_found -> + Type.map (generic_substitute_type gctx) t let generic_substitute_expr gctx e = let vars = Hashtbl.create 0 in @@ -260,28 +284,21 @@ let generic_substitute_expr gctx e = Hashtbl.find vars v.v_id with Not_found -> let v2 = alloc_var v.v_name (generic_substitute_type gctx v.v_type) in + v2.v_meta <- v.v_meta; Hashtbl.add vars v.v_id v2; v2 in let rec build_expr e = match e.eexpr with - | TField(e1, FInstance({cl_kind = KGeneric},cf)) -> - build_expr {e with eexpr = TField(e1,quick_field_dynamic (generic_substitute_type gctx (e1.etype)) cf.cf_name)} - | _ -> map_expr_type build_expr (generic_substitute_type gctx) build_var e + | TField(e1, FInstance({cl_kind = KGeneric} as c,tl,cf)) -> + let _, _, f = gctx.ctx.g.do_build_instance gctx.ctx (TClassDecl c) gctx.p in + let t = f (List.map (generic_substitute_type gctx) tl) in + build_expr {e with eexpr = TField(e1,quick_field t cf.cf_name)} + | _ -> + map_expr_type build_expr (generic_substitute_type gctx) build_var e in build_expr e -let is_generic_parameter ctx c = - (* first check field parameters, then class parameters *) - try - ignore (List.assoc (snd c.cl_path) ctx.curfield.cf_params); - Meta.has Meta.Generic ctx.curfield.cf_meta - with Not_found -> try - ignore(List.assoc (snd c.cl_path) ctx.type_params); - (match ctx.curclass.cl_kind with | KGeneric -> true | _ -> false); - with Not_found -> - false - let has_ctor_constraint c = match c.cl_kind with | KTypeParameter tl -> List.exists (fun t -> match follow t with @@ -290,6 +307,13 @@ let has_ctor_constraint c = match c.cl_kind with ) tl; | _ -> false +let get_short_name = + let i = ref (-1) in + (fun () -> + incr i; + Printf.sprintf "Hx___short___hx_type_%i" !i + ) + let rec build_generic ctx c p tl = let pack = fst c.cl_path in let recurse = ref false in @@ -298,7 +322,7 @@ let rec build_generic ctx c p tl = | TInst (c2,tl) -> (match c2.cl_kind with | KTypeParameter tl -> - if not (is_generic_parameter ctx c2) && has_ctor_constraint c2 then + if not (Typeload.is_generic_parameter ctx c2) && has_ctor_constraint c2 then error "Type parameters with a constructor cannot be used non-generically" p; recurse := true | _ -> ()); @@ -307,16 +331,17 @@ let rec build_generic ctx c p tl = () in List.iter check_recursive tl; - let gctx = try make_generic ctx c.cl_types tl p with Generic_Exception (msg,p) -> error msg p in - let name = (snd c.cl_path) ^ "_" ^ gctx.name in if !recurse then begin TInst (c,tl) (* build a normal instance *) - end else try + end else begin + let gctx = make_generic ctx c.cl_params tl p in + let name = (snd c.cl_path) ^ "_" ^ gctx.name in + try Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false 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 ctx = { ctx with m = { ctx.m with module_types = m.m_types @ ctx.m.module_types } } in - c.cl_build(); (* make sure the super class is already setup *) + ignore(c.cl_build()); (* make sure the super class is already setup *) let mg = { m_id = alloc_mid(); m_path = (pack,name); @@ -358,34 +383,86 @@ let rec build_generic ctx c p tl = List.iter loop tl in List.iter loop tl; - let delays = ref [] in - let build_field f = - let t = generic_substitute_type gctx f.cf_type in - let f = { f with cf_type = t} in - (* delay the expression mapping to make sure all cf_type fields are set correctly first *) - (delays := (fun () -> - try (match f.cf_expr with None -> () | Some e -> f.cf_expr <- Some (generic_substitute_expr gctx e)) - with Unify_error l -> error (error_msg (Unify l)) f.cf_pos) :: !delays); - f + let build_field cf_old = + let cf_new = {cf_old with cf_pos = cf_old.cf_pos} in (* copy *) + let f () = + let t = generic_substitute_type gctx cf_old.cf_type in + ignore (follow t); + begin try (match cf_old.cf_expr with + | None -> + begin match cf_old.cf_kind with + | Method _ when not c.cl_interface && not c.cl_extern -> + display_error ctx (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos; + display_error ctx (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p; + | _ -> + () + end + | Some e -> + cf_new.cf_expr <- Some (generic_substitute_expr gctx e) + ) with Unify_error l -> + error (error_msg (Unify l)) cf_new.cf_pos + end; + t + in + let r = exc_protect ctx (fun r -> + let t = mk_mono() in + r := (fun() -> t); + unify_raise ctx (f()) t p; + t + ) "build_generic" in + delay ctx PForce (fun() -> ignore ((!r)())); + cf_new.cf_type <- TLazy r; + cf_new in if c.cl_init <> None || c.cl_dynamic <> None then error "This class can't be generic" p; - if c.cl_ordered_statics <> [] then error "A generic class can't have static fields" p; + List.iter (fun cf -> match cf.cf_kind with + | Method MethMacro when not ctx.in_macro -> () + | _ -> error "A generic class can't have static fields" cf.cf_pos + ) c.cl_ordered_statics; cg.cl_super <- (match c.cl_super with | None -> None | Some (cs,pl) -> - (match apply_params c.cl_types tl (TInst (cs,pl)) with - | TInst (cs,pl) when cs.cl_kind = KGeneric -> + let find_class subst = + let rec loop subst = match subst with + | (TInst(c,[]),t) :: subst when c == cs -> t + | _ :: subst -> loop subst + | [] -> raise Not_found + in + try + if pl <> [] then raise Not_found; + let t = loop subst in + (* extended type parameter: concrete type must have a constructor, but generic base class must not have one *) + begin match follow t,c.cl_constructor with + | TInst(cs,_),None -> + ignore(cs.cl_build()); + begin match cs.cl_constructor with + | None -> error ("Cannot use " ^ (s_type_path cs.cl_path) ^ " as type parameter because it is extended and has no constructor") p + | _ -> () + end; + | _,Some cf -> error "Generics extending type parameters cannot have constructors" cf.cf_pos + | _ -> () + end; + t + with Not_found -> + apply_params c.cl_params tl (TInst(cs,pl)) + in + let ts = follow (find_class gctx.subst) in + let cs,pl = Typeload.check_extends ctx c ts p in + match cs.cl_kind with + | KGeneric -> (match build_generic ctx cs p pl with | TInst (cs,pl) -> Some (cs,pl) | _ -> assert false) - | TInst (cs,pl) -> Some (cs,pl) - | _ -> assert false) + | _ -> Some(cs,pl) ); + Typeload.add_constructor ctx cg false p; cg.cl_kind <- KGenericInstance (c,tl); + cg.cl_meta <- (Meta.NoDoc,[],p) :: cg.cl_meta; cg.cl_interface <- c.cl_interface; - cg.cl_constructor <- (match c.cl_constructor, c.cl_super with - | None, None -> None - | Some c, _ -> Some (build_field c) + cg.cl_constructor <- (match cg.cl_constructor, c.cl_constructor, c.cl_super with + | _, Some cf, _ -> Some (build_field cf) + | Some ctor, _, _ -> Some ctor + | None, None, None -> None | _ -> error "Please define a constructor for this class in order to use it as generic" c.cl_pos ); cg.cl_implements <- List.map (fun (i,tl) -> @@ -398,8 +475,13 @@ let rec build_generic ctx c p tl = cg.cl_fields <- PMap.add f.cf_name f cg.cl_fields; f ) c.cl_ordered_fields; - List.iter (fun f -> f()) !delays; + (* 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 + let n = get_short_name () in + cg.cl_meta <- (Meta.Native,[EConst(String (n)),p],p) :: cg.cl_meta; + end; TInst (cg,[]) + end (* -------------------------------------------------------------------------- *) (* HAXE.XML.PROXY *) @@ -478,7 +560,7 @@ let build_metadata com t = if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p; Hashtbl.add h f (); f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p - ) ml)) (api.tarray t_dynamic) p + ) ml)) t_dynamic p in let make_meta l = mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p @@ -495,21 +577,38 @@ let build_metadata com t = (* -------------------------------------------------------------------------- *) (* MACRO TYPE *) +let get_macro_path ctx e args p = + let rec loop e = + match fst e with + | EField (e,f) -> f :: loop e + | EConst (Ident i) -> [i] + | _ -> error "Invalid macro call" p + in + let path = match e with + | (EConst(Ident i)),_ -> + let path = try + if not (PMap.mem i ctx.curclass.cl_statics) then raise Not_found; + ctx.curclass.cl_path + with Not_found -> try + (t_infos (fst (PMap.find i ctx.m.module_globals))).mt_path + with Not_found -> + error "Invalid macro call" p + in + i :: (snd path) :: (fst path) + | _ -> + loop e + in + (match path with + | meth :: cl :: path -> (List.rev path,cl), meth, args + | _ -> error "Invalid macro call" p) + let build_macro_type ctx pl p = let path, field, args = (match pl with | [TInst ({ cl_kind = KExpr (ECall (e,args),_) },_)] | [TInst ({ cl_kind = KExpr (EArrayDecl [ECall (e,args),_],_) },_)] -> - let rec loop e = - match fst e with - | EField (e,f) -> f :: loop e - | EConst (Ident i) -> [i] - | _ -> error "Invalid macro call" p - in - (match loop e with - | meth :: cl :: path -> (List.rev path,cl), meth, args - | _ -> error "Invalid macro call" p) + get_macro_path ctx e args p | _ -> - error "MacroType require a single expression call parameter" p + error "MacroType requires a single expression call parameter" p ) in let old = ctx.ret in let t = (match ctx.g.do_macro ctx MMacroType path field args p with @@ -519,43 +618,56 @@ let build_macro_type ctx pl p = ctx.ret <- old; t +let build_macro_build ctx c pl cfl p = + let path, field, args = match Meta.get Meta.GenericBuild c.cl_meta with + | _,[ECall(e,args),_],_ -> get_macro_path ctx e args p + | _ -> error "genericBuild requires a single expression call parameter" p + in + let old = ctx.ret,ctx.g.get_build_infos in + ctx.g.get_build_infos <- (fun() -> Some (TClassDecl c, pl, cfl)); + let t = (match ctx.g.do_macro ctx MMacroType path field args p with + | None -> mk_mono() + | Some _ -> ctx.ret + ) in + ctx.ret <- fst old; + ctx.g.get_build_infos <- snd old; + t + (* -------------------------------------------------------------------------- *) (* API EVENTS *) let build_instance ctx mtype p = match mtype with | TClassDecl c -> - if ctx.pass > PBuildClass then c.cl_build(); + if ctx.pass > PBuildClass then ignore(c.cl_build()); + let build f s = + let r = exc_protect ctx (fun r -> + let t = mk_mono() in + r := (fun() -> t); + unify_raise ctx (f()) t p; + t + ) s in + delay ctx PForce (fun() -> ignore ((!r)())); + TLazy r + in let ft = (fun pl -> match c.cl_kind with | KGeneric -> - let r = exc_protect ctx (fun r -> - let t = mk_mono() in - r := (fun() -> t); - unify_raise ctx (build_generic ctx c p pl) t p; - t - ) "build_generic" in - delay ctx PForce (fun() -> ignore ((!r)())); - TLazy r + build (fun () -> build_generic ctx c p pl) "build_generic" | KMacroType -> - let r = exc_protect ctx (fun r -> - let t = mk_mono() in - r := (fun() -> t); - unify_raise ctx (build_macro_type ctx pl p) t p; - t - ) "macro_type" in - delay ctx PForce (fun() -> ignore ((!r)())); - TLazy r + build (fun () -> build_macro_type ctx pl p) "macro_type" + | KGenericBuild cfl -> + build (fun () -> build_macro_build ctx c pl cfl p) "generic_build" | _ -> TInst (c,pl) ) in - c.cl_types , c.cl_path , ft + c.cl_params , c.cl_path , ft | TEnumDecl e -> - e.e_types , e.e_path , (fun t -> TEnum (e,t)) + e.e_params , e.e_path , (fun t -> TEnum (e,t)) | TTypeDecl t -> - t.t_types , t.t_path , (fun tl -> TType(t,tl)) + t.t_params , t.t_path , (fun tl -> TType(t,tl)) | TAbstractDecl a -> - a.a_types, a.a_path, (fun tl -> TAbstract(a,tl)) + a.a_params, a.a_path, (fun tl -> TAbstract(a,tl)) let on_inherit ctx c p h = match h with @@ -565,804 +677,23 @@ let on_inherit ctx c p h = | HExtends { tpackage = ["haxe";"remoting"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } -> extend_remoting ctx c t p true true; false - | HExtends { tpackage = ["mt"]; tname = "AsyncProxy"; tparams = [TPType(CTPath t)] } -> - extend_remoting ctx c t p true false; - false | HExtends { tpackage = ["haxe";"xml"]; tname = "Proxy"; tparams = [TPExpr(EConst (String file),p);TPType t] } -> extend_xml_proxy ctx c t file p; true | _ -> true -(* -------------------------------------------------------------------------- *) -(* FINAL GENERATION *) - -(* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *) -let save_class_state ctx t = match t with - | TClassDecl c -> - let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern in - let fl = c.cl_fields and ofl = c.cl_ordered_fields and st = c.cl_statics and ost = c.cl_ordered_statics in - let cst = c.cl_constructor and over = c.cl_overrides in - let oflk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ofl in - let ostk = List.map (fun f -> f.cf_kind,f.cf_expr,f.cf_type) ost in - c.cl_restore <- (fun() -> - c.cl_meta <- meta; - c.cl_extern <- ext; - c.cl_path <- path; - c.cl_fields <- fl; - c.cl_ordered_fields <- ofl; - c.cl_statics <- st; - c.cl_ordered_statics <- ost; - c.cl_constructor <- cst; - c.cl_overrides <- over; - (* DCE might modify the cf_kind, so let's restore it as well *) - List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ofl oflk; - List.iter2 (fun f (k,e,t) -> f.cf_kind <- k; f.cf_expr <- e; f.cf_type <- t;) ost ostk; - ) - | _ -> - () - - -(* Checks if a private class' path clashes with another path *) -let check_private_path ctx t = match t with - | TClassDecl c when c.cl_private -> - let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in - if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos; - | _ -> - () - -(* Removes generic base classes *) -let remove_generic_base ctx t = match t with - | TClassDecl c when c.cl_kind = KGeneric && has_ctor_constraint c -> - c.cl_extern <- true - | _ -> - () - -(* Rewrites class or enum paths if @:native metadata is set *) -let apply_native_paths ctx t = - let get_real_path meta path = - let (_,e,mp) = Meta.get Meta.Native meta in - match e with - | [Ast.EConst (Ast.String name),p] -> - (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)),p],mp),parse_path name - | _ -> - error "String expected" mp - in - try - (match t with - | TClassDecl c -> - let meta,path = get_real_path c.cl_meta c.cl_path in - c.cl_meta <- meta :: c.cl_meta; - c.cl_path <- path; - | TEnumDecl e -> - let meta,path = get_real_path e.e_meta e.e_path in - e.e_meta <- meta :: e.e_meta; - e.e_path <- path; - | _ -> - ()) - with Not_found -> - () - -(* Adds the __rtti field if required *) -let add_rtti ctx t = - let rec has_rtti c = - Meta.has Meta.Rtti c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti csup - in - match t with - | TClassDecl c when has_rtti c && not (PMap.mem "__rtti" c.cl_statics) -> - let f = mk_field "__rtti" ctx.t.tstring c.cl_pos in - let str = Genxml.gen_type_string ctx.com t in - f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos); - c.cl_ordered_statics <- f :: c.cl_ordered_statics; - c.cl_statics <- PMap.add f.cf_name f c.cl_statics; - | _ -> - () - -(* Removes extern and macro fields, also checks for Void fields *) -let remove_extern_fields ctx t = match t with - | TClassDecl c -> - let do_remove f = - Meta.has Meta.Extern f.cf_meta || Meta.has Meta.Generic f.cf_meta - || (match f.cf_kind with - | Var {v_read = AccRequire (s,_)} -> true - | Method MethMacro -> not ctx.in_macro - | _ -> false) - in - if not (Common.defined ctx.com Define.DocGen) then begin - c.cl_ordered_fields <- List.filter (fun f -> - let b = do_remove f in - if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields; - not b - ) c.cl_ordered_fields; - c.cl_ordered_statics <- List.filter (fun f -> - let b = do_remove f in - if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics; - not b - ) c.cl_ordered_statics; - end - | _ -> - () - -(* Adds member field initializations as assignments to the constructor *) -let add_field_inits ctx t = - let apply c = - let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_types)) c.cl_pos in - (* TODO: we have to find a variable name which is not used in any of the functions *) - let v = alloc_var "_g" ethis.etype in - 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 ctx.com.config.pf_can_init_member cf then (inits, cf :: fields) else (cf :: inits, cf :: fields) - | Method MethDynamic, Some e when Common.defined ctx.com Define.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) - | _ -> (inits, cf :: fields) - ) ([],[]) c.cl_ordered_fields in - c.cl_ordered_fields <- fields; - match inits with - | [] -> () - | _ -> - let el = List.map (fun cf -> - match cf.cf_expr with - | None -> assert false - | Some e -> - let lhs = mk (TField(ethis,FInstance (c,cf))) cf.cf_type e.epos in - cf.cf_expr <- None; - let eassign = mk (TBinop(OpAssign,lhs,e)) e.etype e.epos in - if Common.defined ctx.com Define.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; - ) inits in - let el = if !need_this then (mk (TVars([v, Some ethis])) ethis.etype ethis.epos) :: el else el in - match c.cl_constructor with - | None -> - let ct = TFun([],ctx.com.basic.tvoid) in - let ce = mk (TFunction { - tf_args = []; - tf_type = ctx.com.basic.tvoid; - tf_expr = mk (TBlock el) ctx.com.basic.tvoid c.cl_pos; - }) ct c.cl_pos in - let ctor = mk_field "new" ct c.cl_pos in - ctor.cf_kind <- Method MethNormal; - c.cl_constructor <- Some { ctor with cf_expr = Some ce }; - | Some cf -> - match cf.cf_expr with - | Some { eexpr = TFunction f } -> - let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in - 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 - c.cl_constructor <- Some {cf with cf_expr = Some ce } - | _ -> - assert false - in - match t with - | TClassDecl c -> - apply c - | _ -> - () - -(* Adds the __meta__ field if required *) -let add_meta_field ctx t = match t with - | TClassDecl c -> - (match build_metadata ctx.com t with - | None -> () - | Some e -> - let f = mk_field "__meta__" t_dynamic c.cl_pos in - f.cf_expr <- Some e; - c.cl_ordered_statics <- f :: c.cl_ordered_statics; - c.cl_statics <- PMap.add f.cf_name f c.cl_statics) - | _ -> - () - -(* Removes interfaces tagged with @:remove metadata *) -let check_remove_metadata ctx t = match t with - | TClassDecl c -> - c.cl_implements <- List.filter (fun (c,_) -> not (Meta.has Meta.Remove c.cl_meta)) c.cl_implements; - | _ -> - () - -(* Checks for Void class fields *) -let check_void_field ctx t = match t with - | TClassDecl c -> - let check f = - match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed" f.cf_pos | _ -> (); - in - List.iter check c.cl_ordered_fields; - List.iter check c.cl_ordered_statics; - | _ -> - () - -(* Promotes type parameters of abstracts to their implementation fields *) -let promote_abstract_parameters ctx t = match t with - | TClassDecl ({cl_kind = KAbstractImpl a} as c) when a.a_types <> [] -> - List.iter (fun f -> - List.iter (fun (n,t) -> match t with - | TInst({cl_kind = KTypeParameter _; cl_path=p,n} as cp,[]) when not (List.mem_assoc n f.cf_params) -> - let path = List.rev ((snd c.cl_path) :: List.rev (fst c.cl_path)),n in - f.cf_params <- (n,TInst({cp with cl_path = path},[])) :: f.cf_params - | _ -> - () - ) a.a_types; - ) c.cl_ordered_statics; - | _ -> - () - -(* -------------------------------------------------------------------------- *) -(* LOCAL VARIABLES USAGE *) - -type usage = - | Block of ((usage -> unit) -> unit) - | Loop of ((usage -> unit) -> unit) - | Function of ((usage -> unit) -> unit) - | Declare of tvar - | Use of tvar - -let rec local_usage f e = - match e.eexpr with - | TLocal v -> - f (Use v) - | TVars l -> - List.iter (fun (v,e) -> - (match e with None -> () | Some e -> local_usage f e); - f (Declare v); - ) l - | TFunction tf -> - let cc f = - List.iter (fun (v,_) -> f (Declare v)) tf.tf_args; - local_usage f tf.tf_expr; - in - f (Function cc) - | TBlock l -> - f (Block (fun f -> List.iter (local_usage f) l)) - | TFor (v,it,e) -> - local_usage f it; - f (Loop (fun f -> - f (Declare v); - local_usage f e; - )) - | TWhile _ -> - f (Loop (fun f -> - iter (local_usage f) e - )) - | TTry (e,catchs) -> - local_usage f e; - List.iter (fun (v,e) -> - f (Block (fun f -> - f (Declare v); - local_usage f e; - )) - ) catchs; - | TMatch (e,_,cases,def) -> - local_usage f e; - List.iter (fun (_,vars,e) -> - let cc f = - (match vars with - | None -> () - | Some l -> List.iter (function None -> () | Some v -> f (Declare v)) l); - local_usage f e; - in - f (Block cc) - ) cases; - (match def with None -> () | Some e -> local_usage f e); - | _ -> - iter (local_usage f) e - -(* -------------------------------------------------------------------------- *) -(* BLOCK VARIABLES CAPTURE *) - -(* - For some platforms, it will simply mark the variables which are used in closures - using the v_capture flag so it can be processed in a more optimized - - For Flash/JS platforms, it will ensure that variables used in loop sub-functions - have an unique scope. It transforms the following expression : - - for( x in array ) - funs.push(function() return x++); - - Into the following : - - for( _x in array ) { - var x = [_x]; - funs.push(function(x) { function() return x[0]++; }(x)); - } -*) - -let captured_vars com e = - - let t = com.basic in - - let rec mk_init av v pos = - mk (TVars [av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos)]) t.tvoid pos - - and mk_var v used = - alloc_var v.v_name (PMap.find v.v_id used) - - and wrap used e = - match e.eexpr with - | TVars vl -> - let vl = List.map (fun (v,ve) -> - if PMap.mem v.v_id used then - v, Some (mk (TArrayDecl (match ve with None -> [] | Some e -> [wrap used e])) v.v_type e.epos) - else - v, (match ve with None -> None | Some e -> Some (wrap used e)) - ) vl in - { e with eexpr = TVars vl } - | TLocal v when PMap.mem v.v_id used -> - mk (TArray ({ e with etype = v.v_type },mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos - | TFor (v,it,expr) when PMap.mem v.v_id used -> - let vtmp = mk_var v used in - let it = wrap used it in - let expr = wrap used expr in - mk (TFor (vtmp,it,concat (mk_init v vtmp e.epos) expr)) e.etype e.epos - | TTry (expr,catchs) -> - let catchs = List.map (fun (v,e) -> - let e = wrap used e in - try - let vtmp = mk_var v used in - vtmp, concat (mk_init v vtmp e.epos) e - with Not_found -> - v, e - ) catchs in - mk (TTry (wrap used expr,catchs)) e.etype e.epos - | TMatch (expr,enum,cases,def) -> - let cases = List.map (fun (il,vars,e) -> - let pos = e.epos in - let e = ref (wrap used e) in - let vars = match vars with - | None -> None - | Some l -> - Some (List.map (fun v -> - match v with - | Some v when PMap.mem v.v_id used -> - let vtmp = mk_var v used in - e := concat (mk_init v vtmp pos) !e; - Some vtmp - | _ -> v - ) l) - in - il, vars, !e - ) cases in - let def = match def with None -> None | Some e -> Some (wrap used e) in - mk (TMatch (wrap used expr,enum,cases,def)) e.etype e.epos - | TFunction f -> - (* - list variables that are marked as used, but also used in that - function and which are not declared inside it ! - *) - let fused = ref PMap.empty in - let tmp_used = ref used in - let rec browse = function - | Block f | Loop f | Function f -> f browse - | Use v -> - if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused; - | Declare v -> - tmp_used := PMap.remove v.v_id !tmp_used - in - local_usage browse e; - let vars = PMap.fold (fun v acc -> v :: acc) !fused [] in - - (* in case the variable has been marked as used in a parallel scope... *) - let fexpr = ref (wrap used f.tf_expr) in - let fargs = List.map (fun (v,o) -> - if PMap.mem v.v_id used then - let vtmp = mk_var v used in - fexpr := concat (mk_init v vtmp e.epos) !fexpr; - vtmp, o - else - v, o - ) f.tf_args in - let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in - (* - Create a new function scope to make sure that the captured loop variable - will not be overwritten in next loop iteration - *) - if com.config.pf_capture_policy = CPLoopVars then - mk (TCall ( - mk_parent (mk (TFunction { - tf_args = List.map (fun v -> v, None) vars; - tf_type = e.etype; - tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos); - }) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos), - List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars) - ) e.etype e.epos - else - e - | _ -> - map_expr (wrap used) e - - and do_wrap used e = - if PMap.is_empty used then - e - else - let used = PMap.map (fun v -> - let vt = v.v_type in - v.v_type <- t.tarray vt; - v.v_capture <- true; - vt - ) used in - wrap used e - - and out_loop e = - match e.eexpr with - | TFor _ | TWhile _ -> - (* - collect variables that are declared in loop but used in subfunctions - *) - let vars = ref PMap.empty in - let used = ref PMap.empty in - let depth = ref 0 in - let rec collect_vars in_loop = function - | Block f -> - let old = !vars in - f (collect_vars in_loop); - vars := old; - | Loop f -> - let old = !vars in - f (collect_vars true); - vars := old; - | Function f -> - incr depth; - f (collect_vars false); - decr depth; - | Declare v -> - if in_loop then vars := PMap.add v.v_id !depth !vars; - | Use v -> - try - let d = PMap.find v.v_id !vars in - if d <> !depth then used := PMap.add v.v_id v !used; - with Not_found -> - () - in - local_usage (collect_vars false) e; - do_wrap !used e - | _ -> - map_expr out_loop e - and all_vars e = - let vars = ref PMap.empty in - let used = ref PMap.empty in - let depth = ref 0 in - let rec collect_vars = function - | Block f -> - let old = !vars in - f collect_vars; - vars := old; - | Loop f -> - let old = !vars in - f collect_vars; - vars := old; - | Function f -> - incr depth; - f collect_vars; - decr depth; - | Declare v -> - vars := PMap.add v.v_id !depth !vars; - | Use v -> - try - let d = PMap.find v.v_id !vars in - if d <> !depth then used := PMap.add v.v_id v !used; - with Not_found -> () - in - local_usage collect_vars e; - !used - in - (* mark all capture variables - also used in rename_local_vars at later stage *) - let captured = all_vars e in - PMap.iter (fun _ v -> v.v_capture <- true) captured; - match com.config.pf_capture_policy with - | CPNone -> e - | CPWrapRef -> do_wrap captured e - | CPLoopVars -> out_loop e - -(* -------------------------------------------------------------------------- *) -(* RENAME LOCAL VARS *) - -let rename_local_vars com e = - let cfg = com.config in - let all_scope = (not cfg.pf_captured_scope) || (not cfg.pf_locals_scope) in - let vars = ref PMap.empty in - let all_vars = ref PMap.empty in - let vtemp = alloc_var "~" t_dynamic in - let rebuild_vars = ref false in - let rebuild m = - PMap.fold (fun v acc -> PMap.add v.v_name v acc) m PMap.empty - in - let save() = - let old = !vars in - if cfg.pf_unique_locals then (fun() -> ()) else (fun() -> vars := if !rebuild_vars then rebuild old else old) - in - let rename vars v = - let count = ref 1 in - while PMap.mem (v.v_name ^ string_of_int !count) vars do - incr count; - done; - v.v_name <- v.v_name ^ string_of_int !count; - in - let declare v p = - (match follow v.v_type with - | TAbstract ({a_path = [],"Void"},_) -> error "Arguments and variables of type Void are not allowed" p - | _ -> ()); - (* chop escape char for all local variables generated *) - if String.unsafe_get v.v_name 0 = String.unsafe_get gen_local_prefix 0 then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1); - let look_vars = (if not cfg.pf_captured_scope && v.v_capture then !all_vars else !vars) in - (try - let v2 = PMap.find v.v_name look_vars in - (* - block_vars will create some wrapper-functions that are declaring - the same variable twice. In that case do not perform a rename since - we are sure it's actually the same variable - *) - if v == v2 then raise Not_found; - rename look_vars v; - with Not_found -> - ()); - vars := PMap.add v.v_name v !vars; - if all_scope then all_vars := PMap.add v.v_name v !all_vars; - in - (* - This is quite a rare case, when a local variable would otherwise prevent - accessing a type because it masks the type value or the package name. - *) - let check t = - match (t_infos t).mt_path with - | [], name | name :: _, _ -> - let vars = if cfg.pf_locals_scope then vars else all_vars in - (try - let v = PMap.find name !vars in - if v == vtemp then raise Not_found; (* ignore *) - rename (!vars) v; - rebuild_vars := true; - vars := PMap.add v.v_name v !vars - with Not_found -> - ()); - vars := PMap.add name vtemp !vars - 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 loop e = - match e.eexpr with - | TVars l -> - List.iter (fun (v,eo) -> - if not cfg.pf_locals_scope then declare v e.epos; - (match eo with None -> () | Some e -> loop e); - if cfg.pf_locals_scope then declare v e.epos; - ) l - | TFunction tf -> - let old = save() in - List.iter (fun (v,_) -> declare v e.epos) tf.tf_args; - loop tf.tf_expr; - old() - | TBlock el -> - let old = save() in - List.iter loop el; - old() - | TFor (v,it,e1) -> - loop it; - let old = save() in - declare v e.epos; - loop e1; - old() - | TTry (e,catchs) -> - loop e; - List.iter (fun (v,e) -> - let old = save() in - declare v e.epos; - check_type v.v_type; - loop e; - old() - ) catchs; - | TMatch (e,_,cases,def) -> - loop e; - List.iter (fun (_,vars,e) -> - let old = save() in - (match vars with - | None -> () - | Some l -> List.iter (function None -> () | Some v -> declare v e.epos) l); - loop e; - old(); - ) cases; - (match def with None -> () | Some e -> loop e); - | TTypeExpr t -> - check t - | TNew (c,_,_) -> - Type.iter loop e; - check (TClassDecl c); - | TCast (e,Some t) -> - loop e; - check t; - | _ -> - Type.iter loop e - in - declare (alloc_var "this" t_dynamic) Ast.null_pos; (* force renaming of 'this' vars in abstract *) - loop e; - e - -(* -------------------------------------------------------------------------- *) -(* CHECK LOCAL VARS INIT *) - -let check_local_vars_init e = - let intersect vl1 vl2 = - PMap.mapi (fun v t -> t && PMap.find v vl2) vl1 - in - let join vars cvars = - List.iter (fun v -> vars := intersect !vars v) cvars - in - let restore vars old_vars declared = - (* restore variables declared in this block to their previous state *) - vars := List.fold_left (fun acc v -> - try PMap.add v (PMap.find v old_vars) acc with Not_found -> PMap.remove v acc - ) !vars declared; - in - let declared = ref [] in - let rec loop vars e = - match e.eexpr with - | TLocal v -> - let init = (try PMap.find v.v_id !vars with Not_found -> true) in - if not init 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 - end - | TVars vl -> - List.iter (fun (v,eo) -> - match eo with - | None -> - declared := v.v_id :: !declared; - vars := PMap.add v.v_id false !vars - | Some e -> - loop vars e - ) vl - | TBlock el -> - let old = !declared in - let old_vars = !vars in - declared := []; - List.iter (loop vars) el; - restore vars old_vars (List.rev !declared); - declared := old; - | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars -> - loop vars e; - vars := PMap.add v.v_id true !vars - | TIf (e1,e2,eo) -> - loop vars e1; - let vbase = !vars in - loop vars e2; - (match eo with - | None -> vars := vbase - | Some e -> - let v1 = !vars in - vars := vbase; - loop vars e; - vars := intersect !vars v1) - | TWhile (cond,e,flag) -> - (match flag with - | NormalWhile -> - loop vars cond; - let old = !vars in - loop vars e; - vars := old; - | DoWhile -> - loop vars e; - loop vars cond) - | TTry (e,catches) -> - let cvars = List.map (fun (v,e) -> - let old = !vars in - loop vars e; - let v = !vars in - vars := old; - v - ) catches in - loop vars e; - join vars cvars; - | TSwitch (e,cases,def) -> - loop vars e; - let cvars = List.map (fun (ec,e) -> - let old = !vars in - List.iter (loop vars) ec; - vars := old; - loop vars e; - let v = !vars in - vars := old; - v - ) cases in - (match def with - | None -> () - | Some e -> - loop vars e; - join vars cvars) - | TMatch (e,_,cases,def) -> - loop vars e; - let old = !vars in - let cvars = List.map (fun (_,vl,e) -> - vars := old; - loop vars e; - restore vars old []; - !vars - ) cases in - (match def with None -> () | Some e -> vars := old; loop vars e); - join vars cvars - (* mark all reachable vars as initialized, since we don't exit the block *) - | TBreak | TContinue | TReturn None -> - vars := PMap.map (fun _ -> true) !vars - | TThrow e | TReturn (Some e) -> - loop vars e; - vars := PMap.map (fun _ -> true) !vars - | _ -> - Type.iter (loop vars) e - in - loop (ref PMap.empty) e; - e - (* -------------------------------------------------------------------------- *) (* ABSTRACT CASTS *) -module Abstract = struct - - let find_to ab pl b = List.find (Type.unify_to_field ab pl b) ab.a_to - let find_from ab pl a b = List.find (Type.unify_from_field ab pl a b) ab.a_from +module AbstractCast = struct let cast_stack = ref [] - let get_underlying_type a pl = - try - if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found; - let m = mk_mono() in - let _ = find_to a pl m in - follow m - with Not_found -> - apply_params a.a_types pl a.a_this - - let rec make_static_call ctx c cf a pl args t p = - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in - let ethis = mk (TTypeExpr (TClassDecl c)) ta p in - let monos = List.map (fun _ -> mk_mono()) cf.cf_params in - let map t = apply_params a.a_types pl (apply_params cf.cf_params monos t) in - let tcf = match follow (map cf.cf_type),args with - | TFun((_,_,ta) :: args,r) as tf,e :: el when Meta.has Meta.From cf.cf_meta -> - unify ctx e.etype ta p; - tf - | t,_ -> t - in - let def () = - let e = mk (TField (ethis,(FStatic (c,cf)))) tcf p in - loop ctx (mk (TCall(e,args)) (map t) p) - in - match cf.cf_expr with - | Some { eexpr = TFunction fd } when cf.cf_kind = Method MethInline -> - let config = if Meta.has Meta.Impl cf.cf_meta then (Some (a.a_types <> [] || cf.cf_params <> [], map)) else None in - (match Optimizer.type_inline ctx cf fd ethis args t config p true with - | Some e -> (match e.eexpr with TCast(e,None) -> e | _ -> e) - | None -> def()) - | _ -> - def() + let make_static_call ctx c cf a pl args t p = + make_static_call ctx c cf (apply_params a.a_params pl) args t p - and check_cast ctx tleft eright p = - let tright = follow eright.etype in - let tleft = follow tleft in - if tleft == tright then eright else + let do_check_cast ctx tleft eright p = let recurse cf f = if cf == ctx.curfield || List.mem cf !cast_stack then error "Recursive implicit cast" p; cast_stack := cf :: !cast_stack; @@ -1370,167 +701,361 @@ module Abstract = struct cast_stack := List.tl !cast_stack; r in - try (match tright,tleft with - | (TAbstract({a_impl = Some c1} as a1,pl1) as t1),(TAbstract({a_impl = Some c2} as a2,pl2) as t2) -> - if a1 == a2 then - eright - else begin - let c,cfo,a,pl = try - if Meta.has Meta.MultiType a1.a_meta then raise Not_found; - c1,snd (find_to a1 pl1 t2),a1,pl1 - with Not_found -> - if Meta.has Meta.MultiType a2.a_meta then raise Not_found; - c2,snd (find_from a2 pl2 t1 t2),a2,pl2 - in - match cfo with - | None -> eright - | Some cf -> - recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p) + let find a tl f = + let tcf,cf = f() in + if (Meta.has Meta.MultiType a.a_meta) then + mk_cast eright tleft p + else match a.a_impl with + | Some c -> recurse cf (fun () -> + 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 + in + if type_iseq tleft eright.etype then + eright + else begin + let rec loop tleft tright = match follow tleft,follow tright with + | TAbstract(a1,tl1),TAbstract(a2,tl2) -> + begin try find a2 tl2 (fun () -> Abstract.find_to a2 tl2 tleft) + with Not_found -> try find a1 tl1 (fun () -> Abstract.find_from a1 tl1 eright.etype tleft) + with Not_found -> raise Not_found end - | TDynamic _,_ | _,TDynamic _ -> - eright - | TAbstract({a_impl = Some c} as a,pl),t2 when not (Meta.has Meta.MultiType a.a_meta) -> - begin match find_to a pl t2 with - | tcf,None -> - let tcf = apply_params a.a_types pl tcf in - if type_iseq tcf tleft then eright else check_cast ctx tcf eright p - | _,Some cf -> - recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p) + | TAbstract(a,tl),_ -> + begin try find a tl (fun () -> Abstract.find_from a tl eright.etype tleft) + with Not_found -> + let rec loop2 tcl = match tcl with + | tc :: tcl -> + if not (type_iseq tc tleft) then loop (apply_params a.a_params tl tc) tright + else loop2 tcl + | [] -> raise Not_found + in + loop2 a.a_from end - | t1,(TAbstract({a_impl = Some c} as a,pl) as t2) when not (Meta.has Meta.MultiType a.a_meta) -> - begin match find_from a pl t1 t2 with - | tcf,None -> - let tcf = apply_params a.a_types pl tcf in - if type_iseq tcf tleft then eright else check_cast ctx tcf eright p - | _,Some cf -> - recurse cf (fun () -> make_static_call ctx c cf a pl [eright] tleft p) + | _,TAbstract(a,tl) -> + begin try find a tl (fun () -> Abstract.find_to a tl tleft) + with Not_found -> + let rec loop2 tcl = match tcl with + | tc :: tcl -> + if not (type_iseq tc tright) then loop tleft (apply_params a.a_params tl tc) + else loop2 tcl + | [] -> raise Not_found + in + loop2 a.a_to end | _ -> - eright) + raise Not_found + in + loop tleft eright.etype + end + + let cast_or_unify_raise ctx tleft eright p = + try + if ctx.com.display <> DMNone then raise Not_found; + do_check_cast ctx tleft eright p with Not_found -> + unify_raise ctx eright.etype tleft p; eright - and call_args ctx el tl = match el,tl with - | [],_ -> [] - | e :: el, [] -> (loop ctx e) :: call_args ctx el [] - | e :: el, (_,_,t) :: tl -> - (check_cast ctx t (loop ctx e) e.epos) :: call_args ctx el tl - - and loop ctx e = match e.eexpr with - | TBinop(OpAssign,e1,e2) -> - let e2 = check_cast ctx e1.etype (loop ctx e2) e.epos in - { e with eexpr = TBinop(OpAssign,loop ctx e1,e2) } - | TVars vl -> - let vl = List.map (fun (v,eo) -> match eo with - | None -> (v,eo) - | Some e -> - let is_generic_abstract = match e.etype with TAbstract ({a_impl = Some _} as a,_) -> Meta.has Meta.MultiType a.a_meta | _ -> false in - let e = check_cast ctx v.v_type (loop ctx e) e.epos in - (* we can rewrite this for better field inference *) - if is_generic_abstract then v.v_type <- e.etype; - v, Some e - ) vl in - { e with eexpr = TVars vl } - | TNew({cl_kind = KAbstractImpl a} as c,pl,el) -> - (* a TNew of an abstract implementation is only generated if it is a generic abstract *) - let at = apply_params a.a_types pl a.a_this in - let m = mk_mono() in - let _,cfo = - try find_to a pl m - with Not_found -> - let st = s_type (print_context()) at in - if has_mono at then - error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") e.epos - else - error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) e.epos; - in - begin match cfo with - | None -> assert false - | Some cf -> - let m = follow m in - let e = make_static_call ctx c cf a pl ((mk (TConst TNull) at e.epos) :: el) m e.epos in - {e with etype = m} - end - | TNew(c,pl,el) -> - begin try - let t,_ = (!get_constructor_ref) ctx c pl e.epos in - begin match follow t with - | TFun(args,_) -> - { e with eexpr = TNew(c,pl,call_args ctx el args)} - | _ -> - Type.map_expr (loop ctx) e - end - with Error _ -> - (* TODO: when does this happen? *) - Type.map_expr (loop ctx) e - end - | TCall(e1, el) -> - let e1 = loop ctx e1 in - begin try - begin match e1.eexpr with - | TField(_,FStatic(_,cf)) when Meta.has Meta.To cf.cf_meta -> - (* do not recurse over @:to functions to avoid infinite recursion *) - { e with eexpr = TCall(e1,el)} - | TField(e2,fa) -> - begin match follow e2.etype with - | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta -> - let m = get_underlying_type a pl in - let fname = field_name fa in - let el = List.map (loop ctx) el in - begin try - let ef = mk (TField({e2 with etype = m},quick_field m fname)) e1.etype e2.epos in - make_call ctx ef el e.etype e.epos - with Not_found -> - (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *) - match follow m with - | TAbstract({a_impl = Some c} as a,pl) -> - let cf = PMap.find fname c.cl_statics in - make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos - | _ -> raise Not_found - end - | _ -> raise Not_found - end - | _ -> - raise Not_found - end + let cast_or_unify ctx tleft eright p = + try + cast_or_unify_raise ctx tleft eright p + with Error (Unify _ as err,_) -> + if not ctx.untyped then display_error ctx (error_msg err) p; + eright + + 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 + | [] -> raise Not_found + | cf :: cfl when not (Ast.Meta.has Ast.Meta.ArrayAccess cf.cf_meta) -> + loop cfl + | cf :: cfl -> + let monos = List.map (fun _ -> mk_mono()) cf.cf_params in + let map t = apply_params a.a_params pl (apply_params cf.cf_params monos t) in + let check_constraints () = + 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 []) | _ -> Type.unify m (map tc) ) constr + | _ -> () + ) monos cf.cf_params; + in + match follow (map cf.cf_type) with + | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r) as tf when is_set -> + begin try + Type.unify tab 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(); + cf,tf,r,e1,e2o + with Unify_error _ | Error (Unify _,_) -> + loop cfl + end + | TFun([(_,_,tab);(_,_,ta1)],r) as tf when not is_set -> + begin try + Type.unify tab ta; + let e1 = cast_or_unify_raise ctx ta1 e1 p in + check_constraints(); + cf,tf,r,e1,None + with Unify_error _ | Error (Unify _,_) -> + loop cfl + end + | _ -> loop cfl + in + loop a.a_array + + 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 + | None -> + error (Printf.sprintf "No @:arrayAccess function accepts argument of %s" (s_type (print_context()) 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 + + let find_multitype_specialization com a pl p = + let m = mk_mono() in + let tl = match Meta.get Meta.MultiType a.a_meta with + | _,[],_ -> pl + | _,el,_ -> + let relevant = Hashtbl.create 0 in + List.iter (fun e -> match fst e with + | EConst(Ident s) -> Hashtbl.replace relevant s true + | _ -> error "Type parameter expected" (pos e) + ) el; + let tl = List.map2 (fun (n,_) t -> if Hashtbl.mem relevant n || not (has_mono t) then t else t_dynamic) a.a_params pl in + if com.platform = Js && a.a_path = ([],"Map") then begin match tl with + | t1 :: _ -> + let rec loop stack t = + if List.exists (fun t2 -> fast_eq t t2) stack then + t + else begin + let stack = t :: stack in + 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; + | TEnum(en,tl) -> + PMap.iter (fun _ ef -> ignore(loop stack ef.ef_type)) en.e_constrs; + Type.map (loop stack) t + | t -> + Type.map (loop stack) t + end + in + ignore(loop [] t1) + | _ -> assert false + end; + tl + in + let _,cf = + try + Abstract.find_to a tl m with Not_found -> + let at = apply_params a.a_params pl a.a_this in + let st = s_type (print_context()) at in + if has_mono at then + error ("Type parameters of multi type abstracts must be known (for " ^ st ^ ")") p + else + error ("Abstract " ^ (s_type_path a.a_path) ^ " has no @:to function that accepts " ^ st) p; + in + cf, follow m + + let handle_abstract_casts ctx e = + let rec loop ctx e = match e.eexpr with + | TNew({cl_kind = KAbstractImpl a} as c,pl,el) -> + (* a TNew of an abstract implementation is only generated if it is a multi type abstract *) + let cf,m = find_multitype_specialization ctx.com a pl e.epos in + let e = make_static_call ctx c cf a pl ((mk (TConst TNull) (TAbstract(a,pl)) e.epos) :: el) m e.epos in + {e with etype = m} + | TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))},[e1]) when (match follow e1.etype with TAbstract({a_impl = Some _},_) -> true | _ -> false) -> begin match follow e1.etype with - | TFun(args,_) -> - { e with eexpr = TCall(loop ctx e1,call_args ctx el args)} + | TAbstract({a_impl = Some c} as a,tl) -> + begin try + let cf = PMap.find "toString" c.cl_statics in + make_static_call ctx c cf a tl [e1] ctx.t.tstring e.epos + with Not_found -> + e + end | _ -> - Type.map_expr (loop ctx) e + assert false end - end - | TArrayDecl el -> - begin match e.etype with - | TInst(_,[t]) -> - let el = List.map (fun e -> check_cast ctx t (loop ctx e) e.epos) el in - { e with eexpr = TArrayDecl el} - | _ -> + | TCall(e1, el) -> + begin try + let rec find_abstract e = match follow e.etype,e.eexpr with + | TAbstract(a,pl),_ when Meta.has Meta.MultiType a.a_meta -> a,pl,e + | _,TCast(e1,None) -> find_abstract e1 + | _ -> raise Not_found + in + let rec find_field e1 = + match e1.eexpr with + | TCast(e2,None) -> + {e1 with eexpr = TCast(find_field e2,None)} + | TField(e2,fa) -> + let a,pl,e2 = find_abstract e2 in + let m = Abstract.get_underlying_type a pl in + let fname = field_name fa in + let el = List.map (loop ctx) el in + begin try + let fa = quick_field m fname in + let get_fun_type t = match follow t with + | TFun(_,tr) as tf -> tf,tr + | _ -> raise Not_found + in + let tf,tr = match fa with + | FStatic(_,cf) -> get_fun_type cf.cf_type + | FInstance(c,tl,cf) -> get_fun_type (apply_params c.cl_params tl cf.cf_type) + | FAnon cf -> get_fun_type cf.cf_type + | _ -> raise Not_found + in + let ef = mk (TField({e2 with etype = m},fa)) tf e2.epos in + let ecall = make_call ctx ef el tr e.epos in + if not (type_iseq ecall.etype e.etype) then + mk (TCast(ecall,None)) e.etype e.epos + else + ecall + with Not_found -> + (* quick_field raises Not_found if m is an abstract, we have to replicate the 'using' call here *) + match follow m with + | TAbstract({a_impl = Some c} as a,pl) -> + let cf = PMap.find fname c.cl_statics in + make_static_call ctx c cf a pl (e2 :: el) e.etype e.epos + | _ -> raise Not_found + end + | _ -> + raise Not_found + in + find_field e1 + with Not_found -> Type.map_expr (loop ctx) e - end - | TObjectDecl fl -> - begin match follow e.etype with - | TAnon a -> - let fl = List.map (fun (n,e) -> - try - let cf = PMap.find n a.a_fields in - let e = match e.eexpr with TCast(e1,None) -> e1 | _ -> e in - (n,check_cast ctx cf.cf_type (loop ctx e) e.epos) - with Not_found -> - (n,loop ctx e) - ) fl in - { e with eexpr = TObjectDecl fl } + end | _ -> Type.map_expr (loop ctx) e - end - | _ -> - Type.map_expr (loop ctx) e + in + loop ctx e +end +module PatternMatchConversion = struct - let handle_abstract_casts ctx e = - loop ctx e + type cctx = { + ctx : typer; + mutable eval_stack : ((tvar * pos) * texpr) list list; + dt_lookup : dt array; + } + + let is_declared cctx v = + let rec loop sl = match sl with + | stack :: sl -> + List.exists (fun ((v2,_),_) -> v == v2) stack || loop sl + | [] -> + false + in + loop cctx.eval_stack + + let group_cases cases = + let dt_eq dt1 dt2 = match dt1,dt2 with + | DTGoto i1, DTGoto i2 when i1 = i2 -> true + (* TODO equal bindings *) + | _ -> false + in + match List.rev cases with + | [] -> [] + | [con,dt] -> [[con],dt] + | (con,dt) :: cases -> + let tmp,ldt,cases = List.fold_left (fun (tmp,ldt,acc) (con,dt) -> + if dt_eq dt ldt then + (con :: tmp,dt,acc) + else + ([con],dt,(tmp,ldt) :: acc) + ) ([con],dt,[]) cases in + match tmp with + | [] -> cases + | tmp -> ((tmp,ldt) :: cases) + + let replace_locals e = + let v_known = ref IntMap.empty in + let copy v = + let v' = alloc_var v.v_name v.v_type in + v_known := IntMap.add v.v_id v' !v_known; + v' + in + let rec loop e = match e.eexpr with + | TVar(v,e1) -> + let v' = copy v in + let e1 = match e1 with None -> None | Some e -> Some (loop e) in + {e with eexpr = TVar(v',e1)} + | TFor(v,e1,e2) -> + let v' = copy v in + let e1 = loop e1 in + let e2 = loop e2 in + {e with eexpr = TFor(v',e1,e2)} + | TTry(e1,catches) -> + let e1 = loop e1 in + let catches = List.map (fun (v,e) -> + let v' = copy v in + let e = loop e in + v',e + ) catches in + {e with eexpr = TTry(e1,catches)} + | TLocal v -> + let v' = try IntMap.find v.v_id !v_known with Not_found -> v in + {e with eexpr = TLocal v'} + | _ -> + Type.map_expr loop e + in + loop e + + let rec convert_dt cctx dt = + match dt with + | DTBind (bl,dt) -> + cctx.eval_stack <- bl :: cctx.eval_stack; + let e = convert_dt cctx dt in + cctx.eval_stack <- List.tl cctx.eval_stack; + let vl,el = List.fold_left (fun (vl,el) ((v,p),e) -> + if is_declared cctx v then + vl, (mk (TBinop(OpAssign,mk (TLocal v) v.v_type p,e)) e.etype e.epos) :: el + else + ((v,p,Some e) :: vl), el + ) ([],[e]) bl in + let el_v = List.map (fun (v,p,eo) -> mk (TVar (v,eo)) cctx.ctx.t.tvoid p) vl in + mk (TBlock (el_v @ el)) e.etype e.epos + | DTGoto i -> + convert_dt cctx (cctx.dt_lookup.(i)) + | DTExpr e -> + e + | DTGuard(e,dt1,dt2) -> + let ethen = convert_dt cctx dt1 in + mk (TIf(e,ethen,match dt2 with None -> None | Some dt -> Some (convert_dt cctx dt))) ethen.etype (punion e.epos ethen.epos) + | DTSwitch({eexpr = TMeta((Meta.Exhaustive,_,_),_)},[_,dt],None) -> + convert_dt cctx dt + | DTSwitch(e_st,cl,dto) -> + let def = match dto with None -> None | Some dt -> Some (convert_dt cctx dt) in + let cases = group_cases cl in + let cases = List.map (fun (cl,dt) -> + let e = convert_dt cctx dt in + (* The macro interpreter does not care about unique locals and + we don't run the analyzer on the output, so let's save some + time here (issue #3937) *) + let e = if cctx.ctx.in_macro then e else replace_locals e in + cl,e + ) cases in + mk (TSwitch(e_st,cases,def)) (mk_mono()) e_st.epos + + let to_typed_ast ctx dt p = + let first = dt.dt_dt_lookup.(dt.dt_first) in + let cctx = { + ctx = ctx; + dt_lookup = dt.dt_dt_lookup; + eval_stack = []; + } in + let e = convert_dt cctx first in + let e = { e with epos = p; etype = dt.dt_type} in + if dt.dt_var_init = [] then + e + else begin + let el_v = List.map (fun (v,eo) -> mk (TVar (v,eo)) cctx.ctx.t.tvoid p) dt.dt_var_init in + mk (TBlock (el_v @ [e])) dt.dt_type e.epos + end end + (* -------------------------------------------------------------------------- *) (* USAGE *) @@ -1538,17 +1063,44 @@ let detect_usage com = let usage = ref [] in List.iter (fun t -> match t with | TClassDecl c -> + let check_constructor c p = + try + let _,cf = get_constructor (fun cf -> cf.cf_type) c in + if Meta.has Meta.Usage cf.cf_meta then + usage := p :: !usage; + with Not_found -> + () + in let rec expr e = match e.eexpr with - | TField(_,fa) -> - (match extract_field fa with - | Some cf when Meta.has Meta.Usage cf.cf_meta -> - let p = {e.epos with pmin = e.epos.pmax - (String.length cf.cf_name)} in - usage := p :: !usage; - | _ -> ()); + | TField(_,FEnum(_,ef)) when Meta.has Meta.Usage ef.ef_meta -> + let p = {e.epos with pmin = e.epos.pmax - (String.length ef.ef_name)} in + usage := p :: !usage; + Type.iter expr e + | TField(_,(FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf))) when Meta.has Meta.Usage cf.cf_meta -> + let p = {e.epos with pmin = e.epos.pmax - (String.length cf.cf_name)} in + usage := p :: !usage; Type.iter expr e + | TLocal v when Meta.has Meta.Usage v.v_meta -> + usage := e.epos :: !usage + | TVar (v,_) when com.display = DMPosition && Meta.has Meta.Usage v.v_meta -> + raise (Typecore.DisplayPosition [e.epos]) + | TFunction tf when com.display = DMPosition && List.exists (fun (v,_) -> Meta.has Meta.Usage v.v_meta) tf.tf_args -> + raise (Typecore.DisplayPosition [e.epos]) + | TTypeExpr mt when (Meta.has Meta.Usage (t_infos mt).mt_meta) -> + usage := e.epos :: !usage + | TNew (c,_,_) -> + check_constructor c e.epos; + Type.iter expr e; + | TCall({eexpr = TConst TSuper},_) -> + begin match c.cl_super with + | Some (c,_) -> + check_constructor c e.epos + | _ -> + () + end | _ -> Type.iter expr e in - let field cf = match cf.cf_expr with None -> () | Some e -> expr e in + let field cf = ignore(follow cf.cf_type); match cf.cf_expr with None -> () | Some e -> expr e in (match c.cl_constructor with None -> () | Some cf -> field cf); (match c.cl_init with None -> () | Some e -> expr e); List.iter field c.cl_ordered_statics; @@ -1561,41 +1113,47 @@ let detect_usage com = ) !usage in raise (Typecore.DisplayPosition usage) -(* -------------------------------------------------------------------------- *) -(* POST PROCESS *) - -let pp_counter = ref 1 - -let post_process filters t = - (* ensure that we don't process twice the same (cached) module *) - let m = (t_infos t).mt_module.m_extra in - if m.m_processed = 0 then m.m_processed <- !pp_counter; - if m.m_processed = !pp_counter then - match t with - | TClassDecl c -> - let process_field f = - match f.cf_expr with - | None -> () - | Some e -> - Abstract.cast_stack := f :: !Abstract.cast_stack; - f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters); - Abstract.cast_stack := List.tl !Abstract.cast_stack; - in - List.iter process_field c.cl_ordered_fields; - List.iter process_field c.cl_ordered_statics; - (match c.cl_constructor with - | None -> () - | Some f -> process_field f); - (match c.cl_init with - | None -> () - | Some e -> - c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters)); - | TEnumDecl _ -> () - | TTypeDecl _ -> () - | TAbstractDecl _ -> () - -let post_process_end() = - incr pp_counter +let update_cache_dependencies com = + let rec check_t m t = match t with + | TInst(c,tl) -> + add_dependency m c.cl_module; + List.iter (check_t m) tl; + | TEnum(en,tl) -> + add_dependency m en.e_module; + List.iter (check_t m) tl; + | TType(t,tl) -> + add_dependency m t.t_module; + List.iter (check_t m) tl; + | TAbstract(a,tl) -> + add_dependency m a.a_module; + List.iter (check_t m) tl; + | TFun(targs,tret) -> + List.iter (fun (_,_,t) -> check_t m t) targs; + check_t m tret; + | TAnon an -> + PMap.iter (fun _ cf -> check_field m cf) an.a_fields + | TMono r -> + (match !r with + | Some t -> check_t m t + | _ -> ()) + | TLazy f -> + check_t m (!f()) + | TDynamic t -> + if t == t_dynamic then + () + else + check_t m t + and check_field m cf = + check_t m cf.cf_type + in + List.iter (fun t -> match t with + | TClassDecl c -> + List.iter (check_field c.cl_module) c.cl_ordered_statics; + List.iter (check_field c.cl_module) c.cl_ordered_fields; + (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf); + | _ -> + () + ) com.types (* -------------------------------------------------------------------------- *) (* STACK MANAGEMENT EMULATION *) @@ -1633,7 +1191,7 @@ let stack_context_init com stack_var exc_var pos_var tmp_var use_add p = let stack_return e = let tmp = alloc_var tmp_var e.etype in mk (TBlock [ - mk (TVars [tmp, Some e]) t.tvoid e.epos; + mk (TVar (tmp, Some e)) t.tvoid e.epos; stack_pop; mk (TReturn (Some (mk (TLocal tmp) e.etype e.epos))) e.etype e.epos ]) e.etype e.epos @@ -1645,7 +1203,7 @@ let stack_context_init com stack_var exc_var pos_var tmp_var use_add p = stack_pos = p; stack_expr = stack_e; stack_pop = stack_pop; - stack_save_pos = mk (TVars [pos_var, Some (field stack_e "length" t.tint p)]) t.tvoid p; + stack_save_pos = mk (TVar (pos_var, Some (field stack_e "length" t.tint p))) t.tvoid p; stack_push = stack_push; stack_return = stack_return; stack_restore = [ @@ -1707,7 +1265,7 @@ let stack_block ctx c m e = exact same type for overriden/implemented function as the original one *) -let rec find_field c f = +let rec find_field com c f = try (match c.cl_super with | None -> @@ -1715,14 +1273,16 @@ let rec find_field c f = | Some ( {cl_path = (["cpp"],"FastIterator")}, _ ) -> raise Not_found (* This is a strongly typed 'extern' and the usual rules don't apply *) | Some (c,_) -> - find_field c f) + find_field com c f) with Not_found -> try + if com.platform = Cpp then (* Cpp uses delegation for interfaces *) + raise Not_found; let rec loop = function | [] -> raise Not_found | (c,_) :: l -> try - find_field c f + find_field com c f with Not_found -> loop l in @@ -1733,20 +1293,28 @@ let rec find_field c f = f let fix_override com c f fd = - let f2 = (try Some (find_field c f) with Not_found -> None) in + 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 changed_args = ref [] in let prefix = "_tmp_" in - let nargs = List.map2 (fun ((v,c) as cur) (_,_,t2) -> + let nargs = List.map2 (fun ((v,ct) as cur) (_,_,t2) -> try - type_eq EqStrict v.v_type t2; + type_eq EqStrict (monomorphs c.cl_params (monomorphs f.cf_params v.v_type)) t2; + (* Flash generates type parameters with a single constraint as that constraint type, so we + have to detect this case and change the variable (issue #2712). *) + begin match follow v.v_type with + | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash -> + if List.mem_assoc (snd cp.cl_path) c.cl_params then raise (Unify_error []) + | _ -> + () + end; cur with Unify_error _ -> let v2 = alloc_var (prefix ^ v.v_name) t2 in changed_args := (v,v2) :: !changed_args; - v2,c + v2,ct ) fd.tf_args targs in let fd2 = { tf_args = nargs; @@ -1757,10 +1325,10 @@ let fix_override com c f fd = let e = fd.tf_expr in let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in let p = (match el with [] -> e.epos | e :: _ -> e.epos) in - let v = mk (TVars (List.map (fun (v,v2) -> - (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p)) - ) args)) com.basic.tvoid p in - { e with eexpr = TBlock (v :: el) } + let el_v = List.map (fun (v,v2) -> + mk (TVar (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))) com.basic.tvoid p + ) args in + { e with eexpr = TBlock (el_v @ el) } ); } in (* as3 does not allow wider visibility, so the base method has to be made public *) @@ -1782,7 +1350,7 @@ let fix_overrides com t = if c.cl_interface then c.cl_ordered_fields <- List.filter (fun f -> try - if find_field c f == f then raise Not_found; + if find_field com c f == f then raise Not_found; c.cl_fields <- PMap.remove f.cf_name c.cl_fields; false; with Not_found -> @@ -1808,7 +1376,7 @@ let fix_abstract_inheritance com t = match t with | TClassDecl c when c.cl_interface -> c.cl_ordered_fields <- List.filter (fun f -> - let b = try (find_field c f) == f + let b = try (find_field com c f) == f with Not_found -> false in if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields; b; @@ -1828,8 +1396,7 @@ let rec is_volatile t = is_volatile (!f()) | TType (t,tl) -> (match t.t_path with - | ["mt";"flash"],"Volatile" -> true - | _ -> is_volatile (apply_params t.t_types tl t.t_type)) + | _ -> is_volatile (apply_params t.t_params tl t.t_type)) | _ -> false @@ -1840,10 +1407,9 @@ let set_default ctx a c p = mk (TIf (mk_parent (mk cond ctx.basic.tbool p), mk (TBinop (OpAssign,ve,mk (TConst c) t p)) t p,None)) ctx.basic.tvoid p let bytes_serialize data = - let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789%:" in + let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" in let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in - let str = Base64.str_encode ~tbl data in - "s" ^ string_of_int (String.length str) ^ ":" ^ str + Base64.str_encode ~tbl data (* Tells if the constructor might be called without any issue whatever its parameters @@ -1854,11 +1420,11 @@ let rec constructor_side_effects e = true | TField (_,FEnum _) -> false - | TUnop _ | TArray _ | TField _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TMatch _ | TReturn _ | TThrow _ -> + | TUnop _ | TArray _ | TField _ | TEnumParameter _ | TCall _ | TNew _ | TFor _ | TWhile _ | TSwitch _ | TReturn _ | TThrow _ -> true - | TBinop _ | TTry _ | TIf _ | TBlock _ | TVars _ + | TBinop _ | TTry _ | TIf _ | TBlock _ | TVar _ | TFunction _ | TArrayDecl _ | TObjectDecl _ - | TParenthesis _ | TTypeExpr _ | TLocal _ + | TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _ | TConst _ | TContinue | TBreak | TCast _ -> try Type.iter (fun e -> if constructor_side_effects e then raise Exit) e; @@ -1866,12 +1432,17 @@ let rec constructor_side_effects e = with Exit -> true +let make_valid_filename s = + let r = Str.regexp "[^A-Za-z0-9_\\-\\.,]" in + Str.global_substitute r (fun s -> "_") s + (* Make a dump of the full typed AST of all types *) let rec create_dumpfile acc = function | [] -> assert false | d :: [] -> + let d = make_valid_filename d in let ch = open_out (String.concat "/" (List.rev (d :: acc)) ^ ".dump") in let buf = Buffer.create 0 in buf, (fun () -> @@ -1885,7 +1456,11 @@ let rec create_dumpfile acc = function let dump_types com = let s_type = s_type (Type.print_context()) in let params = function [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in - let s_expr = try if Common.defined_value com Define.Dump = "pretty" then Type.s_expr_pretty "\t" else Type.s_expr with Not_found -> Type.s_expr in + let s_expr = match Common.defined_value_safe com Define.Dump with + | "pretty" -> Type.s_expr_pretty "\t" + | "legacy" -> Type.s_expr + | _ -> Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t" + in List.iter (fun mt -> let path = Type.t_path mt in let buf,close = create_dumpfile [] ("dump" :: (Common.platform_name com.platform) :: fst path @ [snd path]) in @@ -1898,10 +1473,10 @@ let dump_types com = (match f.cf_expr with | None -> () | Some e -> print "\n\n\t = %s" (s_expr s_type e)); - print ";\n\n"; + print "\n\n"; List.iter (fun f -> print_field stat f) f.cf_overloads in - print "%s%s%s %s%s" (if c.cl_private then "private " else "") (if c.cl_extern then "extern " else "") (if c.cl_interface then "interface" else "class") (s_type_path path) (params c.cl_types); + print "%s%s%s %s%s" (if c.cl_private then "private " else "") (if c.cl_extern then "extern " else "") (if c.cl_interface then "interface" else "class") (s_type_path path) (params c.cl_params); (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl)))); List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements; (match c.cl_dynamic with None -> () | Some t -> print " implements Dynamic<%s>" (s_type t)); @@ -1912,18 +1487,24 @@ let dump_types com = | Some f -> print_field false f); List.iter (print_field false) c.cl_ordered_fields; List.iter (print_field true) c.cl_ordered_statics; + (match c.cl_init with + | None -> () + | Some e -> + print "\n\n\t__init__ = "; + print "%s" (s_expr s_type e); + print "}\n"); print "}"; | Type.TEnumDecl e -> - print "%s%senum %s%s {\n" (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_types); + print "%s%senum %s%s {\n" (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_params); List.iter (fun n -> let f = PMap.find n e.e_constrs in print "\t%s : %s;\n" f.ef_name (s_type f.ef_type); ) e.e_names; print "}" | Type.TTypeDecl t -> - print "%stype %s%s = %s" (if t.t_private then "private " else "") (s_type_path path) (params t.t_types) (s_type t.t_type); + print "%stype %s%s = %s" (if t.t_private then "private " else "") (s_type_path path) (params t.t_params) (s_type t.t_type); | Type.TAbstractDecl a -> - print "%sabstract %s%s {}" (if a.a_private then "private " else "") (s_type_path path) (params a.a_types); + print "%sabstract %s%s {}" (if a.a_private then "private " else "") (s_type_path path) (params a.a_params); ); close(); ) com.types @@ -1964,7 +1545,7 @@ let default_cast ?(vtmp="$t") com e texpr t p = | TTypeDecl _ -> assert false in let vtmp = alloc_var vtmp e.etype in - let var = mk (TVars [vtmp,Some e]) api.tvoid p 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 @@ -1985,14 +1566,19 @@ let default_cast ?(vtmp="$t") com e texpr t p = module Overloads = struct let rec simplify_t t = match t with - | TInst _ | TEnum _ | TAbstract({ a_impl = None }, _) -> + | TAbstract(a,_) when Meta.has Meta.CoreType a.a_meta -> + t + | TInst _ | TEnum _ -> t | TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl) | TType(({ t_path = [],"Null" } as t), [t2]) -> (match simplify_t t2 with - | (TAbstract({ a_impl = None }, _) | TEnum _ as t2) -> TType(t, [simplify_t t2]) + | (TAbstract(a,_) as t2) when Meta.has Meta.CoreType a.a_meta -> + TType(t, [simplify_t t2]) + | (TEnum _ as t2) -> + TType(t, [simplify_t t2]) | t2 -> t2) | TType(t, tl) -> - simplify_t (apply_params t.t_types tl t.t_type) + simplify_t (apply_params t.t_params tl t.t_type) | TMono r -> (match !r with | Some t -> simplify_t t | None -> t_dynamic) @@ -2007,6 +1593,13 @@ struct List.iter2 (fun f a -> if not (type_iseq f a) then incr acc) tlfun tlarg; !acc + (** + The rate function returns an ( int * int ) type. + The smaller the int, the best rated the caller argument is in comparison with the callee. + + The first int refers to how many "conversions" would be necessary to convert from the callee to the caller type, and + the second refers to the type parameters. + **) let rec rate_conv cacc tfun targ = match simplify_t tfun, simplify_t targ with | TInst({ cl_interface = true } as cf, tlf), TInst(ca, tla) -> @@ -2018,13 +1611,13 @@ struct | [] -> (let acc, ca, tla = !cur in match ca.cl_super with | None -> raise Not_found | Some (sup,tls) -> - cur := (acc+1,sup,List.map (apply_params ca.cl_types tla) tls); + cur := (acc+1,sup,List.map (apply_params ca.cl_params tla) tls); stack := [!cur]; loop()) | (acc,ca,tla) :: _ when ca == cf -> acc,tla | (acc,ca,tla) :: s -> - stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_types tla) tl)) ca.cl_implements; + stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_params tla) tl)) ca.cl_implements; loop() in let acc, tla = loop() in @@ -2036,7 +1629,7 @@ struct else match ca.cl_super with | None -> raise Not_found | Some(sup,stl) -> - loop (acc+1) sup (List.map (apply_params ca.cl_types tla) stl) + loop (acc+1) sup (List.map (apply_params ca.cl_params tla) stl) in let acc, tla = loop 0 ca tla in (cacc + acc, rate_tp tlf tla) @@ -2047,7 +1640,7 @@ struct (cacc, 0) | TDynamic _, _ -> (max_int, 0) (* a function with dynamic will always be worst of all *) - | TAbstract({ a_impl = None }, _), TDynamic _ -> + | TAbstract(a, _), TDynamic _ when Meta.has Meta.CoreType a.a_meta -> (cacc + 2, 0) (* a dynamic to a basic type will have an "unboxing" penalty *) | _, TDynamic _ -> (cacc + 1, 0) @@ -2056,16 +1649,16 @@ struct (cacc, rate_tp tlf tla) else let ret = ref None in - if List.exists (fun (t,_) -> try - ret := Some (rate_conv (cacc+1) (apply_params af.a_types tlf t) targ); + if List.exists (fun t -> try + ret := Some (rate_conv (cacc+1) (apply_params af.a_params tlf t) targ); true with | Not_found -> false ) af.a_from then Option.get !ret else - if List.exists (fun (t,_) -> try - ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_types tla t)); + if List.exists (fun t -> try + ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_params tla t)); true with | Not_found -> false @@ -2093,13 +1686,14 @@ struct let rec rm_duplicates acc ret = match ret with | [] -> acc - | ( el, t ) :: ret when List.exists (fun (_,t2) -> type_iseq t t2) acc -> + | ( el, t, _ ) :: ret when List.exists (fun (_,t2,_) -> type_iseq t t2) acc -> rm_duplicates acc ret | r :: ret -> rm_duplicates (r :: acc) ret let s_options rated = - String.concat ",\n" (List.map (fun ((_,t),rate) -> + String.concat ",\n" (List.map (fun ((elist,t,_),rate) -> + "( " ^ (String.concat "," (List.map (fun(e,_) -> s_expr (s_type (print_context())) e) elist)) ^ " ) => " ^ "( " ^ (String.concat "," (List.map (fun (i,i2) -> string_of_int i ^ ":" ^ string_of_int i2) rate)) ^ " ) => " ^ (s_type (print_context()) t) ) rated) @@ -2109,7 +1703,7 @@ struct let rec fewer_optionals acc compatible = match acc, compatible with | _, [] -> acc | [], c :: comp -> fewer_optionals [c] comp - | (elist_acc, _) :: _, ((elist, _) as cur) :: comp -> + | (elist_acc, _, _) :: _, ((elist, _, _) as cur) :: comp -> let acc_opt = count_optionals elist_acc in let comp_opt = count_optionals elist in if acc_opt = comp_opt then @@ -2120,22 +1714,30 @@ struct fewer_optionals [cur] comp let reduce_compatible compatible = match fewer_optionals [] (rm_duplicates [] compatible) with - | [] -> [] | [v] -> [v] + | [] -> [] + | [v] -> [v] | compatible -> (* convert compatible into ( rate * compatible_type ) list *) let rec mk_rate acc elist args = match elist, args with | [], [] -> acc | (_,true) :: elist, _ :: args -> mk_rate acc elist args | (e,false) :: elist, (n,o,t) :: args -> - mk_rate (rate_conv 0 t e.etype :: acc) elist args + (* if the argument is an implicit cast, we need to start with a penalty *) + (* The penalty should be higher than any other implicit cast - other than Dynamic *) + (* since Dynamic has a penalty of max_int, we'll impose max_int - 1 to it *) + (match e.eexpr with + | TMeta( (Meta.ImplicitCast,_,_), _) -> + mk_rate ((max_int - 1, 0) :: acc) elist args + | _ -> + mk_rate (rate_conv 0 t e.etype :: acc) elist args) | _ -> assert false in let rated = ref [] in List.iter (function - | (elist,TFun(args,ret)) -> (try - rated := ( (elist,TFun(args,ret)), mk_rate [] elist args ) :: !rated - with | Not_found -> ()) + | (elist,TFun(args,ret),d) -> (try + rated := ( (elist,TFun(args,ret),d), mk_rate [] elist args ) :: !rated + with | Not_found -> ()) | _ -> assert false ) compatible; @@ -2151,5 +1753,206 @@ struct loop ( (rover,rargs) :: best ) rem in - List.map fst (loop [] !rated) + let r = loop [] !rated in + List.map fst r end;; + +module UnificationCallback = struct + let tf_stack = ref [] + + let check_call_params f el tl = + let rec loop acc el tl = match el,tl with + | e :: el, (n,_,t) :: tl -> + loop ((f e t) :: acc) el tl + | [], [] -> + acc + | [],_ -> + acc + | e :: el, [] -> + loop (e :: acc) el [] + in + List.rev (loop [] el tl) + + let check_call f el t = match follow t with + | TFun(args,_) -> + check_call_params f el args + | _ -> + List.map (fun e -> f e t_dynamic) el + + let rec run f e = + let f e t = + (* TODO: I don't think this should cause errors on Flash target *) + (* if not (type_iseq e.etype t) then f e t else e *) + f e t + in + let check e = match e.eexpr with + | TBinop((OpAssign | OpAssignOp _ as op),e1,e2) -> + let e2 = f e2 e1.etype in + {e with eexpr = TBinop(op,e1,e2)} + | TVar(v,Some ev) -> + let eo = Some (f ev v.v_type) in + { e with eexpr = TVar(v,eo) } + | TCall(e1,el) -> + let el = check_call f el e1.etype in + {e with eexpr = TCall(e1,el)} + | TNew(c,tl,el) -> + begin try + let tcf,_ = get_constructor (fun cf -> apply_params c.cl_params tl cf.cf_type) c in + let el = check_call f el tcf in + {e with eexpr = TNew(c,tl,el)} + with Not_found -> + e + end + | TArrayDecl el -> + begin match follow e.etype with + | TInst({cl_path=[],"Array"},[t]) -> {e with eexpr = TArrayDecl(List.map (fun e -> f e t) el)} + | _ -> e + end + | TObjectDecl fl -> + begin match follow e.etype with + | TAnon an -> + let fl = List.map (fun (n,e) -> + let e = try + let t = (PMap.find n an.a_fields).cf_type in + f e t + with Not_found -> + e + in + n,e + ) fl in + { e with eexpr = TObjectDecl fl } + | _ -> e + end + | TReturn (Some e1) -> + begin match !tf_stack with + | tf :: _ -> { e with eexpr = TReturn (Some (f e1 tf.tf_type))} + | _ -> e + end + | _ -> + e + in + match e.eexpr with + | TFunction tf -> + tf_stack := tf :: !tf_stack; + let etf = {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})} in + tf_stack := List.tl !tf_stack; + etf + | _ -> + check (Type.map_expr (run f) e) +end;; + +module DeprecationCheck = struct + + let curclass = ref null_class + + let warned_positions = Hashtbl.create 0 + + let print_deprecation_message com meta s p_usage = + let s = match meta with + | _,[EConst(String s),_],_ -> s + | _ -> Printf.sprintf "Usage of this %s is deprecated" s + in + if not (Hashtbl.mem warned_positions p_usage) then begin + Hashtbl.replace warned_positions p_usage true; + com.warning s p_usage; + end + + let check_meta com meta s p_usage = + try + print_deprecation_message com (Meta.get Meta.Deprecated meta) s p_usage; + with Not_found -> + () + + let check_cf com cf p = check_meta com cf.cf_meta "field" p + + let check_class com c p = if c != !curclass then check_meta com c.cl_meta "class" p + + let check_enum com en p = check_meta com en.e_meta "enum" p + + let check_ef com ef p = check_meta com ef.ef_meta "enum field" p + + let check_typedef com t p = check_meta com t.t_meta "typedef" p + + let check_module_type com mt p = match mt with + | TClassDecl c -> check_class com c p + | TEnumDecl en -> check_enum com en p + | _ -> () + + let run com = + let rec expr e = match e.eexpr with + | TField(e1,fa) -> + expr e1; + begin match fa with + | FStatic(c,cf) | FInstance(c,_,cf) -> + check_class com c e.epos; + check_cf com cf e.epos + | FAnon cf -> + check_cf com cf e.epos + | FClosure(co,cf) -> + (match co with None -> () | Some (c,_) -> check_class com c e.epos); + check_cf com cf e.epos + | FEnum(en,ef) -> + check_enum com en e.epos; + check_ef com ef e.epos; + | _ -> + () + end + | TNew(c,_,el) -> + List.iter expr el; + check_class com c e.epos; + (match c.cl_constructor with None -> () | Some cf -> check_cf com cf e.epos) + | TTypeExpr(mt) | TCast(_,Some mt) -> + check_module_type com mt e.epos + | TMeta((Meta.Deprecated,_,_) as meta,e1) -> + print_deprecation_message com meta "field" e1.epos; + expr e1; + | _ -> + Type.iter expr e + in + List.iter (fun t -> match t with + | TClassDecl c -> + curclass := c; + let field cf = match cf.cf_expr with None -> () | Some e -> expr e in + (match c.cl_constructor with None -> () | Some cf -> field cf); + (match c.cl_init with None -> () | Some e -> expr e); + List.iter field c.cl_ordered_statics; + List.iter field c.cl_ordered_fields; + | _ -> + () + ) com.types +end + +let interpolate_code com code tl f_string f_expr p = + let exprs = Array.of_list tl in + let i = ref 0 in + let err msg = + let pos = { p with pmin = p.pmin + !i } in + com.error msg pos + in + let regex = Str.regexp "[{}]" in + let rec loop m = match m with + | [] -> + () + | Str.Text txt :: tl -> + i := !i + String.length txt; + f_string txt; + loop tl + | Str.Delim a :: Str.Delim b :: tl when a = b -> + i := !i + 2; + f_string a; + loop tl + | Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl -> + (try + let expr = Array.get exprs (int_of_string n) in + f_expr expr; + i := !i + 2 + String.length n; + loop tl + with + | Failure "int_of_string" -> + err ("Index expected. Got " ^ n) + | Invalid_argument _ -> + err ("Out-of-bounds special parameter: " ^ n)) + | Str.Delim x :: _ -> + err ("Unexpected " ^ x) + in + loop (Str.full_split regex code) diff --git a/common.ml b/common.ml index 04452133aa4e5364d580e5fe9c821021e520fa67..b98dd2b1fdd9ee97c3409a9171feef0f750cce20 100644 --- a/common.ml +++ b/common.ml @@ -49,7 +49,6 @@ type stats = { type platform = | Cross - | Flash8 | Js | Neko | Flash @@ -57,6 +56,7 @@ type platform = | Cpp | Cs | Java + | Python (** The capture policy tells which handling we make of captured locals @@ -83,8 +83,6 @@ type platform_config = { pf_captured_scope : bool; (** generated locals must be absolutely unique wrt the current function *) pf_unique_locals : bool; - (** which expressions can be generated to initialize member variables (or will be moved into the constructor *) - pf_can_init_member : tclass_field -> bool; (** captured variables handling (see before) *) pf_capture_policy : capture_policy; (** when calling a method with optional args, do we replace the missing args with "null" constants *) @@ -93,14 +91,29 @@ type platform_config = { pf_add_final_return : bool; (** does the platform natively support overloaded functions *) pf_overload : bool; + (** does the platform generator handle pattern matching *) + pf_pattern_matching : bool; + (** can the platform use default values for non-nullable arguments *) + pf_can_skip_non_nullable_argument : bool; + (** type paths that are reserved on the platform *) + pf_reserved_type_paths : path list; } +type display_mode = + | DMNone + | DMDefault + | DMUsage + | DMPosition + | DMToplevel + | DMResolve of string + | DMType + type context = { (* config *) version : int; args : string list; mutable sys_args : string list; - mutable display : bool; + mutable display : display_mode; mutable debug : bool; mutable verbose : bool; mutable foptimize : bool; @@ -115,10 +128,13 @@ type context = { mutable warning : string -> pos -> unit; mutable load_extern_type : (path -> pos -> (string * Ast.package) option) list; (* allow finding types which are not in sources *) mutable filters : (unit -> unit) list; + mutable final_filters : (unit -> unit) list; mutable defines_signature : string option; mutable print : string -> unit; mutable get_macros : unit -> context option; mutable run_command : string -> int; + file_lookup_cache : (string,string option) Hashtbl.t; + mutable stored_typed_exprs : (int, texpr) PMap.t; (* output *) mutable file : string; mutable flash_version : float; @@ -132,72 +148,99 @@ type context = { mutable php_lib : string option; mutable php_prefix : string option; mutable swf_libs : (string * (unit -> Swf.swf) * (unit -> ((string list * string),As3hl.hl_class) Hashtbl.t)) list; - mutable java_libs : (string * bool * (unit -> unit) * (unit -> ((string list * string) list)) * ((string list * string) -> ((JData.jclass * string * string) option))) list; + mutable java_libs : (string * bool * (unit -> unit) * (unit -> (path list)) * (path -> ((JData.jclass * string * string) option))) list; (* (path,std,close,all_files,lookup) *) + mutable net_libs : (string * bool * (unit -> path list) * (path -> IlData.ilclass option)) list; (* (path,std,all_files,lookup) *) + mutable net_std : string list; + net_path_map : (path,string list * string list * string) Hashtbl.t; + mutable c_args : string list; mutable js_gen : (unit -> unit) option; (* typing *) mutable basic : basic_types; + memory_marker : float array; } exception Abort of string * Ast.pos -let display_default = ref false +let display_default = ref DMNone module Define = struct type strict_defined = | AbsolutePath | AdvancedTelemetry + | Analyzer | As3 | CheckXmlProxy | CoreApi + | CoreApiSerialize + | Cppia | Dce | DceDebug | Debug | Display - | DisplayMode | DllExport | DllImport | DocGen | Dump | DumpDependencies + | DumpIgnoreVarIds + | EraseGenerics | Fdb + | FileExtension | FlashStrict | FlashUseStage + | ForceLibCheck + | ForceNativeProperty | FormatWarning | GencommonDebug | HaxeBoot | HaxeVer + | HxcppApiLevel + | IncludePrefix | Interp | JavaVer | JsClassic + | JsEs5 + | JsUnflatten + | KeepOldOutput + | LoopUnrollMaxCost | Macro | MacroTimes | NekoSource | NekoV1 | NetworkSandbox + | NetVer + | NetTarget | NoCompilation | NoCOpt + | NoDeprecationWarnings + | NoFlashOverride + | NoDebug | NoInline | NoOpt | NoPatternMatching | NoRoot + | NoSimplify | NoSwfCompress | NoTraces | PhpPrefix | RealPosition | ReplaceFiles | Scriptable + | ShallowExpose + | SourceMapContent | Swc | SwfCompressLevel | SwfDebugPassword | SwfDirectBlit | SwfGpu - | SwfMark | SwfMetadata | SwfPreloaderFrame | SwfProtected | SwfScriptTimeout + | SwfUseDoAbc | Sys + | Unsafe | UseNekoc | UseRttiDoc | Vcproj @@ -205,60 +248,83 @@ module Define = struct | Last (* must be last *) let infos = function - | AbsolutePath -> ("absolute_path","Print absoluate file path in trace output") + | AbsolutePath -> ("absolute_path","Print absolute file path in trace output") | AdvancedTelemetry -> ("advanced-telemetry","Allow the SWF to be measured with Monocle tool") + | Analyzer -> ("analyzer","Use static analyzer for optimization (experimental)") | As3 -> ("as3","Defined when outputing flash9 as3 source code") | CheckXmlProxy -> ("check_xml_proxy","Check the used fields of the xml proxy") | CoreApi -> ("core_api","Defined in the core api context") + | CoreApiSerialize -> ("core_api_serialize","Sets so some generated core api classes be marked with the Serializable attribute on C#") + | Cppia -> ("cppia", "Generate experimental cpp instruction assembly") | Dce -> ("dce","The current DCE mode") | DceDebug -> ("dce_debug","Show DCE log") | Debug -> ("debug","Activated when compiling with -debug") | Display -> ("display","Activated during completion") - | DisplayMode -> ("display_mode", "The display mode to use (default, position, metadata, usage)") | DllExport -> ("dll_export", "GenCPP experimental linking") | DllImport -> ("dll_import", "GenCPP experimental linking") | DocGen -> ("doc_gen","Do not perform any removal/change in order to correctly generate documentation") | Dump -> ("dump","Dump the complete typed AST for internal debugging") | DumpDependencies -> ("dump_dependencies","Dump the classes dependencies") + | DumpIgnoreVarIds -> ("dump_ignore_var_ids","Dump files do not contain variable IDs (helps with diff)") + | EraseGenerics -> ("erase_generics","Erase generic classes on C#") | Fdb -> ("fdb","Enable full flash debug infos for FDB interactive debugging") + | FileExtension -> ("file_extension","Output filename extension for cpp source code") | FlashStrict -> ("flash_strict","More strict typing for flash target") | FlashUseStage -> ("flash_use_stage","Keep the SWF library initial stage") + (* force_lib_check is only here as a debug facility - compiler checking allows errors to be found more easily *) + | ForceLibCheck -> ("force_lib_check","Force the compiler to check -net-lib and -java-lib added classes (internal)") + | ForceNativeProperty -> ("force_native_property","Tag all properties with :nativeProperty metadata for 3.1 compatibility") | FormatWarning -> ("format_warning","Print a warning for each formated string, for 2.x compatibility") | GencommonDebug -> ("gencommon_debug","GenCommon internal") | HaxeBoot -> ("haxe_boot","Given the name 'haxe' to the flash boot class instead of a generated name") | HaxeVer -> ("haxe_ver","The current Haxe version value") + | HxcppApiLevel -> ("hxcpp_api_level","Provided to allow compatibility between hxcpp versions") + | IncludePrefix -> ("include_prefix","prepend path to generated include files") | Interp -> ("interp","The code is compiled to be run with --interp") | JavaVer -> ("java_ver", " Sets the Java version to be targeted") | JsClassic -> ("js_classic","Don't use a function wrapper and strict mode in JS output") + | JsEs5 -> ("js_es5","Generate JS for ES5-compliant runtimes") + | JsUnflatten -> ("js_unflatten","Generate nested objects for packages and types") + | KeepOldOutput -> ("keep_old_output","Keep old source files in the output directory (for C#/Java)") + | LoopUnrollMaxCost -> ("loop_unroll_max_cost","Maximum cost (number of expressions * iterations) before loop unrolling is canceled (default 250)") | Macro -> ("macro","Defined when we compile code in the macro context") | MacroTimes -> ("macro_times","Display per-macro timing when used with --times") + | NetVer -> ("net_ver", " Sets the .NET version to be targeted") + | NetTarget -> ("net_target", " Sets the .NET target. Defaults to \"net\". xbox, micro (Micro Framework), compact (Compact Framework) are some valid values") | NekoSource -> ("neko_source","Output neko source instead of bytecode") | NekoV1 -> ("neko_v1","Keep Neko 1.x compatibility") | NetworkSandbox -> ("network-sandbox","Use local network sandbox instead of local file access one") - | NoCompilation -> ("no-compilation","Disable CPP final compilation") + | NoCompilation -> ("no-compilation","Disable final compilation for Cs, Cpp and Java") | NoCOpt -> ("no_copt","Disable completion optimization (for debug purposes)") + | NoDebug -> ("no_debug","Remove all debug macros from cpp output") + | NoDeprecationWarnings -> ("no-deprecation-warnings","Do not warn if fields annotated with @:deprecated are used") + | NoFlashOverride -> ("no-flash-override", "Change overrides on some basic classes into HX suffixed methods, flash only") | NoOpt -> ("no_opt","Disable optimizations") | NoPatternMatching -> ("no_pattern_matching","Disable pattern matching") | NoInline -> ("no_inline","Disable inlining") - | NoRoot -> ("no_root","GenCS internal") + | NoRoot -> ("no_root","Generate top-level types into haxe.root namespace") | NoMacroCache -> ("no_macro_cache","Disable macro context caching") + | NoSimplify -> "no_simplify",("Disable simplification filter") | NoSwfCompress -> ("no_swf_compress","Disable SWF output compression") | NoTraces -> ("no_traces","Disable all trace calls") | PhpPrefix -> ("php_prefix","Compiled with --php-prefix") | RealPosition -> ("real_position","Disables haxe source mapping when targetting C#") | ReplaceFiles -> ("replace_files","GenCommon internal") | Scriptable -> ("scriptable","GenCPP internal") + | ShallowExpose -> ("shallow-expose","Expose types to surrounding scope of Haxe generated closure without writing to window object") + | SourceMapContent -> ("source-map-content","Include the hx sources as part of the JS source map") | Swc -> ("swc","Output a SWC instead of a SWF") | SwfCompressLevel -> ("swf_compress_level"," Set the amount of compression for the SWF output") - | SwfDebugPassword -> ("swf_debug_password", "Set a password for debugging.") + | SwfDebugPassword -> ("swf_debug_password", "Set a password for debugging") | SwfDirectBlit -> ("swf_direct_blit", "Use hardware acceleration to blit graphics") | SwfGpu -> ("swf_gpu", "Use GPU compositing features when drawing graphics") - | SwfMark -> ("swf_mark","GenSWF8 internal") - | SwfMetadata -> ("swf_metadata", "= Include contents of as metadata in the swf.") + | SwfMetadata -> ("swf_metadata", "= Include contents of as metadata in the swf") | SwfPreloaderFrame -> ("swf_preloader_frame", "Insert empty first frame in swf") | SwfProtected -> ("swf_protected","Compile Haxe private as protected in the SWF instead of public") | SwfScriptTimeout -> ("swf_script_timeout", "Maximum ActionScript processing time before script stuck dialog box displays (in seconds)") + | SwfUseDoAbc -> ("swf_use_doabc", "Use DoAbc swf-tag instead of DoAbcDefine") | Sys -> ("sys","Defined for all system platforms") + | Unsafe -> ("unsafe","Allow unsafe code when targeting C#") | UseNekoc -> ("use_nekoc","Use nekoc compiler instead of internal one") | UseRttiDoc -> ("use_rtti_doc","Allows access to documentation during compilation") | Vcproj -> ("vcproj","GenCPP internal") @@ -275,6 +341,7 @@ module MetaInfo = struct | TEnum | TTypedef | TAnyField + | TExpr type meta_parameter = | HasParam of string @@ -285,71 +352,101 @@ module MetaInfo = struct | Internal let to_string = function + | Abi -> ":abi",("Function ABI/calling convention",[Platforms [Cpp]]) | Abstract -> ":abstract",("Sets the underlying class implementation as 'abstract'",[Platforms [Java;Cs]]) | Access -> ":access",("Forces private access to package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]]) + | Accessor -> ":accessor",("Used internally by DCE to mark property accessors",[UsedOn TClassField;Internal]) | Allow -> ":allow",("Allows private access from package, type or field",[HasParam "Target path";UsedOnEither [TClass;TClassField]]) + | Analyzer -> ":analyzer",("Used to configure the static analyzer",[]) | Annotation -> ":annotation",("Annotation (@interface) definitions on -java-lib imports will be annotated with this metadata. Has no effect on types compiled by Haxe",[Platform Java; UsedOn TClass]) | ArrayAccess -> ":arrayAccess",("Allows [] access on an abstract",[UsedOnEither [TAbstract;TAbstractField]]) + | Ast -> ":ast",("Internally used to pass the AST source into the typed AST",[Internal]) | AutoBuild -> ":autoBuild",("Extends @:build metadata to all extending and implementing classes",[HasParam "Build macro call";UsedOn TClass]) | Bind -> ":bind",("Override Swf class declaration",[Platform Flash;UsedOn TClass]) | Bitmap -> ":bitmap",("Embeds given bitmap data into the class (must extend flash.display.BitmapData)",[HasParam "Bitmap file path";UsedOn TClass;Platform Flash]) + | BridgeProperties -> ":bridgeProperties",("Creates native property bridges for all Haxe properties in this class",[UsedOn TClass;Platform Cs]) | Build -> ":build",("Builds a class or enum from a macro",[HasParam "Build macro call";UsedOnEither [TClass;TEnum]]) - | BuildXml -> ":buildXml",("",[Platform Cpp]) + | BuildXml -> ":buildXml",("Specify xml data to be injected into Build.xml",[Platform Cpp]) + | Callable -> ":callable",("Abstract forwards call to its underlying type",[UsedOn TAbstract]) | Class -> ":class",("Used internally to annotate an enum that will be generated as a class",[Platforms [Java;Cs]; UsedOn TEnum; Internal]) | ClassCode -> ":classCode",("Used to inject platform-native code into a class",[Platforms [Java;Cs]; UsedOn TClass]) | Commutative -> ":commutative",("Declares an abstract operator as commutative",[UsedOn TAbstractField]) | CompilerGenerated -> ":compilerGenerated",("Marks a field as generated by the compiler. Shouldn't be used by the end user",[Platforms [Java;Cs]]) | CoreApi -> ":coreApi",("Identifies this class as a core api class (forces Api check)",[UsedOnEither [TClass;TEnum;TTypedef;TAbstract]]) | CoreType -> ":coreType",("Identifies an abstract as core type so that it requires no implementation",[UsedOn TAbstract]) - | CppFileCode -> ":cppFileCode",("",[Platform Cpp]) + | CppFileCode -> ":cppFileCode",("Code to be injected into generated cpp file",[Platform Cpp]) + | CppInclude -> ":cppInclude",("File to be included in generated cpp file",[Platform Cpp]) | CppNamespaceCode -> ":cppNamespaceCode",("",[Platform Cpp]) + | CsNative -> ":csNative",("Automatically added by -net-lib on classes generated from .NET DLL files",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal]) + | Dce -> ":dce",("Forces dead code elimination even when -dce full is not specified",[UsedOnEither [TClass;TEnum]]) | Debug -> ":debug",("Forces debug information to be generated into the Swf even without -debug",[UsedOnEither [TClass;TClassField]; Platform Flash]) | Decl -> ":decl",("",[Platform Cpp]) | DefParam -> ":defParam",("?",[]) + | Delegate -> ":delegate",("Automatically added by -net-lib on delegates",[Platform Cs; UsedOn TAbstract]) | Depend -> ":depend",("",[Platform Cpp]) - | Deprecated -> ":deprecated",("Automatically added by -java-lib on class fields annotated with @Deprecated annotation. Has no effect on types compiled by Haxe.",[Platform Java; UsedOnEither [TClass;TEnum;TClassField]]) + | Deprecated -> ":deprecated",("Automatically added by -java-lib on class fields annotated with @Deprecated annotation. Has no effect on types compiled by Haxe",[Platform Java; UsedOnEither [TClass;TEnum;TClassField]]) + | DirectlyUsed -> ":directlyUsed",("Marks types that are directly referenced by non-extern code",[Internal]) | DynamicObject -> ":dynamicObject",("Used internally to identify the Dynamic Object implementation",[Platforms [Java;Cs]; UsedOn TClass; Internal]) | Enum -> ":enum",("Used internally to annotate a class that was generated from an enum",[Platforms [Java;Cs]; UsedOn TClass; Internal]) | EnumConstructorParam -> ":enumConstructorParam",("Used internally to annotate GADT type parameters",[UsedOn TClass; Internal]) + | Event -> ":event",("Automatically added by -net-lib on events. Has no effect on types compiled by Haxe",[Platform Cs; UsedOn TClassField]) + | Exhaustive -> ":exhaustive",("",[Internal]) | Expose -> ":expose",("Makes the class available on the window object",[HasParam "?Name=Class path";UsedOn TClass;Platform Js]) | Extern -> ":extern",("Marks the field as extern so it is not generated",[UsedOn TClassField]) | FakeEnum -> ":fakeEnum",("Treat enum as collection of values of the specified type",[HasParam "Type name";UsedOn TEnum]) | File -> ":file",("Includes a given binary file into the target Swf and associates it with the class (must extend flash.utils.ByteArray)",[HasParam "File path";UsedOn TClass;Platform Flash]) | Final -> ":final",("Prevents a class from being extended",[UsedOn TClass]) + | FlatEnum -> ":flatEnum",("Internally used to mark an enum as being flat, i.e. having no function constructors",[UsedOn TEnum; Internal]) | Font -> ":font",("Embeds the given TrueType font into the class (must extend flash.text.Font)",[HasParam "TTF path";HasParam "Range String";UsedOn TClass]) + | Forward -> ":forward",("Forwards field access to underlying type",[HasParam "List of field names";UsedOn TAbstract]) | From -> ":from",("Specifies that the field of the abstract is a cast operation from the type identified in the function",[UsedOn TAbstractField]) | FunctionCode -> ":functionCode",("",[Platform Cpp]) | FunctionTailCode -> ":functionTailCode",("",[Platform Cpp]) | Generic -> ":generic",("Marks a class or class field as generic so each type parameter combination generates its own type/field",[UsedOnEither [TClass;TClassField]]) + | GenericBuild -> ":genericBuild",("Builds instances of a type using the specified macro",[UsedOn TClass]) + | GenericInstance -> ":genericInstance",("Internally used to mark instances of @:generic methods",[UsedOn TClassField;Internal]) | Getter -> ":getter",("Generates a native getter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash]) | Hack -> ":hack",("Allows extending classes marked as @:final",[UsedOn TClass]) + | HasUntyped -> (":has_untyped",("Used by the typer to mark fields that have untyped expressions",[Internal])) | HaxeGeneric -> ":haxeGeneric",("Used internally to annotate non-native generic classes",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal]) - | HeaderClassCode -> ":headerClassCode",("",[Platform Cpp]) - | HeaderCode -> ":headerCode",("",[Platform Cpp]) + | HeaderClassCode -> ":headerClassCode",("Code to be injected into the generated class, in the header",[Platform Cpp]) + | HeaderCode -> ":headerCode",("Code to be injected into the generated header file",[Platform Cpp]) + | HeaderInclude -> ":headerInclude",("File to be included in generated header file",[Platform Cpp]) | HeaderNamespaceCode -> ":headerNamespaceCode",("",[Platform Cpp]) | HxGen -> ":hxGen",("Annotates that an extern class was generated by Haxe",[Platforms [Java;Cs]; UsedOnEither [TClass;TEnum]]) | IfFeature -> ":ifFeature",("Causes a field to be kept by DCE if the given feature is part of the compilation",[HasParam "Feature name";UsedOn TClassField]) | Impl -> ":impl",("Used internally to mark abstract implementation fields",[UsedOn TAbstractField; Internal]) + | PythonImport -> ":pythonImport",("Generates python import statement for extern classes",[Platforms [Python]; UsedOn TClass]) + | ImplicitCast -> ":implicitCast",("Generated automatically on the AST when an implicit abstract cast happens",[Internal; UsedOn TExpr]) | Include -> ":include",("",[Platform Cpp]) | InitPackage -> ":initPackage",("?",[]) | Meta.Internal -> ":internal",("Generates the annotated field/class with 'internal' access",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum;TClassField]]) | IsVar -> ":isVar",("Forces a physical field to be generated for properties that otherwise would not require one",[UsedOn TClassField]) + | JavaCanonical -> ":javaCanonical",("Used by the Java target to annotate the canonical path of the type",[HasParam "Output type package";HasParam "Output type name";UsedOnEither [TClass;TEnum]; Platform Java]) | JavaNative -> ":javaNative",("Automatically added by -java-lib on classes generated from JAR/class files",[Platform Java; UsedOnEither[TClass;TEnum]; Internal]) + | JsRequire -> ":jsRequire",("Generate javascript module require expression for given extern",[Platform Js; UsedOn TClass]) | Keep -> ":keep",("Causes a field or type to be kept by DCE",[]) | KeepInit -> ":keepInit",("Causes a class to be kept by DCE even if all its field are removed",[UsedOn TClass]) | KeepSub -> ":keepSub",("Extends @:keep metadata to all implementing and extending classes",[UsedOn TClass]) + | LibType -> ":libType",("Used by -net-lib and -java-lib to mark a class that shouldn't be checked (overrides, interfaces, etc) by the type loader",[Internal; UsedOn TClass; Platforms [Java;Cs]]) | Meta -> ":meta",("Internally used to mark a class field as being the metadata field",[]) | Macro -> ":macro",("(deprecated)",[]) | MaybeUsed -> ":maybeUsed",("Internally used by DCE to mark fields that might be kept",[Internal]) - | MultiType -> ":multiType",("Specifies that an abstract chooses its this-type from its @:to functions",[UsedOn TAbstract]) + | MergeBlock -> ":mergeBlock",("Merge the annotated block into the current scope",[UsedOn TExpr]) + | MultiType -> ":multiType",("Specifies that an abstract chooses its this-type from its @:to functions",[UsedOn TAbstract; HasParam "Relevant type parameters"]) | Native -> ":native",("Rewrites the path of a class or enum during generation",[HasParam "Output type path";UsedOnEither [TClass;TEnum]]) - | NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]]) + | NativeChildren -> ":nativeChildren",("Annotates that all children from a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs]; UsedOn TClass]) + | NativeGen -> ":nativeGen",("Annotates that a type should be treated as if it were an extern definition - platform native",[Platforms [Java;Cs;Python]; UsedOnEither[TClass;TEnum]]) | NativeGeneric -> ":nativeGeneric",("Used internally to annotate native generic classes",[Platform Cs; UsedOnEither[TClass;TEnum]; Internal]) + | NativeProperty -> ":nativeProperty",("Use native properties which will execute even with dynamic usage",[Platform Cpp]) | NoCompletion -> ":noCompletion",("Prevents the compiler from suggesting completion on this field",[UsedOn TClassField]) | NoDebug -> ":noDebug",("Does not generate debug information into the Swf even if -debug is set",[UsedOnEither [TClass;TClassField];Platform Flash]) | NoDoc -> ":noDoc",("Prevents a type from being included in documentation generation",[]) + | NoExpr -> ":noExpr",("Internally used to mark abstract fields which have no expression by design",[Internal]) | NoImportGlobal -> ":noImportGlobal",("Prevents a static field from being imported with import Class.*",[UsedOn TAnyField]) - | NoPackageRestrict -> ":noPackageRestrict",("?",[]) + | NonVirtual -> ":nonVirtual",("Declares function to be non-virtual in cpp",[Platform Cpp]) + | NoPackageRestrict -> ":noPackageRestrict",("Allows a module to be accessed across all targets if found on its first type",[Internal]) + | NoPrivateAccess -> ":noPrivateAccess",("Disallow private access to anything for the annotated expression",[UsedOn TExpr]) | NoStack -> ":noStack",("",[Platform Cpp]) | NotNull -> ":notNull",("Declares an abstract type as not accepting null values",[UsedOn TAbstract]) | NoUsing -> ":noUsing",("Prevents a field from being used with 'using'",[UsedOn TClassField]) @@ -359,33 +456,46 @@ module MetaInfo = struct | Overload -> ":overload",("Allows the field to be called with different argument types",[HasParam "Function specification (no expression)";UsedOn TClassField]) | Public -> ":public",("Marks a class field as being public",[UsedOn TClassField]) | PublicFields -> ":publicFields",("Forces all class fields of inheriting classes to be public",[UsedOn TClass]) - | PrivateAccess -> ":privateAccess",("Internally used by the typer to allow context-sensitive private access",[Internal]) + | QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[Internal]) + | PrivateAccess -> ":privateAccess",("Allow private access to anything for the annotated expression",[UsedOn TExpr]) | Protected -> ":protected",("Marks a class field as being protected",[UsedOn TClassField]) + | Property -> ":property",("Marks a property field to be compiled as a native C# property",[UsedOn TClassField;Platform Cs]) | ReadOnly -> ":readOnly",("Generates a field with the 'readonly' native keyword",[Platform Cs; UsedOn TClassField]) | RealPath -> ":realPath",("Internally used on @:native types to retain original path information",[Internal]) | Remove -> ":remove",("Causes an interface to be removed from all implementing classes before generation",[UsedOn TClass]) | Require -> ":require",("Allows access to a field only if the specified compiler flag is set",[HasParam "Compiler flag to check";UsedOn TClassField]) + | RequiresAssign -> ":requiresAssign",("Used internally to mark certain abstract operator overloads",[Internal]) + (* | Resolve -> ":resolve",("Abstract fields marked with this metadata can be used to resolve unknown fields",[UsedOn TClassField]) *) | ReplaceReflection -> ":replaceReflection",("Used internally to specify a function that should replace its internal __hx_functionName counterpart",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]; Internal]) | Rtti -> ":rtti",("Adds runtime type informations",[UsedOn TClass]) | Runtime -> ":runtime",("?",[]) | RuntimeValue -> ":runtimeValue",("Marks an abstract as being a runtime value",[UsedOn TAbstract]) - | Setter -> ":setter",("Generates a native getter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash]) + | SelfCall -> ":selfCall",("Translates method calls into calling object directly",[UsedOn TClassField; Platform Js]) + | Setter -> ":setter",("Generates a native setter function on the given field",[HasParam "Class field name";UsedOn TClassField;Platform Flash]) + | StoredTypedExpr -> ":storedTypedExpr",("Used internally to reference a typed expression returned from a macro",[Internal]) | SkipCtor -> ":skipCtor",("Used internally to generate a constructor as if it were a native type (no __hx_ctor)",[Platforms [Java;Cs]; Internal]) | SkipReflection -> ":skipReflection",("Used internally to annotate a field that shouldn't have its reflection data generated",[Platforms [Java;Cs]; UsedOn TClassField; Internal]) | Sound -> ":sound",( "Includes a given .wav or .mp3 file into the target Swf and associates it with the class (must extend flash.media.Sound)",[HasParam "File path";UsedOn TClass;Platform Flash]) - | Struct -> ":struct",("Marks a class definition as a struct.",[Platform Cs; UsedOn TClass]) + | SourceFile -> ":sourceFile",("Source code filename for external class",[Platform Cpp]) + | Strict -> ":strict",("Used to declare a native C# attribute or a native Java metadata. Is type checked",[Platforms [Java;Cs]]) + | Struct -> ":struct",("Marks a class definition as a struct",[Platform Cs; UsedOn TClass]) + | StructAccess -> ":structAccess",("Marks an extern class as using struct access('.') not pointer('->')",[Platform Cpp; UsedOn TClass]) | SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass]) - | Throws -> ":throws",("Adds a 'throws' declaration to the generated function.",[HasParam "Type as String"; Platform Java; UsedOn TClassField]) + | Throws -> ":throws",("Adds a 'throws' declaration to the generated function",[HasParam "Type as String"; Platform Java; UsedOn TClassField]) + | This -> ":this",("Internally used to pass a 'this' expression to macros",[Internal; UsedOn TExpr]) | To -> ":to",("Specifies that the field of the abstract is a cast operation to the type identified in the function",[UsedOn TAbstractField]) | ToString -> ":toString",("Internally used",[Internal]) | Transient -> ":transient",("Adds the 'transient' flag to the class field",[Platform Java; UsedOn TClassField]) | ValueUsed -> ":valueUsed",("Internally used by DCE to mark an abstract value as used",[Internal]) | Volatile -> ":volatile",("",[Platforms [Java;Cs]]) + | Unbound -> ":unbound", ("Compiler internal to denote unbounded global variable",[]) | UnifyMinDynamic -> ":unifyMinDynamic",("Allows a collection of types to unify to Dynamic",[UsedOn TClassField]) | Unreflective -> ":unreflective",("",[Platform Cpp]) | Unsafe -> ":unsafe",("Declares a class, or a method with the C#'s 'unsafe' flag",[Platform Cs; UsedOnEither [TClass;TClassField]]) | Usage -> ":usage",("?",[]) | Used -> ":used",("Internally used by DCE to mark a class or field as used",[Internal]) + | Value -> ":value",("Used to store default values for fields and function arguments",[UsedOn TClassField]) + | Void -> ":void",("Use Cpp native 'void' return type",[Platform Cpp]) | Last -> assert false (* do not put any custom metadata after Last *) | Dollar s -> "$" ^ s,("",[]) @@ -427,11 +537,13 @@ let default_config = pf_locals_scope = true; pf_captured_scope = true; pf_unique_locals = false; - pf_can_init_member = (fun _ -> true); pf_capture_policy = CPNone; pf_pad_nulls = false; pf_add_final_return = false; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } let get_config com = @@ -439,19 +551,6 @@ let get_config com = match com.platform with | Cross -> default_config - | Flash8 -> - { - pf_static = false; - pf_sys = false; - pf_locals_scope = com.flash_version > 6.; - pf_captured_scope = false; - pf_unique_locals = false; - pf_can_init_member = (fun _ -> true); - pf_capture_policy = CPLoopVars; - pf_pad_nulls = false; - pf_add_final_return = false; - pf_overload = false; - } | Js -> { pf_static = false; @@ -459,11 +558,13 @@ let get_config com = pf_locals_scope = false; pf_captured_scope = false; pf_unique_locals = false; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPLoopVars; pf_pad_nulls = false; pf_add_final_return = false; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = [([],"Object");([],"Error")]; } | Neko -> { @@ -472,11 +573,13 @@ let get_config com = pf_locals_scope = true; pf_captured_scope = true; pf_unique_locals = false; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPNone; pf_pad_nulls = true; pf_add_final_return = false; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } | Flash when defined Define.As3 -> { @@ -485,11 +588,13 @@ let get_config com = pf_locals_scope = false; pf_captured_scope = true; pf_unique_locals = true; - pf_can_init_member = (fun _ -> true); pf_capture_policy = CPLoopVars; pf_pad_nulls = false; pf_add_final_return = true; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = false; + pf_reserved_type_paths = []; } | Flash -> { @@ -498,11 +603,13 @@ let get_config com = pf_locals_scope = true; pf_captured_scope = true; (* handled by genSwf9 *) pf_unique_locals = false; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPLoopVars; pf_pad_nulls = false; pf_add_final_return = false; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = false; + pf_reserved_type_paths = [([],"Object");([],"Error")]; } | Php -> { @@ -511,16 +618,13 @@ let get_config com = pf_locals_scope = false; (* some duplicate work is done in genPhp *) pf_captured_scope = false; pf_unique_locals = false; - pf_can_init_member = (fun cf -> - match cf.cf_kind, cf.cf_expr with - | Var { v_write = AccCall }, _ -> false - | _, Some { eexpr = TTypeExpr _ } -> false - | _ -> true - ); pf_capture_policy = CPNone; pf_pad_nulls = true; pf_add_final_return = false; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } | Cpp -> { @@ -529,11 +633,13 @@ let get_config com = pf_locals_scope = true; pf_captured_scope = true; pf_unique_locals = false; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPWrapRef; pf_pad_nulls = true; pf_add_final_return = true; pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } | Cs -> { @@ -542,11 +648,13 @@ let get_config com = pf_locals_scope = false; pf_captured_scope = true; pf_unique_locals = true; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPWrapRef; pf_pad_nulls = true; pf_add_final_return = false; pf_overload = true; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } | Java -> { @@ -555,12 +663,31 @@ let get_config com = pf_locals_scope = false; pf_captured_scope = true; pf_unique_locals = false; - pf_can_init_member = (fun _ -> false); pf_capture_policy = CPWrapRef; pf_pad_nulls = true; pf_add_final_return = false; pf_overload = true; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; } + | Python -> + { + pf_static = false; + pf_sys = true; + pf_locals_scope = false; + pf_captured_scope = false; + pf_unique_locals = false; + pf_capture_policy = CPLoopVars; + pf_pad_nulls = false; + pf_add_final_return = false; + pf_overload = false; + pf_pattern_matching = false; + pf_can_skip_non_nullable_argument = true; + pf_reserved_type_paths = []; + } + +let memory_marker = [|Unix.time()|] let create v args = let m = Type.mk_mono() in @@ -580,11 +707,12 @@ let create v args = std_path = []; class_path = []; main_class = None; - defines = PMap.add "true" "1" (if !display_default then PMap.add "display" "1" PMap.empty else PMap.empty); + defines = PMap.add "true" "1" (if !display_default <> DMNone then PMap.add "display" "1" PMap.empty else PMap.empty); package_rules = PMap.empty; file = ""; types = []; filters = []; + final_filters = []; modules = []; main = None; flash_version = 10.; @@ -593,6 +721,10 @@ let create v args = php_lib = None; swf_libs = []; java_libs = []; + net_libs = []; + net_std = []; + net_path_map = Hashtbl.create 0; + c_args = []; neko_libs = []; php_prefix = None; js_gen = None; @@ -610,6 +742,9 @@ let create v args = tstring = m; tarray = (fun _ -> assert false); }; + file_lookup_cache = Hashtbl.create 0; + stored_typed_exprs = PMap.empty; + memory_marker = memory_marker; } let log com str = @@ -617,7 +752,12 @@ let log com str = let clone com = let t = com.basic in - { com with basic = { t with tvoid = t.tvoid }; main_class = None; features = Hashtbl.create 0; } + { com with + basic = { t with tvoid = t.tvoid }; + main_class = None; + features = Hashtbl.create 0; + file_lookup_cache = Hashtbl.create 0; + } let file_time file = try (Unix.stat file).Unix.st_mtime with _ -> 0. @@ -642,7 +782,6 @@ let file_extension file = | [] -> "" let platforms = [ - Flash8; Js; Neko; Flash; @@ -650,11 +789,11 @@ let platforms = [ Cpp; Cs; Java; + Python; ] let platform_name = function | Cross -> "cross" - | Flash8 -> "flash8" | Js -> "js" | Neko -> "neko" | Flash -> "flash" @@ -662,12 +801,39 @@ let platform_name = function | Cpp -> "cpp" | Cs -> "cs" | Java -> "java" + | Python -> "python" let flash_versions = List.map (fun v -> let maj = int_of_float v in let min = int_of_float (mod_float (v *. 10.) 10.) in v, string_of_int maj ^ (if min = 0 then "" else "_" ^ string_of_int min) -) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8] +) [9.;10.;10.1;10.2;10.3;11.;11.1;11.2;11.3;11.4;11.5;11.6;11.7;11.8;11.9;12.0;13.0;14.0;15.0;16.0;17.0] + +let flash_version_tag = function + | 6. -> 6 + | 7. -> 7 + | 8. -> 8 + | 9. -> 9 + | 10. | 10.1 -> 10 + | 10.2 -> 11 + | 10.3 -> 12 + | 11. -> 13 + | 11.1 -> 14 + | 11.2 -> 15 + | 11.3 -> 16 + | 11.4 -> 17 + | 11.5 -> 18 + | 11.6 -> 19 + | 11.7 -> 20 + | 11.8 -> 21 + | 11.9 -> 22 + | 12.0 -> 23 + | 13.0 -> 24 + | 14.0 -> 25 + | 15.0 -> 26 + | 16.0 -> 27 + | 17.0 -> 28 + | v -> failwith ("Invalid SWF version " ^ string_of_float v) let raw_defined ctx v = PMap.mem v ctx.defines @@ -714,6 +880,17 @@ let add_feature com f = let has_dce com = (try defined_value com Define.Dce <> "no" with Not_found -> false) +(* + TODO: The has_dce check is there because we mark types with @:directlyUsed in the DCE filter, + which is not run in dce=no and thus we can't know if a type is used directly or not, + so we just assume that they are. + + If we had dce filter always running (even with dce=no), we would have types marked with @:directlyUsed + and we wouldn't need to generate unnecessary imports in dce=no, but that's good enough for now. +*) +let is_directly_used com meta = + not (has_dce com) || Ast.Meta.has Ast.Meta.DirectlyUsed meta + let rec has_feature com f = try Hashtbl.find com.features f @@ -726,10 +903,14 @@ let rec has_feature com f = let r = (try let path = List.rev pack, cl in (match List.find (fun t -> t_path t = path && not (Ast.Meta.has Ast.Meta.RealPath (t_infos t).mt_meta)) com.types with - | t when meth = "*" -> (match t with TAbstractDecl a -> Ast.Meta.has Ast.Meta.ValueUsed a.a_meta | _ -> Ast.Meta.has Ast.Meta.Used (t_infos t).mt_meta) - | TClassDecl ({cl_extern = true} as c) -> Meta.has Meta.Used (try PMap.find meth c.cl_statics with Not_found -> PMap.find meth c.cl_fields).cf_meta - | TClassDecl c -> PMap.exists meth c.cl_statics || PMap.exists meth c.cl_fields - | _ -> false) + | t when meth = "*" -> (match t with TAbstractDecl a -> Ast.Meta.has Ast.Meta.ValueUsed a.a_meta | _ -> + Ast.Meta.has Ast.Meta.Used (t_infos t).mt_meta) + | TClassDecl ({cl_extern = true} as c) when com.platform <> Js || cl <> "Array" && cl <> "Math" -> + Meta.has Meta.Used (try PMap.find meth c.cl_statics with Not_found -> PMap.find meth c.cl_fields).cf_meta + | TClassDecl c -> + PMap.exists meth c.cl_statics || PMap.exists meth c.cl_fields + | _ -> + false) with Not_found -> false ) in @@ -750,17 +931,33 @@ let platform ctx p = ctx.platform = p let add_filter ctx f = ctx.filters <- f :: ctx.filters +let add_final_filter ctx f = + ctx.final_filters <- f :: ctx.final_filters + let find_file ctx f = - let rec loop = function - | [] -> raise Not_found - | p :: l -> - let file = p ^ f in - if Sys.file_exists file then - file - else - loop l - in - loop ctx.class_path + try + (match Hashtbl.find ctx.file_lookup_cache f with + | None -> raise Exit + | Some f -> f) + with Exit -> + raise Not_found + | Not_found -> + let rec loop had_empty = function + | [] when had_empty -> raise Not_found + | [] -> loop true [""] + | p :: l -> + let file = p ^ f in + if Sys.file_exists file then + file + else + loop (had_empty || p = "") l + in + let r = (try Some (loop false ctx.class_path) with Not_found -> None) in + Hashtbl.add ctx.file_lookup_cache f r; + (match r with + | None -> raise Not_found + | Some f -> f) + let get_full_path f = try Extc.get_full_path f with _ -> f @@ -774,6 +971,31 @@ let normalize_path p = | '\\' | '/' -> p | _ -> p ^ "/" +let rec mkdir_recursive base dir_list = + match dir_list with + | [] -> () + | dir :: remaining -> + let path = match base with + | "" -> dir + | "/" -> "/" ^ dir + | _ -> base ^ "/" ^ dir + in + if not ( (path = "") || ( ((String.length path) = 2) && ((String.sub path 1 1) = ":") ) ) then + if not (Sys.file_exists path) then + Unix.mkdir path 0o755; + mkdir_recursive (if (path = "") then "/" else path) remaining + +let mkdir_from_path path = + let parts = Str.split_delim (Str.regexp "[\\/]+") path in + match parts with + | [] -> (* path was "" *) () + | _ -> + let dir_list = List.rev (List.tl (List.rev parts)) in + mkdir_recursive "" dir_list + +let mem_size v = + Objsize.size_with_headers (Objsize.objsize v [] []) + (* ------------------------- TIMERS ----------------------------- *) type timer_infos = { @@ -824,3 +1046,33 @@ let rec close_times() = | [] -> () | t :: _ -> close t; close_times() +;; +Ast.Meta.to_string_ref := fun m -> fst (MetaInfo.to_string m) + +(* Taken from OCaml source typing/oprint.ml + + This is a better version of string_of_float which prints without loss of precision + so that float_of_string (float_repres x) = x for all floats x +*) +let valid_float_lexeme s = + let l = String.length s in + let rec loop i = + if i >= l then s ^ "." else + match s.[i] with + | '0' .. '9' | '-' -> loop (i+1) + | _ -> s + in loop 0 + +let float_repres f = + match classify_float f with + | FP_nan -> "nan" + | FP_infinite -> + if f < 0.0 then "neg_infinity" else "infinity" + | _ -> + let float_val = + let s1 = Printf.sprintf "%.12g" f in + if f = float_of_string s1 then s1 else + let s2 = Printf.sprintf "%.15g" f in + if f = float_of_string s2 then s2 else + Printf.sprintf "%.18g" f + in valid_float_lexeme float_val diff --git a/dce.ml b/dce.ml index d8fb612b47d7ccfc3b9a804d501ba8cad0d5734f..ca34d26b437e680e484d0cd5a9d6f387fd0c3281 100644 --- a/dce.ml +++ b/dce.ml @@ -1,497 +1,735 @@ -(* - * Copyright (C)2005-2013 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. - *) - -open Ast -open Common -open Type - -type dce = { - com : context; - full : bool; - std_dirs : string list; - debug : bool; - follow_expr : dce -> texpr -> unit; - mutable added_fields : (tclass * tclass_field * bool) list; - mutable marked_fields : tclass_field list; - mutable marked_maybe_fields : tclass_field list; - mutable t_stack : t list; -} - -(* checking *) - -(* check for @:keepSub metadata, which forces @:keep on child classes *) -let rec super_forces_keep c = - Meta.has Meta.KeepSub c.cl_meta || match c.cl_super with - | Some (csup,_) -> super_forces_keep csup - | _ -> false - -let is_std_file dce file = - List.exists (ExtString.String.starts_with file) dce.std_dirs - -(* check if a class is kept entirely *) -let keep_whole_class dce c = - Meta.has Meta.Keep c.cl_meta - || not (dce.full || is_std_file dce c.cl_module.m_extra.m_file) - || super_forces_keep c - || (match c with - | { cl_extern = true; cl_path = ([],("Math"|"Array"))} when dce.com.platform = Js -> false - | { cl_extern = true } - | { cl_path = ["flash";"_Boot"],"RealBoot" } -> true - | { cl_path = [],"String" } - | { cl_path = [],"Array" } -> not (dce.com.platform = Js) - | _ -> false) - -(* check if a metadata contains @:ifFeature with a used feature argument *) -let has_used_feature com meta = - try - let _,el,_ = Meta.get Meta.IfFeature meta in - List.exists (fun e -> match fst e with - | EConst(String s) when Common.has_feature com s -> true - | _ -> false - ) el - with Not_found -> - false - -(* check if a field is kept *) -let keep_field dce cf = - Meta.has Meta.Keep cf.cf_meta - || Meta.has Meta.Used cf.cf_meta - || cf.cf_name = "__init__" - || has_used_feature dce.com cf.cf_meta - -(* marking *) - -(* mark a field as kept *) -let rec mark_field dce c cf stat = - let add () = - if not (Meta.has Meta.Used cf.cf_meta) then begin - cf.cf_meta <- (Meta.Used,[],cf.cf_pos) :: cf.cf_meta; - dce.added_fields <- (c,cf,stat) :: dce.added_fields; - dce.marked_fields <- cf :: dce.marked_fields - end - in - if not (PMap.mem cf.cf_name (if stat then c.cl_statics else c.cl_fields)) then begin - match c.cl_super with - | None -> add() - | Some (c,_) -> mark_field dce c cf stat - end else - add() - -let rec update_marked_class_fields dce c = - (* mark all :?used fields as surely :used now *) - List.iter (fun cf -> - if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf true - ) c.cl_ordered_statics; - List.iter (fun cf -> - if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf false - ) c.cl_ordered_fields; - (* we always have to keep super classes and implemented interfaces *) - (match c.cl_init with None -> () | Some init -> dce.follow_expr dce init); - List.iter (fun (c,_) -> mark_class dce c) c.cl_implements; - (match c.cl_super with None -> () | Some (csup,pl) -> mark_class dce csup) - -(* 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; - 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; - PMap.iter (fun _ ef -> mark_t dce ef.ef_type) e.e_constrs; -end - -and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then - a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta - -(* mark a type as kept *) -and mark_t dce t = 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; - List.iter (mark_t dce) tl; - end; - List.iter (mark_t dce) pl - | TInst(c,pl) -> - mark_class dce c; - List.iter (mark_t dce) pl - | TFun(args,ret) -> - List.iter (fun (_,_,t) -> mark_t dce t) args; - mark_t dce ret - | TEnum(e,pl) -> - mark_enum dce e; - List.iter (mark_t dce) pl - | TAbstract(a,pl) -> - mark_abstract dce a; - List.iter (mark_t dce) pl - | TLazy _ | TDynamic _ | TAnon _ | TType _ | TMono _ -> () - -let mark_mt dce mt = match mt with - | TClassDecl c -> - mark_class dce c; - | TEnumDecl e -> - mark_enum dce e - | TAbstractDecl a -> - (* abstract 'feature' is defined as the abstract type beeing used as a value, not as a type *) - if not (Meta.has Meta.ValueUsed a.a_meta) then a.a_meta <- (Meta.ValueUsed,[],a.a_pos) :: a.a_meta; - mark_abstract dce a - | TTypeDecl _ -> - () - -(* find all dependent fields by checking implementing/subclassing types *) -let rec mark_dependent_fields dce csup n stat = - List.iter (fun mt -> match mt with - | TClassDecl c when is_parent csup c -> - let rec loop c = - (try - let cf = PMap.find n (if stat then c.cl_statics else c.cl_fields) in - (* if it's clear that the class is kept, the field has to be kept as well. This is also true for - extern interfaces because we cannot remove fields from them *) - if Meta.has Meta.Used c.cl_meta || (csup.cl_interface && csup.cl_extern) then mark_field dce c cf stat - (* otherwise it might be kept if the class is kept later, so mark it as :?used *) - else if not (Meta.has Meta.MaybeUsed cf.cf_meta) then begin - cf.cf_meta <- (Meta.MaybeUsed,[],cf.cf_pos) :: cf.cf_meta; - dce.marked_maybe_fields <- cf :: dce.marked_maybe_fields; - end - with Not_found -> - (* if the field is not present on current class, it might come from a base class *) - (match c.cl_super with None -> () | Some (csup,_) -> loop csup)) - in - loop c - | _ -> () - ) dce.com.types - -(* expr and field evaluation *) - -let opt f e = match e with None -> () | Some e -> f e - -let rec to_string dce t = - let push t = - dce.t_stack <- t :: dce.t_stack; - fun () -> dce.t_stack <- List.tl dce.t_stack - in - let t = follow t in - if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.t_stack) then match follow t with - | TInst(c,pl) as t -> - let pop = push t in - field dce c "toString" false; - List.iter (to_string dce) pl; - pop(); - | TEnum(en,pl) as t -> - let pop = push t in - PMap.iter (fun _ ef -> to_string dce ef.ef_type) en.e_constrs; - List.iter (to_string dce) pl; - pop(); - | TAnon a as t -> - let pop = push t in - PMap.iter (fun _ cf -> to_string dce cf.cf_type) a.a_fields; - pop(); - | TFun(args,r) as t -> - let pop = push t in - List.iter (fun (_,_,t) -> to_string dce t) args; - to_string dce r; - pop(); - | _ -> () - -and field dce c n stat = - let find_field n = - if n = "new" then match c.cl_constructor with - | None -> raise Not_found - | Some cf -> cf - else PMap.find n (if stat then c.cl_statics else c.cl_fields) - in - (try - let cf = find_field n in - mark_field dce c cf stat; - with Not_found -> try - (* me might have a property access on an interface *) - let l = String.length n - 4 in - if l < 0 then raise Not_found; - let prefix = String.sub n 0 4 in - let pn = String.sub n 4 l in - let cf = find_field pn in - if not (Meta.has Meta.Used cf.cf_meta) then begin - let keep () = - mark_dependent_fields dce c n stat; - field dce c pn stat - in - (match prefix,cf.cf_kind with - | "get_",Var {v_read = AccCall} when "get_" ^ cf.cf_name = n -> keep() - | "set_",Var {v_write = AccCall} when "set_" ^ cf.cf_name = n -> keep() - | _ -> raise Not_found - ); - end; - raise Not_found - with Not_found -> try - if c.cl_interface then begin - let rec loop cl = match cl with - | [] -> raise Not_found - | (c,_) :: cl -> - try field dce c n stat with Not_found -> loop cl - in - loop c.cl_implements - end else match c.cl_super with Some (csup,_) -> field dce csup n stat | None -> raise Not_found - with Not_found -> try - match c.cl_kind with - | KTypeParameter tl -> - let rec loop tl = match tl with - | [] -> raise Not_found - | TInst(c,_) :: cl -> - (try field dce c n stat with Not_found -> loop cl) - | t :: tl -> - loop tl - in - loop tl - | _ -> raise Not_found - with Not_found -> - if dce.debug then prerr_endline ("[DCE] Field " ^ n ^ " not found on " ^ (s_type_path c.cl_path)) else ()) - -and expr dce e = - mark_t dce e.etype; - match e.eexpr with - | TNew(c,pl,el) -> - mark_class dce c; - let rec loop c = - field dce c "new" false; - match c.cl_super with None -> () | Some (csup,_) -> loop csup - in - loop c; - List.iter (expr dce) el; - List.iter (mark_t dce) pl; - | TVars vl -> - List.iter (fun (v,e) -> - opt (expr dce) e; - mark_t dce v.v_type; - ) vl; - | TCast(e, Some mt) -> - mark_mt dce mt; - expr dce e; - | TTypeExpr mt -> - mark_mt dce mt - | TTry(e, vl) -> - expr dce e; - List.iter (fun (v,e) -> - expr dce e; - mark_t dce v.v_type; - ) vl; - | TCall ({eexpr = TLocal ({v_name = "__define_feature__"})},[{eexpr = TConst (TString ft)};e]) -> - Common.add_feature dce.com ft; - expr dce e - (* keep toString method when the class is argument to Std.string or haxe.Log.trace *) - | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = (["haxe"],"Log")} as c))},FStatic (_,{cf_name="trace"}))} as ef, ([e2;_] as args)) - | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = ([],"Std")} as c))},FStatic (_,{cf_name="string"}))} as ef, ([e2] as args)) -> - mark_class dce c; - to_string dce e2.etype; - expr dce ef; - List.iter (expr dce) args; - | TCall ({eexpr = TConst TSuper} as e,el) -> - mark_t dce e.etype; - List.iter (expr dce) el; - | TField(e,fa) -> - begin match fa with - | FStatic(c,cf) -> - mark_class dce c; - mark_field dce c cf true; - | FInstance(c,cf) -> - mark_class dce c; - mark_field dce c cf false; - | _ -> - let n = field_name fa in - begin match follow e.etype with - | TInst(c,_) -> - mark_class dce c; - field dce c n false; - | TAnon a -> - (match !(a.a_status) with - | Statics c -> - mark_class dce c; - field dce c n true; - | _ -> ()) - | _ -> () - end; - end; - expr dce e; - | TThrow e -> - to_string dce e.etype; - expr dce e - | _ -> - Type.iter (expr dce) e - -let run com main full = - let dce = { - com = com; - full = full; - std_dirs = if full then [] else List.map Common.unique_full_path com.std_path; - debug = Common.defined com Define.DceDebug; - added_fields = []; - follow_expr = expr; - marked_fields = []; - marked_maybe_fields = []; - t_stack = []; - } in - begin match main with - | Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} -> - cf.cf_meta <- (Meta.Keep,[],cf.cf_pos) :: cf.cf_meta - | _ -> - () - end; - (* first step: get all entry points, which is the main method and all class methods which are marked with @:keep *) - List.iter (fun t -> match t with - | TClassDecl c -> - let keep_class = keep_whole_class dce c && (not c.cl_extern || c.cl_interface) in - let loop stat cf = - if keep_class || keep_field dce cf then mark_field dce c cf stat - in - List.iter (loop true) c.cl_ordered_statics; - List.iter (loop false) c.cl_ordered_fields; - begin match c.cl_constructor with - | Some cf -> loop false cf - | None -> () - end - | _ -> - () - ) com.types; - if dce.debug then begin - List.iter (fun (c,cf,_) -> match cf.cf_expr with - | None -> () - | Some _ -> print_endline ("[DCE] Entry point: " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) - ) dce.added_fields; - end; - (* second step: initiate DCE passes and keep going until no new fields were added *) - let rec loop () = - match dce.added_fields with - | [] -> () - | cfl -> - dce.added_fields <- []; - (* extend to dependent (= overriding/implementing) class fields *) - List.iter (fun (c,cf,stat) -> mark_dependent_fields dce c cf.cf_name stat) cfl; - (* mark fields as used *) - List.iter (fun (c,cf,stat) -> - mark_class dce c; - mark_field dce c cf stat; - mark_t dce cf.cf_type - ) cfl; - (* follow expressions to new types/fields *) - List.iter (fun (_,cf,_) -> - opt (expr dce) cf.cf_expr; - List.iter (fun cf -> if cf.cf_expr <> None then opt (expr dce) cf.cf_expr) cf.cf_overloads - ) cfl; - loop () - in - loop (); - (* third step: filter types *) - let rec loop acc types = - match types with - | (TClassDecl c) as mt :: l when keep_whole_class dce c -> - loop (mt :: acc) l - | (TClassDecl c) as mt :: l -> - (* 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_ordered_statics <- List.filter (fun cf -> - let b = keep_field dce cf in - if not b then begin - if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name)); - c.cl_statics <- PMap.remove cf.cf_name c.cl_statics; - end; - b - ) c.cl_ordered_statics; - c.cl_ordered_fields <- List.filter (fun cf -> - let b = keep_field dce cf in - if not b then begin - if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name)); - c.cl_fields <- PMap.remove cf.cf_name c.cl_fields; - end; - b - ) c.cl_ordered_fields; - (match c.cl_constructor with Some cf when not (keep_field dce cf) -> c.cl_constructor <- None | _ -> ()); - (* we keep a class if it was used or has a used field *) - if Meta.has Meta.Used c.cl_meta || c.cl_ordered_statics <> [] || c.cl_ordered_fields <> [] then loop (mt :: acc) l else begin - (match c.cl_init with - | Some f when Meta.has Meta.KeepInit c.cl_meta -> - (* it means that we only need the __init__ block *) - c.cl_extern <- true; - loop (mt :: acc) l - | _ -> - if dce.debug then print_endline ("[DCE] Removed class " ^ (s_type_path c.cl_path)); - loop acc l) - end - | (TEnumDecl e) as mt :: l when Meta.has Meta.Used e.e_meta || Meta.has Meta.Keep e.e_meta || e.e_extern || not (dce.full || is_std_file dce e.e_module.m_extra.m_file) -> - loop (mt :: acc) l - | TEnumDecl e :: l -> - if dce.debug then print_endline ("[DCE] Removed enum " ^ (s_type_path e.e_path)); - loop acc l - | mt :: l -> - loop (mt :: acc) l - | [] -> - acc - in - com.types <- loop [] (List.rev com.types); - - (* extra step to adjust properties that had accessors removed (required for Php and Cpp) *) - List.iter (fun mt -> match mt with - | (TClassDecl c) -> - let rec has_accessor c n stat = - PMap.mem n (if stat then c.cl_statics else c.cl_fields) - || match c.cl_super with Some (csup,_) -> has_accessor csup n stat | None -> false - in - let check_prop stat cf = - (match cf.cf_kind with - | Var {v_read = AccCall; v_write = a} -> - let s = "get_" ^ cf.cf_name in - cf.cf_kind <- Var {v_read = if has_accessor c s stat then AccCall else AccNever; v_write = a} - | _ -> ()); - (match cf.cf_kind with - | Var {v_write = AccCall; v_read = a} -> - let s = "set_" ^ cf.cf_name in - cf.cf_kind <- Var {v_write = if has_accessor c s stat then AccCall else AccNever; v_read = a} - | _ -> ()) - in - List.iter (check_prop true) c.cl_ordered_statics; - List.iter (check_prop false) c.cl_ordered_fields; - | _ -> () - ) com.types; - - (* remove "override" from fields that do not override anything anymore *) - List.iter (fun mt -> match mt with - | TClassDecl c -> - c.cl_overrides <- List.filter (fun s -> - let rec loop c = - match c.cl_super with - | Some (csup,_) when PMap.mem s.cf_name csup.cl_fields -> true - | Some (csup,_) -> loop csup - | None -> false - in - loop c - ) c.cl_overrides; - | _ -> () - ) com.types; - - (* cleanup added fields metadata - compatibility with compilation server *) - let rec remove_meta m = function - | [] -> [] - | (m2,_,_) :: l when m = m2 -> l - | x :: l -> x :: remove_meta m l - in - List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.Used cf.cf_meta) dce.marked_fields; - List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.MaybeUsed cf.cf_meta) dce.marked_maybe_fields; - - +(* + * Copyright (C)2005-2013 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. + *) + +open Ast +open Common +open Type + +type dce = { + com : context; + full : bool; + std_dirs : string list; + debug : bool; + follow_expr : dce -> texpr -> unit; + mutable curclass : tclass; + mutable added_fields : (tclass * tclass_field * bool) list; + mutable marked_fields : tclass_field list; + mutable marked_maybe_fields : tclass_field list; + mutable t_stack : t list; + mutable ts_stack : t list; + mutable features : (string,(tclass * tclass_field * bool) list) Hashtbl.t; +} + +(* checking *) + +(* check for @:keepSub metadata, which forces @:keep on child classes *) +let rec super_forces_keep c = + Meta.has Meta.KeepSub c.cl_meta || match c.cl_super with + | Some (csup,_) -> super_forces_keep csup + | _ -> false + +let is_std_file dce file = + List.exists (ExtString.String.starts_with file) dce.std_dirs + +(* check if a class is kept entirely *) +let keep_whole_class dce c = + Meta.has Meta.Keep c.cl_meta + || not (dce.full || is_std_file dce c.cl_module.m_extra.m_file || has_meta Meta.Dce c.cl_meta) + || super_forces_keep c + || (match c with + | { cl_path = ([],("Math"|"Array"))} when dce.com.platform = Js -> false + | { cl_extern = true } + | { cl_path = ["flash";"_Boot"],"RealBoot" } -> true + | { cl_path = [],"String" } + | { cl_path = [],"Array" } -> not (dce.com.platform = Js) + | _ -> false) + +let keep_whole_enum dce en = + Meta.has Meta.Keep en.e_meta + || not (dce.full || is_std_file dce en.e_module.m_extra.m_file || has_meta Meta.Dce en.e_meta) + +(* check if a field is kept *) +let keep_field dce cf = + Meta.has Meta.Keep cf.cf_meta + || Meta.has Meta.Used cf.cf_meta + || cf.cf_name = "__init__" + || is_extern_field cf + +(* marking *) + +let rec check_feature dce s = + try + let l = Hashtbl.find dce.features s in + List.iter (fun (c,cf,stat) -> + mark_field dce c cf stat + ) l; + Hashtbl.remove dce.features s; + with Not_found -> + () + +and check_and_add_feature dce s = + check_feature dce s; + Common.add_feature dce.com s; + +(* mark a field as kept *) +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; + 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); + end + in + if cf.cf_name = "new" then begin + let rec loop c = match c.cl_super with + | None -> () + | Some (csup,_) -> + begin match csup.cl_constructor with + | None -> () + | Some cf -> add cf + end; + loop csup + in + loop c + end; + if not (PMap.mem cf.cf_name (if stat then c.cl_statics else c.cl_fields)) then begin + match c.cl_super with + | None -> add cf + | Some (c,_) -> mark_field dce c cf stat + end else + add cf + +let rec update_marked_class_fields dce c = + (* mark all :?used fields as surely :used now *) + List.iter (fun cf -> + if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf true + ) c.cl_ordered_statics; + List.iter (fun cf -> + if Meta.has Meta.MaybeUsed cf.cf_meta then mark_field dce c cf false + ) c.cl_ordered_fields; + (* we always have to keep super classes and implemented interfaces *) + (match c.cl_init with None -> () | Some init -> dce.follow_expr dce init); + List.iter (fun (c,_) -> mark_class dce c) c.cl_implements; + (match c.cl_super with None -> () | Some (csup,pl) -> mark_class dce csup) + +(* 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; + 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; + 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; +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 +end + +(* mark a type as kept *) +and mark_t dce p t = + if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.t_stack) then begin + dce.t_stack <- t :: dce.t_stack; + 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; + List.iter (mark_t dce p) tl; + end; + List.iter (mark_t dce p) pl + | TInst(c,pl) -> + mark_class dce c; + List.iter (mark_t dce p) pl + | TFun(args,ret) -> + List.iter (fun (_,_,t) -> mark_t dce p t) args; + mark_t dce p ret + | TEnum(e,pl) -> + mark_enum dce e; + List.iter (mark_t dce p) pl + | TAbstract(a,pl) when Meta.has Meta.MultiType a.a_meta -> + begin try + mark_t dce p (snd (Codegen.AbstractCast.find_multitype_specialization dce.com a pl p)) + with Typecore.Error _ -> + () + end + | TAbstract(a,pl) -> + mark_abstract dce a; + List.iter (mark_t dce p) pl; + if not (Meta.has Meta.CoreType a.a_meta) then + mark_t dce p (Abstract.get_underlying_type a pl) + | TLazy _ | TDynamic _ | TType _ | TAnon _ | TMono _ -> () + end; + dce.t_stack <- List.tl dce.t_stack + end + +let mark_mt dce mt = match mt with + | TClassDecl c -> + mark_class dce c; + | TEnumDecl e -> + mark_enum dce e + | TAbstractDecl a -> + (* abstract 'feature' is defined as the abstract type beeing used as a value, not as a type *) + if not (Meta.has Meta.ValueUsed a.a_meta) then a.a_meta <- (Meta.ValueUsed,[],a.a_pos) :: a.a_meta; + mark_abstract dce a + | TTypeDecl _ -> + () + +(* find all dependent fields by checking implementing/subclassing types *) +let rec mark_dependent_fields dce csup n stat = + List.iter (fun mt -> match mt with + | TClassDecl c when is_parent csup c -> + let rec loop c = + (try + let cf = PMap.find n (if stat then c.cl_statics else c.cl_fields) in + (* if it's clear that the class is kept, the field has to be kept as well. This is also true for + extern interfaces because we cannot remove fields from them *) + if Meta.has Meta.Used c.cl_meta || (csup.cl_interface && csup.cl_extern) then mark_field dce c cf stat + (* otherwise it might be kept if the class is kept later, so mark it as :?used *) + else if not (Meta.has Meta.MaybeUsed cf.cf_meta) then begin + cf.cf_meta <- (Meta.MaybeUsed,[],cf.cf_pos) :: cf.cf_meta; + dce.marked_maybe_fields <- cf :: dce.marked_maybe_fields; + end + with Not_found -> + (* if the field is not present on current class, it might come from a base class *) + (match c.cl_super with None -> () | Some (csup,_) -> loop csup)) + in + loop c + | _ -> () + ) dce.com.types + +(* expr and field evaluation *) + +let opt f e = match e with None -> () | Some e -> f e + +let rec to_string dce t = match t with + | TInst(c,tl) -> + field dce c "toString" false; + | TType(tt,tl) -> + if not (List.exists (fun t2 -> Type.fast_eq t t2) dce.ts_stack) then begin + dce.ts_stack <- t :: dce.ts_stack; + to_string dce (apply_params tt.t_params tl tt.t_type) + end + | TAbstract({a_impl = Some c} as a,tl) -> + if Meta.has Meta.CoreType a.a_meta then + field dce c "toString" false + else + to_string dce (Abstract.get_underlying_type a tl) + | TMono r -> + (match !r with + | Some t -> to_string dce t + | _ -> ()) + | TLazy f -> + to_string dce (!f()) + | TDynamic t -> + if t == t_dynamic then + () + else + to_string dce t + | TEnum _ | TFun _ | TAnon _ | TAbstract({a_impl = None},_) -> + (* if we to_string these it does not imply that we need all its sub-types *) + () + +and field dce c n stat = + let find_field n = + if n = "new" then match c.cl_constructor with + | None -> raise Not_found + | Some cf -> cf + else PMap.find n (if stat then c.cl_statics else c.cl_fields) + in + (try + let cf = find_field n in + mark_field dce c cf stat; + with Not_found -> try + if c.cl_interface then begin + let rec loop cl = match cl with + | [] -> raise Not_found + | (c,_) :: cl -> + try field dce c n stat with Not_found -> loop cl + in + loop c.cl_implements + end else match c.cl_super with Some (csup,_) -> field dce csup n stat | None -> raise Not_found + with Not_found -> try + match c.cl_kind with + | KTypeParameter tl -> + let rec loop tl = match tl with + | [] -> raise Not_found + | TInst(c,_) :: cl -> + (try field dce c n stat with Not_found -> loop cl) + | t :: tl -> + loop tl + in + loop tl + | _ -> raise Not_found + with Not_found -> + if dce.debug then prerr_endline ("[DCE] Field " ^ n ^ " not found on " ^ (s_type_path c.cl_path)) else ()) + +and mark_directly_used_class c = + if not (Meta.has Meta.DirectlyUsed c.cl_meta) then + c.cl_meta <- (Meta.DirectlyUsed,[],c.cl_pos) :: c.cl_meta + +and mark_directly_used_enum e = + if not (Meta.has Meta.DirectlyUsed e.e_meta) then + e.e_meta <- (Meta.DirectlyUsed,[],e.e_pos) :: e.e_meta + +and mark_directly_used_mt mt = + match mt with + | TClassDecl c -> + mark_directly_used_class c + | TEnumDecl e -> + mark_directly_used_enum e + | _ -> + () + +and check_dynamic_write dce fa = + let n = field_name fa in + check_and_add_feature dce ("dynamic_write"); + check_and_add_feature dce ("dynamic_write." ^ n) + +and check_anon_optional_write dce fa = + let n = field_name fa in + check_and_add_feature dce ("anon_optional_write"); + check_and_add_feature dce ("anon_optional_write." ^ n) + +and check_anon_write dce fa = + let n = field_name fa in + check_and_add_feature dce ("anon_write"); + check_and_add_feature dce ("anon_write." ^ n) + +and is_array t = match follow t with + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_array (Abstract.get_underlying_type a tl) + | TInst({ cl_path = ([], "Array")},_) -> true + | _ -> false + +and is_dynamic t = match follow t with + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_dynamic (Abstract.get_underlying_type a tl) + | TDynamic _ -> true + | _ -> false + +and is_string t = match follow t with + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> is_string (Abstract.get_underlying_type a tl) + | TInst( { cl_path = ([], "String")}, _) -> true + | _ -> false + +and is_const_string e = match e.eexpr with + | TConst(TString(_)) -> true + | _ -> false + +and expr dce e = + mark_t dce e.epos e.etype; + match e.eexpr with + | TNew(c,pl,el) -> + mark_class dce c; + mark_directly_used_class c; + field dce c "new" false; + List.iter (expr dce) el; + List.iter (mark_t dce e.epos) pl; + | TVar (v,e1) -> + opt (expr dce) e1; + mark_t dce e.epos v.v_type; + | TCast(e, Some mt) -> + check_feature dce "typed_cast"; + mark_mt dce mt; + mark_directly_used_mt mt; + expr dce e; + | TObjectDecl(vl) -> + check_and_add_feature dce "has_anon"; + List.iter (fun (_,e) -> expr dce e) vl; + | TTypeExpr mt -> + mark_mt dce mt; + mark_directly_used_mt mt; + | TTry(e, vl) -> + expr dce e; + List.iter (fun (v,e) -> + if v.v_type != t_dynamic then check_feature dce "typed_catch"; + expr dce e; + mark_t dce e.epos v.v_type; + ) vl; + | TCall ({eexpr = TLocal ({v_name = "`trace"})},[p;{ eexpr = TObjectDecl(v)}]) -> + check_and_add_feature dce "has_anon_trace"; + List.iter (fun (_,e) -> expr dce e) v; + expr dce p; + | TCall ({eexpr = TLocal ({v_name = "__define_feature__"})},[{eexpr = TConst (TString ft)};e]) -> + Hashtbl.replace dce.curclass.cl_module.m_extra.m_features ft true; + check_feature dce ft; + expr dce e; + + (* keep toString method when the class is argument to Std.string or haxe.Log.trace *) + | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = (["haxe"],"Log")} as c))},FStatic (_,{cf_name="trace"}))} as ef, ((e2 :: el) as args)) + | TCall ({eexpr = TField({eexpr = TTypeExpr (TClassDecl ({cl_path = ([],"Std")} as c))},FStatic (_,{cf_name="string"}))} as ef, ((e2 :: el) as args)) -> + mark_class dce c; + to_string dce e2.etype; + begin match el with + | [{eexpr = TObjectDecl fl}] -> + begin try + begin match List.assoc "customParams" fl with + | {eexpr = TArrayDecl el} -> + List.iter (fun e -> to_string dce e.etype) el + | _ -> + () + end + with Not_found -> + () + end + | _ -> + () + end; + expr dce ef; + List.iter (expr dce) args; + | TCall ({eexpr = TConst TSuper} as e,el) -> + mark_t dce e.epos e.etype; + List.iter (expr dce) el; + | TBinop(OpAdd,e1,e2) when is_dynamic e1.etype || is_dynamic e2.etype -> + check_and_add_feature dce "add_dynamic"; + expr dce e1; + expr dce e2; + | TBinop( (OpAdd | (OpAssignOp OpAdd)),e1,e2) when ((is_string e1.etype || is_string e2.etype) && not ( is_const_string e1 && is_const_string e2)) -> + check_and_add_feature dce "unsafe_string_concat"; + expr dce e1; + expr dce e2; + | TArray(({etype = TDynamic t} as e1),e2) when t == t_dynamic -> + check_and_add_feature dce "dynamic_array_read"; + expr dce e1; + expr dce e2; + | TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = TDynamic t},_)} as e1), e2) when t == t_dynamic -> + check_and_add_feature dce "dynamic_array_write"; + expr dce e1; + expr dce e2; + | TArray(({etype = t} as e1),e2) when is_array t -> + check_and_add_feature dce "array_read"; + expr dce e1; + expr dce e2; + | TBinop( (OpAssign | OpAssignOp _), ({eexpr = TArray({etype = t},_)} as e1), e2) when is_array t -> + check_and_add_feature dce "array_write"; + expr dce e1; + expr dce e2; + | TBinop(OpAssign,({eexpr = TField(_,(FDynamic _ as fa) )} as e1),e2) -> + check_dynamic_write dce fa; + expr dce e1; + expr dce e2; + | TBinop(OpAssign,({eexpr = TField(_,(FAnon cf as fa) )} as e1),e2) -> + if Meta.has Meta.Optional cf.cf_meta then + check_anon_optional_write dce fa + else + check_anon_write dce fa; + expr dce e1; + expr dce e2; + | TBinop(OpAssignOp op,({eexpr = TField(_,(FDynamic _ as fa) )} as e1),e2) -> + check_dynamic_write dce fa; + expr dce e1; + expr dce e2; + | TBinop(OpAssignOp op,({eexpr = TField(_,(FAnon cf as fa) )} as e1),e2) -> + if Meta.has Meta.Optional cf.cf_meta then + check_anon_optional_write dce fa + else + check_anon_write dce fa; + expr dce e1; + expr dce e2; + | TBinop(OpEq,({ etype = t1} as e1), ({ etype = t2} as e2) ) when is_dynamic t1 || is_dynamic t2 -> + check_and_add_feature dce "dynamic_binop_=="; + expr dce e1; + expr dce e2; + | TBinop(OpEq,({ etype = t1} as e1), ({ etype = t2} as e2) ) when is_dynamic t1 || is_dynamic t2 -> + check_and_add_feature dce "dynamic_binop_!="; + expr dce e1; + expr dce e2; + | TBinop(OpMod,e1,e2) -> + check_and_add_feature dce "binop_%"; + expr dce e1; + expr dce e2; + | TBinop(OpUShr,e1,e2) -> + check_and_add_feature dce "binop_>>>"; + expr dce e1; + expr dce e2; + | TField(e,fa) -> + begin match fa with + | FStatic(c,cf) -> + mark_class dce c; + mark_field dce c cf true; + | FInstance(c,_,cf) -> + mark_class dce c; + mark_field dce c cf false; + | _ -> + + let n = field_name fa in + (match fa with + | FAnon cf -> + if Meta.has Meta.Optional cf.cf_meta then begin + check_and_add_feature dce "anon_optional_read"; + check_and_add_feature dce ("anon_optional_read." ^ n); + end else begin + check_and_add_feature dce "anon_read"; + check_and_add_feature dce ("anon_read." ^ n); + end + | FDynamic _ -> + check_and_add_feature dce "dynamic_read"; + check_and_add_feature dce ("dynamic_read." ^ n); + | _ -> ()); + begin match follow e.etype with + | TInst(c,_) -> + mark_class dce c; + field dce c n false; + | TAnon a -> + (match !(a.a_status) with + | Statics c -> + mark_class dce c; + field dce c n true; + | _ -> ()) + + + | _ -> () + end; + end; + expr dce e; + | TThrow e -> + check_and_add_feature dce "has_throw"; + to_string dce e.etype; + expr dce e + | _ -> + Type.iter (expr dce) e + +let fix_accessors com = + List.iter (fun mt -> match mt with + | (TClassDecl c) -> + let rec has_accessor c n stat = + PMap.mem n (if stat then c.cl_statics else c.cl_fields) + || match c.cl_super with Some (csup,_) -> has_accessor csup n stat | None -> false + in + let check_prop stat cf = + (match cf.cf_kind with + | Var {v_read = AccCall; v_write = a} -> + let s = "get_" ^ cf.cf_name in + cf.cf_kind <- Var {v_read = if has_accessor c s stat then AccCall else AccNever; v_write = a} + | _ -> ()); + (match cf.cf_kind with + | Var {v_write = AccCall; v_read = a} -> + let s = "set_" ^ cf.cf_name in + cf.cf_kind <- Var {v_write = if has_accessor c s stat then AccCall else AccNever; v_read = a} + | _ -> ()) + in + List.iter (check_prop true) c.cl_ordered_statics; + List.iter (check_prop false) c.cl_ordered_fields; + | _ -> () + ) com.types + +let run com main full = + let dce = { + com = com; + full = full; + std_dirs = if full then [] else List.map Common.unique_full_path com.std_path; + debug = Common.defined com Define.DceDebug; + added_fields = []; + follow_expr = expr; + marked_fields = []; + marked_maybe_fields = []; + t_stack = []; + ts_stack = []; + features = Hashtbl.create 0; + curclass = null_class; + } in + begin match main with + | Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} -> + cf.cf_meta <- (Meta.Keep,[],cf.cf_pos) :: cf.cf_meta + | _ -> + () + end; + List.iter (fun m -> + List.iter (fun (s,v) -> + if Hashtbl.mem dce.features s then Hashtbl.replace dce.features s (v :: Hashtbl.find dce.features s) + else Hashtbl.add dce.features s [v] + ) m.m_extra.m_if_feature; + ) com.modules; + (* first step: get all entry points, which is the main method and all class methods which are marked with @:keep *) + List.iter (fun t -> match t with + | TClassDecl c -> + let keep_class = keep_whole_class dce c && (not c.cl_extern || c.cl_interface) in + let loop stat cf = + if keep_class || keep_field dce cf then mark_field dce c cf stat + in + List.iter (loop true) c.cl_ordered_statics; + List.iter (loop false) c.cl_ordered_fields; + begin match c.cl_constructor with + | Some cf -> loop false cf + | None -> () + end; + begin match c.cl_init with + | Some e when keep_class || Meta.has Meta.KeepInit c.cl_meta -> + (* create a fake field to deal with our internal logic (issue #3286) *) + let cf = mk_field "__init__" e.etype e.epos in + cf.cf_expr <- Some e; + loop true cf + | _ -> + () + end; + | TEnumDecl en when keep_whole_enum dce en -> + mark_enum dce en + | _ -> + () + ) com.types; + if dce.debug then begin + List.iter (fun (c,cf,_) -> match cf.cf_expr with + | None -> () + | Some _ -> print_endline ("[DCE] Entry point: " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) + ) dce.added_fields; + end; + (* second step: initiate DCE passes and keep going until no new fields were added *) + let rec loop () = + match dce.added_fields with + | [] -> () + | cfl -> + dce.added_fields <- []; + (* extend to dependent (= overriding/implementing) class fields *) + List.iter (fun (c,cf,stat) -> mark_dependent_fields dce c cf.cf_name stat) cfl; + (* mark fields as used *) + List.iter (fun (c,cf,stat) -> + if not (is_extern_field cf) then mark_class dce c; + mark_field dce c cf stat; + mark_t dce cf.cf_pos cf.cf_type + ) cfl; + (* follow expressions to new types/fields *) + List.iter (fun (c,cf,_) -> + dce.curclass <- c; + opt (expr dce) cf.cf_expr; + List.iter (fun cf -> if cf.cf_expr <> None then opt (expr dce) cf.cf_expr) cf.cf_overloads + ) cfl; + loop () + in + loop (); + (* third step: filter types *) + let rec loop acc types = + match types with + | (TClassDecl c) as mt :: l when keep_whole_class dce c -> + loop (mt :: acc) l + | (TClassDecl c) as mt :: l -> + let check_property cf stat = + let add_accessor_metadata cf = + if not (Meta.has Meta.Accessor cf.cf_meta) then cf.cf_meta <- (Meta.Accessor,[],c.cl_pos) :: cf.cf_meta + in + begin match cf.cf_kind with + | Var {v_read = AccCall} -> + begin try + add_accessor_metadata (PMap.find ("get_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields)) + with Not_found -> + () + end + | _ -> + () + end; + begin match cf.cf_kind with + | Var {v_write = AccCall} -> + begin try + add_accessor_metadata (PMap.find ("set_" ^ cf.cf_name) (if stat then c.cl_statics else c.cl_fields)) + with Not_found -> + () + end + | _ -> + () + 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_ordered_statics <- List.filter (fun cf -> + let b = keep_field dce cf in + if not b then begin + if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name)); + check_property cf true; + c.cl_statics <- PMap.remove cf.cf_name c.cl_statics; + end; + b + ) c.cl_ordered_statics; + c.cl_ordered_fields <- List.filter (fun cf -> + let b = keep_field dce cf in + if not b then begin + if dce.debug then print_endline ("[DCE] Removed field " ^ (s_type_path c.cl_path) ^ "." ^ (cf.cf_name)); + check_property cf false; + c.cl_fields <- PMap.remove cf.cf_name c.cl_fields; + end; + b + ) c.cl_ordered_fields; + (match c.cl_constructor with Some cf when not (keep_field dce cf) -> c.cl_constructor <- None | _ -> ()); + let inef cf = not (is_extern_field cf) in + let has_non_extern_fields = List.exists inef c.cl_ordered_fields || List.exists inef c.cl_ordered_statics in + (* we keep a class if it was used or has a used field *) + if Meta.has Meta.Used c.cl_meta || has_non_extern_fields then loop (mt :: acc) l else begin + (match c.cl_init with + | Some f when Meta.has Meta.KeepInit c.cl_meta -> + (* it means that we only need the __init__ block *) + c.cl_extern <- true; + loop (mt :: acc) l + | _ -> + if dce.debug then print_endline ("[DCE] Removed class " ^ (s_type_path c.cl_path)); + loop acc l) + end + | (TEnumDecl en) as mt :: l when Meta.has Meta.Used en.e_meta || en.e_extern || keep_whole_enum dce en -> + loop (mt :: acc) l + | TEnumDecl e :: l -> + if dce.debug then print_endline ("[DCE] Removed enum " ^ (s_type_path e.e_path)); + loop acc l + | mt :: l -> + loop (mt :: acc) l + | [] -> + acc + in + com.types <- loop [] (List.rev com.types); + + (* extra step to adjust properties that had accessors removed (required for Php and Cpp) *) + fix_accessors com; + + (* remove "override" from fields that do not override anything anymore *) + List.iter (fun mt -> match mt with + | TClassDecl c -> + c.cl_overrides <- List.filter (fun s -> + let rec loop c = + match c.cl_super with + | Some (csup,_) when PMap.mem s.cf_name csup.cl_fields -> true + | Some (csup,_) -> loop csup + | None -> false + in + loop c + ) c.cl_overrides; + | _ -> () + ) com.types; + + (* mark extern classes as really used if they are extended by non-extern ones *) + List.iter (function + | TClassDecl ({cl_extern = false; cl_super = Some ({cl_extern = true} as csup, _)}) -> + mark_directly_used_class csup + | TClassDecl ({cl_extern = false} as c) when c.cl_implements <> [] -> + List.iter (fun (iface,_) -> if (iface.cl_extern) then mark_directly_used_class iface) c.cl_implements; + | _ -> () + ) com.types; + + (* cleanup added fields metadata - compatibility with compilation server *) + let rec remove_meta m = function + | [] -> [] + | (m2,_,_) :: l when m = m2 -> l + | x :: l -> x :: remove_meta m l + in + List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.Used cf.cf_meta) dce.marked_fields; + List.iter (fun cf -> cf.cf_meta <- remove_meta Meta.MaybeUsed cf.cf_meta) dce.marked_maybe_fields; + + diff --git a/doc/extract.hxml b/doc/extract.hxml deleted file mode 100644 index ce658c4ca861fff0f8b14a8ae8d2f7ee55d54e58..0000000000000000000000000000000000000000 --- a/doc/extract.hxml +++ /dev/null @@ -1,6 +0,0 @@ --debug --swf-lib library.swf --swf test.swf --swf-version 11.7 ---macro patchTypes("../doc/extract.patch") ---gen-hx-classes \ No newline at end of file diff --git a/doc/install.ml b/doc/install.ml deleted file mode 100644 index b4db78fcfbb897aa4cb172a5f7fa5dbd06b649ce..0000000000000000000000000000000000000000 --- a/doc/install.ml +++ /dev/null @@ -1,202 +0,0 @@ -(* - * Haxe installer - * Copyright (c)2005 Nicolas Cannasse - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - *) - -#load "unix.cma" - -(* ----- BEGIN CONFIGURATION ---- *) - -let bytecode = false -let native = true - -(* ------ END CONFIGURATION ----- *) - -let os_type = Sys.os_type - -(* remove the comment to compile with windows using ocaml cygwin *) -(* let os_type = "Cygwin" *) - -let obj_ext = match os_type with "Win32" -> ".obj" | _ -> ".o" -let exe_ext = match os_type with "Win32" | "Cygwin" -> ".exe" | _ -> "" -let ocamloptflags = match os_type with "Unix" -> "-cclib -fno-stack-protector " | _ -> "" - -let zlib_path = match os_type with - | "Win32" -> "libs/extc/zlib/" - | _ -> "./" - -let zlib = match os_type with - | "Win32" -> zlib_path ^ "zlib.lib" - | _ -> - try - List.find Sys.file_exists ["/usr/lib/libz.dylib";"/usr/lib64/libz.so.1";"/usr/lib/libz.so.1";"/lib/libz.so.1";"/usr/lib/libz.so.4.1";"/lib/x86_64-linux-gnu/libz.so.1"] - with - Not_found -> - failwith "LibZ was not found on your system, please install it or modify the search directories in the install script" - -let msg m = - prerr_endline m; - flush stdout - -let command c = - msg ("> " ^ c); - if Sys.command c <> 0 then failwith ("Error while running " ^ c) - -let cvs root cmd = - command ("cvs -z3 -d" ^ root ^ " " ^ cmd) - -let ocamlc file = - if bytecode then command ("ocamlc -c " ^ file); - if native then command ("ocamlopt -c " ^ ocamloptflags ^ file) - -let modules l ext = - String.concat " " (List.map (fun f -> f ^ ext) l) - -;; - - -let download() = - command "svn co http://haxe.googlecode.com/svn/trunk haxe"; -in - -let compile_libs() = - Sys.chdir "haxe/libs"; - - (* EXTLIB *) - Sys.chdir "extlib"; - command ("ocaml install.ml -nodoc -d .. " ^ (if bytecode then "-b " else "") ^ (if native then "-n" else "")); - msg ""; - Sys.chdir ".."; - - (* EXTC *) - Sys.chdir "extc"; - let c_opts = (if Sys.ocaml_version < "3.08" then " -ccopt -Dcaml_copy_string=copy_string " else " ") in - command ("ocamlc" ^ c_opts ^ " -I .. -I ../../" ^ zlib_path ^ " extc_stubs.c"); - - let options = "-cclib libs/extc/extc_stubs" ^ obj_ext ^ " -cclib " ^ zlib ^ " extc.ml" in - let options = if Sys.os_type = "Win32" then options ^ " -cclib shell32.lib" else options in - if bytecode then command ("ocamlc -a -I .. -o extc.cma " ^ options); - if native then command ("ocamlopt -a -I .. -o extc.cmxa " ^ options); - Sys.chdir ".."; - - (* SWFLIB *) - Sys.chdir "swflib"; - let files = "-I .. -I ../extc as3.mli as3hl.mli as3code.ml as3parse.ml as3hlparse.ml swf.ml actionScript.ml swfParser.ml png.mli png.ml" in - if bytecode then command ("ocamlc -a -o swflib.cma " ^ files); - if native then command ("ocamlopt -a -o swflib.cmxa " ^ files); - Sys.chdir ".."; - - (* NEKO *) - Sys.chdir "neko"; - let files = "-I .. nast.ml nxml.ml binast.ml nbytecode.ml ncompile.ml" in - if bytecode then command ("ocamlc -a -o neko.cma " ^ files); - if native then command ("ocamlopt -a -o neko.cmxa " ^ files); - Sys.chdir ".."; - - (* ZIPLIB *) - Sys.chdir "ziplib"; - let files = "-I .. -I ../extc zlib.mli zlib.ml zip.mli zip.ml" in - if bytecode then command ("ocamlc -a -o zip.cma " ^ files); - if native then command ("ocamlopt -a -o zip.cmxa " ^ files); - Sys.chdir ".."; - - (* JAVALIB *) - Sys.chdir "javalib"; - let files = "-I .. jData.ml jReader.ml" in - if bytecode then command ("ocamlc -a -o java.cma " ^ files); - if native then command ("ocamlopt -a -o java.cmxa " ^ files); - Sys.chdir ".."; - - (* TTFLIB *) - Sys.chdir "ttflib"; - let files = "-I .. -I ../extlib -I ../swflib tTFData.ml tTFParser.ml tTFTools.ml tTFSwfWriter.ml tTFCanvasWriter.ml tTFJsonWriter.ml main.ml" in - if bytecode then command ("ocamlc -a -o ttf.cma " ^ files); - if native then command ("ocamlopt -a -o ttf.cmxa " ^ files); - Sys.chdir ".."; - - (* XML-LIGHT *) - Sys.chdir "xml-light"; - command ("ocamlyacc xml_parser.mly"); - command ("ocamlc xml.mli dtd.mli xml_parser.mli xml_lexer.mli"); - command ("ocamllex xml_lexer.mll"); - let files = "xml_parser.ml xml_lexer.ml dtd.ml xmlParser.mli xmlParser.ml xml.ml" in - if bytecode then command ("ocamlc -a -o xml-light.cma " ^ files); - if native then command ("ocamlopt -a -o xml-light.cmxa " ^ files); - Sys.chdir ".."; - - Sys.chdir "../.."; -in - -let compile() = - - (try Unix.mkdir "bin" 0o740 with Unix.Unix_error(Unix.EEXIST,_,_) -> ()); - - Sys.chdir "haxe"; - (* HAXE *) - command "ocamllex lexer.mll"; - let libs = [ - "libs/extLib"; - "libs/extc/extc"; - "libs/swflib/swflib"; - "libs/xml-light/xml-light"; - "libs/neko/neko"; - "libs/javalib/java"; - "unix"; - "libs/ziplib/zip"; - "str"; - "libs/ttflib/ttf" - ] in - let paths = [ - "libs"; - "libs/swflib"; - "libs/xml-light"; - "libs/extc"; - "libs/neko"; - "libs/ziplib"; - "libs/javalib"; - "libs/ttflib" - ] in - let mlist = [ - "ast";"lexer";"type";"common";"parser";"typecore"; - "genxml";"optimizer";"typeload";"codegen"; - "gencommon"; "genneko";"genas3";"genjs";"genswf8";"genswf9";"genswf";"genphp";"gencpp"; "gencs";"genjava"; - "interp";"typer";"matcher";"dce";"main"; - ] in - let path_str = String.concat " " (List.map (fun s -> "-I " ^ s) paths) in - let libs_str ext = " " ^ String.concat " " (List.map (fun l -> l ^ ext) libs) ^ " " in - ocamlc (path_str ^ " -pp camlp4o " ^ modules mlist ".ml"); - if bytecode then command ("ocamlc -custom -o ../bin/haxe-byte" ^ exe_ext ^ libs_str ".cma" ^ modules mlist ".cmo"); - if native then command ("ocamlopt -o ../bin/haxe" ^ exe_ext ^ libs_str ".cmxa" ^ modules mlist ".cmx"); -in - -let make_std() = - - if Sys.file_exists "../bin/std" then command (if os_type = "Win32" then "rmdir /S /Q ..\\bin\\std" else "rm -rf ../bin/std"); - command "svn export -q std ../bin/std"; - -in -let startdir = Sys.getcwd() in -try - download(); - compile_libs(); - compile(); - make_std(); - Sys.chdir startdir; -with - Failure msg -> - Sys.chdir startdir; - prerr_endline msg; exit 1 diff --git a/doc/CHANGES.txt b/extra/CHANGES.txt similarity index 81% rename from doc/CHANGES.txt rename to extra/CHANGES.txt index 0c8a3a90b13c6c9e057c266627cd94ae2ee0a394..5d0363d77c55940e8640d7363b021212daba78ee 100644 --- a/doc/CHANGES.txt +++ b/extra/CHANGES.txt @@ -1,3 +1,299 @@ +2015-05-12: 3.2.0 + + New features: + + all : added @:noPrivateAccess to re-enable access restrictions within @:privateAccess + cpp : some support for @:nativeGen metadata + + Bugfixes: + + all : fixed detection of @:generic classes with constructor constraints + all : fixed variable initialization check issue in loop condition + all : fixed pattern matching on @:enum abstracts via field access (#4084) + all : fixed missing implicit casts in Map literals (#4100) + all : fixed various minor issues in haxe.xml.Parser + all : fixed class path issue when HAXE_STD_PATH is set (#4163) + js : fixed DCE issue related to printing enums (#4197) + js : fixed various issues with the new Bytes implementation + php : fixed EOF handling in FileInput.readByte (#4082) + cs/java : fixed Math.fround implementation (#4177) + cs/java : fixed some cases of Std.parseInt failing (#4132) + cpp : fixed compilation without -main (#4199) + + General improvements and optimizations: + + all : --macro keep no longer causes types to be included for compilation + php : support interpolation in __php__ code + js : added variable number of arguments support in js.html.* classes + js : refined new HTML externs + + Macro features and changes: + + macro : [breaking] synced FClosure and FInstance with the compiler updates + +2015-03-15: 3.2.0-RC1 + + This release removes support for Flash 8 target + + New features: + + all : added --display mode for toplevel completion + all : added --display mode for position and usage information + all : allowed @:callable on abstracts to forward calls to their underlying type + all : allowed pattern matching on getters + all : allowed @:native on class fields + all : added static analyzer with constant propagation + all : added Haxe-based XML implementation + python : added python target + flash : flash player 12-14 support + js : added @:jsRequire and js.Lib.require + js : support haxe.CallStack.exceptionStack + cs : added @:bridgeProperties + cs : added -D erase_generics + cs : added -D dll_import to import haxe-generated dlls + java/cs : added `sys.db` package + java/cs : clean unused files in output folder, unless `-D keep_old_output` is defined + java/cs : added `-c-arg` to add C#/Java compiler arguments + cpp : inititial implementation of cppia scripting + + Bugfixes: + + all : fixed nullability of abstracts over functions + all : fixed some equality checks between UInt and Int + all : fixed rare issue with abstract casts + all : fixed some internal code which relied on unspecified evaluation order + all : fixed exhaustiveness checks involving guards + all : fixed issue involving recursively constrained type parameters and @:generic + all : fixed type inference issue in map literals + all : fixed type inference issue when calling abstract method from within the abstract + all : fixed several abstract variance issues + all : fixed DCE issues with interface properties + all : fixed variance issue with function variables and dynamic methods on interfaces + all : fixed pattern matching on empty arrays that are typed as Dynamic + all : fixed various @:generic issues + all : fixed default cases on @:enum abstract being omitted + all : fixed various expression positions + all : disallowed break/continue in closures in loops + all : disallowed inline functions in value places + all : fixed parsing of cast followed by parentheses + all : fixed resource naming in case of invalid file system characters + all : fixed issue with inlined array declarations with field access + cpp : fixed issue with the side-effect handler + cpp : fixed issue with NativeArray in --no-inline mode + php : fixed issue with invalid references for closures in for-loops + php : fixed Reflect.compare and string comparison for numeric strings + cs/java : fixed various issues with -java-lib and -net-lib. + cs/java : added @:libType to skip checking on -java-lib / -net-lib types + cs/java : compilation server now works with C#/Java [experimental support] + cs : fixed Type.enumIndex / switch on C# native enums + cs : fixed reflection on COM types + java : fixed sys.net.Socket server implementation + spod : various fixes - working now on cpp, java, neko, php and c# + cpp : improved boot order, with enums constants first + + General improvements and optimizations: + + all : disallowed using `super` in value positions + all : check exhaustiveness of explicit Null types + all : resolve unqualified identifiers to @:enum abstract constructors + all : determine @:generic type parameters from constructor call if possible + all : properly disallowed field redefinition in extending interface + all : properly disallowed leading zeroes for Int and Float literals + all : allowed variance on interface variables + all : allowed pattern matching on arrays if they are typed as Dynamic + all : allowed pattern matching on fields of parent classes + all : -D doc-gen no longer implies -dce no + all : allowed matching against null on any enum instance + flash/js: optimized haxe.ds.StringMap + neko : create output directory if it does not exist + js : inline Math methods and fields + cs/java : optimized Reflect.fields on dynamic structures + cs/java : haxe will now clear output directory of old files (use -D keep-old-output to keep them) + cs : optimized field lookup structure + cs : optimized casting of parametrized types + cs : beautify c# code output + cs : added `cs.Flags` to manipulate C# enums that can be also flags + xml : improved documentation generation and fixed missing entity escaping + cpp : property access via Dynamic variables now requires property to be declared with @:nativeProperty + cpp : allow injection of code from relative paths using @:sourceFile and @:cppInclude + cpp : stronger typing of native functions via cpp.Function + cpp.Callable + cpp : moved 'Class' implementation to hx namespace to improve objective C interaction + cpp : added file_extension define to change the output filename extension (eg, ".mm") + cpp : added pre-calculated hashes to string constants to allow faster lookups + cpp : map implementation allows strongly typed interactions in some cases (avoids boxing) + cpp : added native WeakMap implementation + cpp : put each resource into own cpp file to allow more data/smaller files + + Standard Library: + + all : added typed arrays to haxe.io package + all : added haxe.ds.Either + all : added haxe.extern.Rest type for representing "rest" arguments in extern method signatures + all : added haxe.extern.EitherType abstract type for dealing with externs for dynamic targets + all : added haxe.DynamicAccess type for working with dynamic anonymous structures using a Map-like interface + all : [breaking] changed haxe.ds.Vector.get to return T instead of Null + all : added haxe.macro.Compiler.addGlobalMetadata + all : changed haxe.Int64 to be an abstract type instead of a class + js : updated HTML externs + + Macro features and changes: + + macro : added Context.getLocalTVars + macro : added TypedExprTools.iter + macro : added Context.getCallArguments + macro : changed @:genericBuild macros to prefer ComplexType returns + macro : [breaking] extended TAnonymous structures now have AExtend status instead of AClosed + macro : added Context.getDefines + macro : fixed file_seek from end (position was inversed) + macro : added Context.storeTypedExpr + macro : allowed type name reification + + Deprecations: + + all : deprecated structurally extending classes and interfaces + sys : Sys.command shell special chars (&|<>#;*?(){}$) are now properly escaped + java/cs : Lib.nativeType is now renamed to Lib.getNativeType + +2014-04-13: 3.1.3 + + Bugfixes: + + all : fixed handling of abstract variance + flash : ensure correct endianess in haxe.io.BytesBuffer + cpp : fixed issue involving class paths with spaces + php : fixed >>> + macro : fixed haxe.macro.Compiler.keep + + General improvements and optimizations: + + all : give @:deprecated warnings by default, allow -D no-deprecation-warnings + cpp : optimized Vector implementation + + Standard Library: + + all : renamed Bytes.readDouble/Float to getDouble/Float to avoid inheritance issues + all : deprecated Bytes.readString in favor of getString + all : added pretty-printing to haxe.format.JsonPrinter (and haxe.Json) + +2014-03-29: 3.1.2 + + Bugfixes: + + all : disallowed spaces between >>, >>>, >>= and >>>= + all : fix branching issue when switching on Dynamic values with only one case + all : added missing abstract cast call when checking for equality + all : fixed member fields initializations on parent classes that have no constructor + all : fixed toString usage of abstracts which are argument to Std.string + flash : avoid rare FP 12 PPAPI JIT crash + cpp : fixed bug in side-effect handler which caused incorrect behavior of while loops + js : fixed missing print function for enum values with DCE + macro : make sure member field initializations are respected + + General improvements and optimizations: + + all : cached file exist checks to speed up compilations with a lot of class paths + all : improved completion related to super class fields + all : allowed iterating on abstract which have get_length and @:arrayAccess fields + js : improved Type.allEnums implementation to avoid issues with obfuscation + + Standard Library: + + all : added haxe.io.Bytes.readDouble/Float + all : added haxe.io.BytesBuffer.addString/Float/Double + +2014-03-15: 3.1.1 + + New features: + + all : added -D deprecation-warnings + all : allowed \u escape sequences in strings + cs : implemented haxe.CallStack + + Bugfixes: + + all : fixed wrong handling of "" and null in haxe.io.Path.join + all : fixed invalid cast-to-self generation on some abstracts + all : removed @:to Dynamic from UInt to avoid issues in the Map selection algorithm + all : fixed various issues with UInt + all : fixed position setter in haxe.io.BytesInput + all : fixed various issues with member/static extension macros + flash : fixed invalid override involving single-constraint type parameters + flash8 : fixed various bugs + js : fixed a problem with Std.string(null) being optimized incorrectly + js : fixed custom generators + cpp : dealt with string literals that are too long for MSVC + cs : fixed various issues with -net-lib + +2014-03-04: 3.1.0 + + New features: + + all : allowed null-patterns in pattern matching + all : allowed extractors in pattern matching using => syntax + all : allowed extending generic type parameters + all : allowed (expr : type) syntax (ECheckType) + all : allowed @:enum and @:forward on abstracts + all : allowed using abstracts as static extension + all : allowed Class.new + all : added EnumValue.match + all : allow multiple structural extension using { > T1, > T2, fields } + all : inline array and structure declarations if possible + cs : added -net-lib + cs : support for native delegates + cs : support for attributes + cs : support for events + + Standard Library: + + all : support abstract types in haxe.rtti.XmlParser + all : added Std.instance + all : added length field to BytesBuffer, BytesOutput, BytesInput and StringBuf + all : added UInt for all targets + all : added Array.indexOf and Array.lastIndexOf + all : added haxe.xml.Printer + all : added haxe.Int32 as abstract type + all : added haxe.format.JsonParser/Printer + + General improvements and optimizations: + + all : optimized pattern matching output + all : allowed recursive type parameter constraints + all : improved support of custom @:coreType abstracts + all : evaluate conditional expressions in @:require + all : improved inline constructors by detecting more cases where it can be applied + js : improved inlining + js : always use JSON extern (compile with -D old-browser to disable) + js : added -D js-flatten + js : added -D js-es5 + cpp : improved side-effect detection + + Bugfixes: + + all : inlining a parameter which has side effects will not remove it even if not used + all : implemented constraints check on enum and enum field type parameters + all : fixed memory leak in compilation server and optimized caching in general + all : fixed issue with invalid lowercase class name in Windows completion + flash : fixed font embedding with UTF8 chars + flash : give error if non-nullable basic types are skipped in a call + flash : give error if assigned parent class field values would be overwritten by super() + + Macro features and changes: + + macro : add Context.onAfterGenerate + macro : add Context.typeExpr + macro : add Context.getExpectedType + macro : add ExprTools.getValue + macro : allowed $v{(c:Float|Int|String)} + macro : resolve error line number in external files + macro : rewrote macros used as static extension + macro : exposed typed AST + macro : added @:genericBuild + macro : [breaking] first argument of ComplexType.TExtend is now Array instead of TypePath + macro : improved expression printing + +2013-09-25: 3.0.1 + all : minor DCE bug fix + 2013-05-25: 3.0.0 all : added haxe.ds.BalancedTree all : added haxe.ds.EnumValueMap @@ -280,7 +576,7 @@ all : added --dead-code-elimination, removes unused functions from the output (beta feature could not make in the final release) all : added @:keep to prevent --dead-code-elimination of class/method - flash9 : fixed issues with loading a haXe SWF (boot_XXXX class extends flash.Boot) + flash9 : fixed issues with loading a Haxe SWF (boot_XXXX class extends flash.Boot) all : allow to inline override methods (if the superclass method is not inlined already) all : fixed escape sequences in literal regular expressions flash9 : fixed Xml.setNodeValue @@ -319,7 +615,7 @@ compiler : fixed -no-opt flash : allow several -swf-lib no longer support automatic creation of classes for f8 swfs in f9 mode - classes defined in f9 swf are not redefinable in haXe code (use extern) + classes defined in f9 swf are not redefinable in Haxe code (use extern) flash9 : allow direct access and completion with classes defined in -swf-lib's flash9 : remove imported libraries debug infos when not compiled with -debug all : only display errors with --display if no completion matched @@ -347,7 +643,7 @@ php : removed eval() everywhere and simplified _hx_lambda php : fixed return type for Std.string() with integers and floats php : fixed php.Lib.rethrow - all : added custom haXe serialization + all : added custom Haxe serialization php : aligned php.Web.parseMultipart signature with neko implementation cpp : Added source location and stack dump for errors in debug mode cpp : Remapped more keywords @@ -460,8 +756,8 @@ php: fixed String.charCodeAt php: minor optimization (removed foreach from std code) php: implemented haxe.Stack - php: changed exception handler to use haXe call stack - php: changed special vars to use the » prefix instead of __ + php: changed exception handler to use Haxe call stack + php: changed special vars to use the '\xBB' prefix instead of __ php: fixed use of reserved keywords for var names php: List iterator is now class based (faster) php: fixed behavior of class variables having assigned functions @@ -477,16 +773,16 @@ bugfix for flash.display.BitmapDataChannel and GraphicsPathCommand (allow inline static) resolve environment variable in -cmd commands added flash.Vector.indexOf and lastIndexOf - fixed bug in interfaces that define the method toString (haXe/PHP) + fixed bug in interfaces that define the method toString (Haxe/PHP) fixed bug in haxe.io.BytesInput.readBytes in Flash9 (was throwing Eof if full buffer can't be readed) fixed implements/extends special classes when they are imported StringBuf now uses an array for JS implementation (around same on FF, faster on IE) - fixed assignment of field length in anonym objects (haXe/PHP) + fixed assignment of field length in anonym objects (Haxe/PHP) fixed addEventListener typing for flash9 fixed __vector__ generation for AS3 target fix with inline functions : position is now the inserted position and not the original one (better error reporting) added SWC output support - fixed issues with unset of values in for loops and executing blocks that return functions (haXe/PHP) + fixed issues with unset of values in for loops and executing blocks that return functions (Haxe/PHP) "throw" type is now Unknown instead of Dynamic (prevent type-hole in "if A else if B else throw") added __foreach__ for flash9/as3 fixed f9 verify error with different kind of functions @@ -511,7 +807,7 @@ speedup Array.remove on flash9/js 2008-11-23: 2.02 - Std.is(MyInterface, Class) now returns true (haXe/PHP) + Std.is(MyInterface, Class) now returns true (Haxe/PHP) php arrays are wrapped into _hx_array instances, fixes issues with references (array cast, access out of bounds ...) removed untested php classes (php.DBase, php.IniHash) added -D use_rtti_doc @@ -564,12 +860,12 @@ always use full classes paths for genAS3 prevent different get/set property accesses when implementing an interface fixed assign of dynamicfunction references in PHP - haXe/PHP now generates code for extern classes __init__ + Haxe/PHP now generates code for extern classes __init__ added strings literal support in haxe.Template - fixed Process arguments and exitCode() in haXe/PHP - fixed hierarchy problem for classes with the name from different packages haXe/PHP + fixed Process arguments and exitCode() in Haxe/PHP + fixed hierarchy problem for classes with the name from different packages Haxe/PHP php.db.Mysql now throws an exception when tries to connect to an unexistant DB - fixed blocks in if statements for haXe/PHP + fixed blocks in if statements for Haxe/PHP added php check on the full hierarchy for colliding names added support for "g" modifier in EReg for PHP PHP now generates __toString for classes that have toString defined @@ -591,7 +887,7 @@ fixed current package bug in inherited constructor type delayed type-parameter constraints check (allow mutual rec extends for SPOD) improved unclosed macro error reporting - haXe/PHP integration + Haxe/PHP integration renamed NekoSocketConnection to SyncSocketConnection (php support) fixes in genAs3 fix for flash9 : always coerce call return type @@ -769,7 +1065,7 @@ optional enums arguments on Flash9 are now automatically Null forbid usage of type parameters in static functions fixed Std.int with negative numbers - fixed some F9 issues with haXe-specific Array, Date and Math methods + fixed some F9 issues with Haxe-specific Array, Date and Math methods used AS3 namespace for F9 Array and String instance methods fixed F9 with uninitialized integer registers fixed F9 + operator with Dynamic/Null operands @@ -781,7 +1077,7 @@ fixed stack overflow with static setter fixed package completion bug when -cp points to an not existing dir fix duplicate sandboxes tags with -swf - __resolve in haXe Remoting is now public + __resolve in Haxe Remoting is now public 2007-07-25: 1.14 fixed no error when invalid "catch" expression @@ -961,7 +1257,7 @@ fixed scope bug in try/catch with Flash9 added remoting over XMLSocket and LocalConnection for Flash9 fixed Std.is(*,null) = false - allowed >64K haXe/neko strings + allowed >64K Haxe/neko strings -debug and stack traces support for Flash and JS minor changes in xml output @@ -995,7 +1291,7 @@ some method renamed in neko.FileSystem. added neko.remoting.Server.setLogger fixed bug in haxe.Serializer on neko (was preventing List serialization) - fixed bugs in haXe.Unserializer on neko (invalid enum tag & pbs with UTF8 strings) + fixed bugs in Haxe.Unserializer on neko (invalid enum tag & pbs with UTF8 strings) fixed sqlite escape & quote , added BOOL support allowed direct property access in getter/setter (prevent rec loop) allowed event-driven neko http requests diff --git a/doc/CONTRIB.txt b/extra/CONTRIB.txt similarity index 98% rename from doc/CONTRIB.txt rename to extra/CONTRIB.txt index eb519d63e9a0c5d60d2f6c19a156c6110e7bf8af..7c594ada272090f374b6b44dc1bccd24d81ce487 100644 --- a/doc/CONTRIB.txt +++ b/extra/CONTRIB.txt @@ -1,25 +1,25 @@ -Contributor License Agreement : - -You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the project Haxe : - -1) Definitions - - "Contribution" : any source code, documentation, including any modifications or additions to an existing work that is intentionally submitted by You to the Haxe Foundation for inclusion in, or documentation of, any of the products managed and maintained by the Haxe Foundation. - - "Submitted" means any form or electronic, verbal or written communication, including but not limited to communication on electronic mailing lists, source code control systems and issue tracking system that are managed by, or on behalf of, the Haxe Foundation for the purpose of improving Haxe. - -2) Grant of Copyright License. Subject to the terms and conditions of this Grant, You hereby grant to the Haxe Foundation and to recipients of software distributed by the Haxe Foundation a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. - -3) You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to the Haxe Foundation, or that your employer has executed a separate Corporate Contributor License Grant with the Haxe Foundation. - -4) You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. - -5) You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. - -Full Name : -Email : -Mailing Address : -Country : - - +Contributor License Agreement : + +You accept and agree to the following terms and conditions for Your present and future Contributions submitted to the project Haxe : + +1) Definitions + + "Contribution" : any source code, documentation, including any modifications or additions to an existing work that is intentionally submitted by You to the Haxe Foundation for inclusion in, or documentation of, any of the products managed and maintained by the Haxe Foundation. + + "Submitted" means any form or electronic, verbal or written communication, including but not limited to communication on electronic mailing lists, source code control systems and issue tracking system that are managed by, or on behalf of, the Haxe Foundation for the purpose of improving Haxe. + +2) Grant of Copyright License. Subject to the terms and conditions of this Grant, You hereby grant to the Haxe Foundation and to recipients of software distributed by the Haxe Foundation a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. + +3) You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to the Haxe Foundation, or that your employer has executed a separate Corporate Contributor License Grant with the Haxe Foundation. + +4) You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. + +5) You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +Full Name : +Email : +Mailing Address : +Country : + + Signature: \ No newline at end of file diff --git a/doc/EnvVarUpdate.nsh b/extra/EnvVarUpdate.nsh similarity index 96% rename from doc/EnvVarUpdate.nsh rename to extra/EnvVarUpdate.nsh index 839d6a0206281b02147dd84061e4b2ccd9e7e24d..39682000c358ec2f09bbd7f6ad953bf1fd950b2a 100644 --- a/doc/EnvVarUpdate.nsh +++ b/extra/EnvVarUpdate.nsh @@ -1,327 +1,327 @@ -/** - * EnvVarUpdate.nsh - * : Environmental Variables: append, prepend, and remove entries - * - * WARNING: If you use StrFunc.nsh header then include it before this file - * with all required definitions. This is to avoid conflicts - * - * Usage: - * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString" - * - * Credits: - * Version 1.0 - * * Cal Turney (turnec2) - * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this - * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar, - * WriteEnvStr, and un.DeleteEnvStr - * * Diego Pedroso (deguix) for StrTok - * * Kevin English (kenglish_hi) for StrContains - * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry - * (dandaman32) for StrReplace - * - * Version 1.1 (compatibility with StrFunc.nsh) - * * techtonik - * - * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries - * - */ - - -!ifndef ENVVARUPDATE_FUNCTION -!define ENVVARUPDATE_FUNCTION -!verbose push -!verbose 3 -!include "LogicLib.nsh" -!include "WinMessages.NSH" -!include "StrFunc.nsh" - -; ---- Fix for conflict if StrFunc.nsh is already includes in main file ----------------------- -!macro _IncludeStrFunction StrFuncName - !ifndef ${StrFuncName}_INCLUDED - ${${StrFuncName}} - !endif - !ifndef Un${StrFuncName}_INCLUDED - ${Un${StrFuncName}} - !endif - !define un.${StrFuncName} "${Un${StrFuncName}}" -!macroend - -!insertmacro _IncludeStrFunction StrTok -!insertmacro _IncludeStrFunction StrStr -!insertmacro _IncludeStrFunction StrRep - -; ---------------------------------- Macro Definitions ---------------------------------------- -!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString - Push "${EnvVarName}" - Push "${Action}" - Push "${RegLoc}" - Push "${PathString}" - Call EnvVarUpdate - Pop "${ResultVar}" -!macroend -!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' - -!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString - Push "${EnvVarName}" - Push "${Action}" - Push "${RegLoc}" - Push "${PathString}" - Call un.EnvVarUpdate - Pop "${ResultVar}" -!macroend -!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' -; ---------------------------------- Macro Definitions end------------------------------------- - -;----------------------------------- EnvVarUpdate start---------------------------------------- -!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' -!define hkcu_current_user 'HKCU "Environment"' - -!macro EnvVarUpdate UN - -Function ${UN}EnvVarUpdate - - Push $0 - Exch 4 - Exch $1 - Exch 3 - Exch $2 - Exch 2 - Exch $3 - Exch - Exch $4 - Push $5 - Push $6 - Push $7 - Push $8 - Push $9 - Push $R0 - - /* After this point: - ------------------------- - $0 = ResultVar (returned) - $1 = EnvVarName (input) - $2 = Action (input) - $3 = RegLoc (input) - $4 = PathString (input) - $5 = Orig EnvVar (read from registry) - $6 = Len of $0 (temp) - $7 = tempstr1 (temp) - $8 = Entry counter (temp) - $9 = tempstr2 (temp) - $R0 = tempChar (temp) */ - - ; Step 1: Read contents of EnvVarName from RegLoc - ; - ; Check for empty EnvVarName - ${If} $1 == "" - SetErrors - DetailPrint "ERROR: EnvVarName is blank" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Check for valid Action - ${If} $2 != "A" - ${AndIf} $2 != "P" - ${AndIf} $2 != "R" - SetErrors - DetailPrint "ERROR: Invalid Action - must be A, P, or R" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ${If} $3 == HKLM - ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 - ${ElseIf} $3 == HKCU - ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 - ${Else} - SetErrors - DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Check for empty PathString - ${If} $4 == "" - SetErrors - DetailPrint "ERROR: PathString is blank" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Make sure we've got some work to do - ${If} $5 == "" - ${AndIf} $2 == "R" - SetErrors - DetailPrint "$1 is empty - Nothing to remove" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Step 2: Scrub EnvVar - ; - StrCpy $0 $5 ; Copy the contents to $0 - ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or - ; after the last one are not removed here but instead in Step 3) - ${If} $0 != "" ; If EnvVar is not empty ... - ${Do} - ${${UN}StrStr} $7 $0 " ;" - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' - ${Loop} - ${Do} - ${${UN}StrStr} $7 $0 "; " - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' - ${Loop} - ${Do} - ${${UN}StrStr} $7 $0 ";;" - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 ";;" ";" - ${Loop} - - ; Remove a leading or trailing semicolon from EnvVar - StrCpy $7 $0 1 0 - ${If} $7 == ";" - StrCpy $0 $0 "" 1 ; Change ';' to '' - ${EndIf} - StrLen $6 $0 - IntOp $6 $6 - 1 - StrCpy $7 $0 1 $6 - ${If} $7 == ";" - StrCpy $0 $0 $6 ; Change ';' to '' - ${EndIf} - ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug - ${EndIf} - - /* Step 3. Remove all instances of the target path/string (even if "A" or "P") - $6 = bool flag (1 = found and removed PathString) - $7 = a string (e.g. path) delimited by semicolon(s) - $8 = entry counter starting at 0 - $9 = copy of $0 - $R0 = tempChar */ - - ${If} $5 != "" ; If EnvVar is not empty ... - StrCpy $9 $0 - StrCpy $0 "" - StrCpy $8 0 - StrCpy $6 0 - - ${Do} - ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter - - ${If} $7 == "" ; If we've run out of entries, - ${ExitDo} ; were done - ${EndIf} ; - - ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) - ${Do} - StrCpy $R0 $7 1 - ${If} $R0 != " " - ${ExitDo} - ${EndIf} - StrCpy $7 $7 "" 1 ; Remove leading space - ${Loop} - ${Do} - StrCpy $R0 $7 1 -1 - ${If} $R0 != " " - ${ExitDo} - ${EndIf} - StrCpy $7 $7 -1 ; Remove trailing space - ${Loop} - ${If} $7 == $4 ; If string matches, remove it by not appending it - StrCpy $6 1 ; Set 'found' flag - ${ElseIf} $7 != $4 ; If string does NOT match - ${AndIf} $0 == "" ; and the 1st string being added to $0, - StrCpy $0 $7 ; copy it to $0 without a prepended semicolon - ${ElseIf} $7 != $4 ; If string does NOT match - ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, - StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon - ${EndIf} ; - - IntOp $8 $8 + 1 ; Bump counter - ${Loop} ; Check for duplicates until we run out of paths - ${EndIf} - - ; Step 4: Perform the requested Action - ; - ${If} $2 != "R" ; If Append or Prepend - ${If} $6 == 1 ; And if we found the target - DetailPrint "Target is already present in $1. It will be removed and" - ${EndIf} - ${If} $0 == "" ; If EnvVar is (now) empty - StrCpy $0 $4 ; just copy PathString to EnvVar - ${If} $6 == 0 ; If found flag is either 0 - ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) - DetailPrint "$1 was empty and has been updated with the target" - ${EndIf} - ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), - StrCpy $0 $0;$4 ; append PathString - ${If} $6 == 1 - DetailPrint "appended to $1" - ${Else} - DetailPrint "Target was appended to $1" - ${EndIf} - ${Else} ; If Prepend (and EnvVar is not empty), - StrCpy $0 $4;$0 ; prepend PathString - ${If} $6 == 1 - DetailPrint "prepended to $1" - ${Else} - DetailPrint "Target was prepended to $1" - ${EndIf} - ${EndIf} - ${Else} ; If Action = Remove - ${If} $6 == 1 ; and we found the target - DetailPrint "Target was found and removed from $1" - ${Else} - DetailPrint "Target was NOT found in $1 (nothing to remove)" - ${EndIf} - ${If} $0 == "" - DetailPrint "$1 is now empty" - ${EndIf} - ${EndIf} - - ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change - ; - ClearErrors - ${If} $3 == HKLM - WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section - ${ElseIf} $3 == HKCU - WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section - ${EndIf} - - IfErrors 0 +4 - MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" - DetailPrint "Could not write updated $1 to $3" - Goto EnvVarUpdate_Restore_Vars - - ; "Export" our change - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - - EnvVarUpdate_Restore_Vars: - ; - ; Restore the user's variables and return ResultVar - Pop $R0 - Pop $9 - Pop $8 - Pop $7 - Pop $6 - Pop $5 - Pop $4 - Pop $3 - Pop $2 - Pop $1 - Push $0 ; Push my $0 (ResultVar) - Exch - Pop $0 ; Restore his $0 - -FunctionEnd - -!macroend ; EnvVarUpdate UN -!insertmacro EnvVarUpdate "" -!insertmacro EnvVarUpdate "un." -;----------------------------------- EnvVarUpdate end---------------------------------------- - -!verbose pop -!endif +/** + * EnvVarUpdate.nsh + * : Environmental Variables: append, prepend, and remove entries + * + * WARNING: If you use StrFunc.nsh header then include it before this file + * with all required definitions. This is to avoid conflicts + * + * Usage: + * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString" + * + * Credits: + * Version 1.0 + * * Cal Turney (turnec2) + * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this + * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar, + * WriteEnvStr, and un.DeleteEnvStr + * * Diego Pedroso (deguix) for StrTok + * * Kevin English (kenglish_hi) for StrContains + * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry + * (dandaman32) for StrReplace + * + * Version 1.1 (compatibility with StrFunc.nsh) + * * techtonik + * + * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries + * + */ + + +!ifndef ENVVARUPDATE_FUNCTION +!define ENVVARUPDATE_FUNCTION +!verbose push +!verbose 3 +!include "LogicLib.nsh" +!include "WinMessages.NSH" +!include "StrFunc.nsh" + +; ---- Fix for conflict if StrFunc.nsh is already includes in main file ----------------------- +!macro _IncludeStrFunction StrFuncName + !ifndef ${StrFuncName}_INCLUDED + ${${StrFuncName}} + !endif + !ifndef Un${StrFuncName}_INCLUDED + ${Un${StrFuncName}} + !endif + !define un.${StrFuncName} "${Un${StrFuncName}}" +!macroend + +!insertmacro _IncludeStrFunction StrTok +!insertmacro _IncludeStrFunction StrStr +!insertmacro _IncludeStrFunction StrRep + +; ---------------------------------- Macro Definitions ---------------------------------------- +!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' + +!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call un.EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' +; ---------------------------------- Macro Definitions end------------------------------------- + +;----------------------------------- EnvVarUpdate start---------------------------------------- +!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' +!define hkcu_current_user 'HKCU "Environment"' + +!macro EnvVarUpdate UN + +Function ${UN}EnvVarUpdate + + Push $0 + Exch 4 + Exch $1 + Exch 3 + Exch $2 + Exch 2 + Exch $3 + Exch + Exch $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R0 + + /* After this point: + ------------------------- + $0 = ResultVar (returned) + $1 = EnvVarName (input) + $2 = Action (input) + $3 = RegLoc (input) + $4 = PathString (input) + $5 = Orig EnvVar (read from registry) + $6 = Len of $0 (temp) + $7 = tempstr1 (temp) + $8 = Entry counter (temp) + $9 = tempstr2 (temp) + $R0 = tempChar (temp) */ + + ; Step 1: Read contents of EnvVarName from RegLoc + ; + ; Check for empty EnvVarName + ${If} $1 == "" + SetErrors + DetailPrint "ERROR: EnvVarName is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for valid Action + ${If} $2 != "A" + ${AndIf} $2 != "P" + ${AndIf} $2 != "R" + SetErrors + DetailPrint "ERROR: Invalid Action - must be A, P, or R" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ${If} $3 == HKLM + ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 + ${ElseIf} $3 == HKCU + ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 + ${Else} + SetErrors + DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for empty PathString + ${If} $4 == "" + SetErrors + DetailPrint "ERROR: PathString is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Make sure we've got some work to do + ${If} $5 == "" + ${AndIf} $2 == "R" + SetErrors + DetailPrint "$1 is empty - Nothing to remove" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Step 2: Scrub EnvVar + ; + StrCpy $0 $5 ; Copy the contents to $0 + ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or + ; after the last one are not removed here but instead in Step 3) + ${If} $0 != "" ; If EnvVar is not empty ... + ${Do} + ${${UN}StrStr} $7 $0 " ;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 "; " + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' + ${Loop} + ${Do} + ${${UN}StrStr} $7 $0 ";;" + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${${UN}StrRep} $0 $0 ";;" ";" + ${Loop} + + ; Remove a leading or trailing semicolon from EnvVar + StrCpy $7 $0 1 0 + ${If} $7 == ";" + StrCpy $0 $0 "" 1 ; Change ';' to '' + ${EndIf} + StrLen $6 $0 + IntOp $6 $6 - 1 + StrCpy $7 $0 1 $6 + ${If} $7 == ";" + StrCpy $0 $0 $6 ; Change ';' to '' + ${EndIf} + ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug + ${EndIf} + + /* Step 3. Remove all instances of the target path/string (even if "A" or "P") + $6 = bool flag (1 = found and removed PathString) + $7 = a string (e.g. path) delimited by semicolon(s) + $8 = entry counter starting at 0 + $9 = copy of $0 + $R0 = tempChar */ + + ${If} $5 != "" ; If EnvVar is not empty ... + StrCpy $9 $0 + StrCpy $0 "" + StrCpy $8 0 + StrCpy $6 0 + + ${Do} + ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter + + ${If} $7 == "" ; If we've run out of entries, + ${ExitDo} ; were done + ${EndIf} ; + + ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) + ${Do} + StrCpy $R0 $7 1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 "" 1 ; Remove leading space + ${Loop} + ${Do} + StrCpy $R0 $7 1 -1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 -1 ; Remove trailing space + ${Loop} + ${If} $7 == $4 ; If string matches, remove it by not appending it + StrCpy $6 1 ; Set 'found' flag + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 == "" ; and the 1st string being added to $0, + StrCpy $0 $7 ; copy it to $0 without a prepended semicolon + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, + StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon + ${EndIf} ; + + IntOp $8 $8 + 1 ; Bump counter + ${Loop} ; Check for duplicates until we run out of paths + ${EndIf} + + ; Step 4: Perform the requested Action + ; + ${If} $2 != "R" ; If Append or Prepend + ${If} $6 == 1 ; And if we found the target + DetailPrint "Target is already present in $1. It will be removed and" + ${EndIf} + ${If} $0 == "" ; If EnvVar is (now) empty + StrCpy $0 $4 ; just copy PathString to EnvVar + ${If} $6 == 0 ; If found flag is either 0 + ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) + DetailPrint "$1 was empty and has been updated with the target" + ${EndIf} + ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), + StrCpy $0 $0;$4 ; append PathString + ${If} $6 == 1 + DetailPrint "appended to $1" + ${Else} + DetailPrint "Target was appended to $1" + ${EndIf} + ${Else} ; If Prepend (and EnvVar is not empty), + StrCpy $0 $4;$0 ; prepend PathString + ${If} $6 == 1 + DetailPrint "prepended to $1" + ${Else} + DetailPrint "Target was prepended to $1" + ${EndIf} + ${EndIf} + ${Else} ; If Action = Remove + ${If} $6 == 1 ; and we found the target + DetailPrint "Target was found and removed from $1" + ${Else} + DetailPrint "Target was NOT found in $1 (nothing to remove)" + ${EndIf} + ${If} $0 == "" + DetailPrint "$1 is now empty" + ${EndIf} + ${EndIf} + + ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change + ; + ClearErrors + ${If} $3 == HKLM + WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section + ${ElseIf} $3 == HKCU + WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section + ${EndIf} + + IfErrors 0 +4 + MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" + DetailPrint "Could not write updated $1 to $3" + Goto EnvVarUpdate_Restore_Vars + + ; "Export" our change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + EnvVarUpdate_Restore_Vars: + ; + ; Restore the user's variables and return ResultVar + Pop $R0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Push $0 ; Push my $0 (ResultVar) + Exch + Pop $0 ; Restore his $0 + +FunctionEnd + +!macroend ; EnvVarUpdate UN +!insertmacro EnvVarUpdate "" +!insertmacro EnvVarUpdate "un." +;----------------------------------- EnvVarUpdate end---------------------------------------- + +!verbose pop +!endif diff --git a/doc/ImportAll.hx b/extra/ImportAll.hx similarity index 93% rename from doc/ImportAll.hx rename to extra/ImportAll.hx index 3b279f67c7cddc125743adda7d55d12dddc9500a..b4a19544e6cd48d747ad679614f99c2d8bf66901 100644 --- a/doc/ImportAll.hx +++ b/extra/ImportAll.hx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, The haXe Project Contributors + * Copyright (c) 2005, The Haxe Project Contributors * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -40,18 +40,16 @@ class ImportAll { if( !Context.defined("js") ) return; case "cpp": if( !Context.defined("cpp") ) return; - case "flash8": - if( !Context.defined("flash") || Context.defined("flash9") ) return; case "flash": if( !Context.defined("flash9") ) return; - case "mt","mtwin": - return; case "sys": if( !Context.defined("neko") && !Context.defined("php") && !Context.defined("cpp") ) return; case "java": if( !Context.defined("java") ) return; case "cs": if( !Context.defined("cs") ) return; + case "python": + if( !Context.defined("python") ) return; case "tools": return; case "build-tool": @@ -74,8 +72,6 @@ class ImportAll { var full = (pack == "") ? file : pack + "." + file; if( StringTools.endsWith(file, ".hx") ) { var cl = full.substr(0, full.length - 3); - if( StringTools.startsWith(cl,"flash8.") ) - cl = "flash."+cl.substr(7); switch( cl ) { case "ImportAll", "neko.db.MacroManager": continue; case "haxe.TimerQueue": if( Context.defined("neko") || Context.defined("php") || Context.defined("cpp") ) continue; @@ -84,6 +80,7 @@ class ImportAll { case "haxe.macro.ExampleJSGenerator","haxe.macro.Context", "haxe.macro.Compiler": if( !Context.defined("neko") ) continue; case "haxe.remoting.SocketWrapper": if( !Context.defined("flash") ) continue; case "haxe.remoting.SyncSocketConnection": if( !(Context.defined("neko") || Context.defined("php") || Context.defined("cpp")) ) continue; + case "sys.db.Sqlite" | "sys.db.Mysql" | "cs.db.AdoNet": continue; } Context.getModule(cl); } else if( sys.FileSystem.isDirectory(p + "/" + file) ) diff --git a/doc/LICENSE.txt b/extra/LICENSE.txt similarity index 100% rename from doc/LICENSE.txt rename to extra/LICENSE.txt diff --git a/doc/all.hxml b/extra/all.hxml similarity index 87% rename from doc/all.hxml rename to extra/all.hxml index 8ec5dc88e81ad53d30e0d62b7cd3b4b26283ac27..e9756dcc3d3ebf43c7f1cca954cf88ed25e1c6d1 100644 --- a/doc/all.hxml +++ b/extra/all.hxml @@ -8,13 +8,6 @@ --next --swf all.swf --swf-version 8 --xml flash8.xml --D flash_lite - ---next - -js all.js -xml js.xml @@ -47,6 +40,10 @@ -xml cs.xml -D xmldoc +--next +-python all_python +-xml python.xml + --next -xml cross.xml diff --git a/doc/all.hxproj b/extra/all.hxproj similarity index 96% rename from doc/all.hxproj rename to extra/all.hxproj index 568981f18141d5aaa128fefd09f343843ec0f34e..5652970604c3759846e6abedbd27956b293f60ec 100644 --- a/doc/all.hxproj +++ b/extra/all.hxproj @@ -1,55 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - haxe all.hxml - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + haxe all.hxml + + + + + + + \ No newline at end of file diff --git a/extra/clean-whitespace b/extra/clean-whitespace new file mode 100755 index 0000000000000000000000000000000000000000..db2e10ac511b0f3c9d3655769b07328b367602bf --- /dev/null +++ b/extra/clean-whitespace @@ -0,0 +1,6 @@ +#!/bin/sh +# +# Remove trailing whitespace from Haxe files + +# Exclude generated js.html.* for now +find -path ./std/js/html -prune -o -name '*.hx' -print0 | xargs -0 perl -pi -e "s/[ \t]+$//" diff --git a/extra/extract.hxml b/extra/extract.hxml new file mode 100644 index 0000000000000000000000000000000000000000..4ae6de90f54bee21268cc3ae1fb7f9a0b9719660 --- /dev/null +++ b/extra/extract.hxml @@ -0,0 +1,6 @@ +-debug +-swf-lib library.swf +-swf test.swf +-swf-version 15 +--macro patchTypes("../extra/extract.patch") +--gen-hx-classes \ No newline at end of file diff --git a/doc/extract.patch b/extra/extract.patch similarity index 97% rename from doc/extract.patch rename to extra/extract.patch index d94524f15c4afd722c2cc65b212e650f1f2cb83f..93f847f36966291245339e5c4b8316219b73eb71 100644 --- a/doc/extract.patch +++ b/extra/extract.patch @@ -1,1224 +1,1236 @@ -// types patches configuration for playerglobal.swc - -flash.display.DisplayObject.filters : Array; - --flash.accessibility.Accessibility.new -@:require(flash10_1) flash.accessibility.ISearchableText -@:require(flash10_1) flash.accessibility.ISimpleTextSelection - -@:require(flash10_1) flash.automation.ActionGenerator -@:require(flash10_1) flash.automation.AutomationAction -@:require(flash10_1) flash.automation.Configuration -@:require(flash10_1) flash.automation.KeyboardAutomationAction -@:require(flash10_1) flash.automation.MouseAutomationAction -@:require(flash10_1) flash.automation.StageCapture -@:require(flash10_1) flash.automation.StageCaptureEvent - --flash.desktop.Clipboard.new -flash.desktop.Clipboard.formats : Array; -flash.desktop.Clipboard.$format : ClipboardFormats; -flash.desktop.Clipboard.$transferMode : ClipboardTransferMode; - -enum flash.desktop.ClipboardFormats; -enum flash.desktop.ClipboardTransferMode; - -enum flash.display.PixelSnapping; -enum flash.display.BlendMode; - -@:require(flash10) flash.desktop.Clipboard -@:require(flash10) flash.desktop.ClipboardFormats -@:require(flash10) flash.desktop.ClipboardTransferMode - -flash.display.Bitmap.pixelSnapping : PixelSnapping; -flash.display.Bitmap.$pixelSnapping : PixelSnapping; -flash.display.BitmapData.$blendMode : BlendMode; -flash.display.BitmapData.$redArray : Array; -flash.display.BitmapData.$greenArray : Array; -flash.display.BitmapData.$blueArray : Array; -flash.display.BitmapData.$alphaArray : Array; -flash.display.BitmapData.$offsets : Array; -@:require(flash10) flash.display.BitmapData.setVector -@:require(flash10) flash.display.BitmapData.getVector -@:require(flash10) flash.display.BitmapData.histogram - -@:require(flash10_1) flash.display.Loader.uncaughtErrorEvents; -@:require(flash10_1) flash.display.LoaderInfo.isURLInaccessible; -@:require(flash10_1) flash.display.LoaderInfo.uncaughtErrorEvents; - -@:require(flash10_1) flash.display.ColorCorrection -@:require(flash10_1) flash.display.ColorCorrectionSupport -@:require(flash10_1) flash.display.FocusDirection -@:require(flash10_1) flash.display.NativeMenu -@:require(flash10_1) flash.display.NativeMenuItem - -@:require(flash10) flash.display.DisplayObject.blendShader -@:require(flash10) flash.display.DisplayObject.rotationX -@:require(flash10) flash.display.DisplayObject.rotationY -@:require(flash10) flash.display.DisplayObject.rotationZ -@:require(flash10) flash.display.DisplayObject.scaleZ -@:require(flash10) flash.display.DisplayObject.z -@:require(flash10) flash.display.DisplayObject.globalToLocal3D -@:require(flash10) flash.display.DisplayObject.local3DToGlobal --flash.display.DisplayObject.new -flash.display.DisplayObject.blendMode : BlendMode; -flash.display.DisplayObject.opaqueBackground : Null; -flash.display.DisplayObjectContainer.getObjectsUnderPoint : Array; - -@:require(flash10_1) flash.display.Sprite.startTouchDrag; -@:require(flash10_1) flash.display.Sprite.stopTouchDrag; - -@:require(flash10_1) flash.display.Stage.wmodeGPU; - -enum flash.display.GradientType; -enum flash.display.CapsStyle; -enum flash.display.JointStyle; -enum flash.display.GraphicsPathWinding; -enum flash.display.TriangleCulling; -enum flash.display.InterpolationMethod; -enum flash.display.LineScaleMode; -enum flash.display.ShaderParameterType; -enum flash.display.ShaderPrecision; -enum flash.display.SpreadMethod; -enum flash.display.StageAlign; -enum flash.display.StageDisplayState; -enum flash.display.StageQuality; -enum flash.display.StageScaleMode; --flash.display.SWFVersion.new - -flash.display.Graphics.$type : GradientType; -flash.display.Graphics.$colors : Array; -flash.display.Graphics.$spreadMethod : SpreadMethod; -flash.display.Graphics.$interpolationMethod : InterpolationMethod; -flash.display.Graphics.$scaleMode : LineScaleMode; -flash.display.Graphics.$caps : CapsStyle; -flash.display.Graphics.$joints : JointStyle; -flash.display.Graphics.$winding : GraphicsPathWinding; -flash.display.Graphics.$culling : TriangleCulling; -@:require(flash10) flash.display.Graphics.beginShaderFill -@:require(flash10) flash.display.Graphics.copyFrom -@:require(flash10) flash.display.Graphics.drawGraphicsData -@:require(flash10) flash.display.Graphics.drawPath -@:require(flash10) flash.display.Graphics.drawTriangles -@:require(flash10) flash.display.Graphics.lineBitmapStyle -@:require(flash10) flash.display.Graphics.lineShaderStyle - - -flash.display.GraphicsGradientFill.type : GradientType; -flash.display.GraphicsGradientFill.colors : Array; -flash.display.GraphicsGradientFill.spreadMethod : SpreadMethod; -flash.display.GraphicsGradientFill.interpolationMethod : InterpolationMethod; -flash.display.GraphicsGradientFill.alphas : Array; -flash.display.GraphicsGradientFill.ratios : Array; -flash.display.GraphicsGradientFill.$type : GradientType; -flash.display.GraphicsGradientFill.$colors : Array; -flash.display.GraphicsGradientFill.$spreadMethod : SpreadMethod; -flash.display.GraphicsGradientFill.$interpolationMethod : InterpolationMethod; -flash.display.GraphicsGradientFill.$alphas : Array; -flash.display.GraphicsGradientFill.$ratios : Array; -flash.display.GraphicsGradientFill.$matrix : flash.geom.Matrix; - -flash.display.GraphicsPath.winding : GraphicsPathWinding; -flash.display.GraphicsPath.$winding : GraphicsPathWinding; - -flash.display.GraphicsStroke.scaleMode : LineScaleMode; -flash.display.GraphicsStroke.caps : CapsStyle; -flash.display.GraphicsStroke.joints : JointStyle; -flash.display.GraphicsStroke.$scaleMode : LineScaleMode; -flash.display.GraphicsStroke.$caps : CapsStyle; -flash.display.GraphicsStroke.$joints : JointStyle; - -flash.display.GraphicsTrianglePath.culling : TriangleCulling; -flash.display.GraphicsTrianglePath.$culling : TriangleCulling; - - -@:require(flash10) flash.display.Loader.unloadAndStop - -enum flash.display.ActionScriptVersion; -enum flash.display.ColorCorrection; -enum flash.display.ColorCorrectionSupport; - --flash.display.LoaderInfo.new -flash.display.LoaderInfo.parameters : Dynamic; -flash.display.LoaderInfo.actionScriptVersion : ActionScriptVersion; - --flash.display.MorphShape.new - -@:require(flash10) flash.display.MovieClip.currentFrameLabel -flash.display.MovieClip.currentLabels : Array; -flash.display.MovieClip.scenes : Array; - -flash.display.Scene.labels : Array; -flash.display.Scene.$labels : Array; - -@:require(flash10) flash.display.Shader; -flash.display.Shader.precisionHint : ShaderPrecision; - --flash.display.ShaderParameter.new -flash.display.ShaderParameter.type : ShaderParameterType; - --flash.display.Stage.new -flash.display.Stage.align : StageAlign; -flash.display.Stage.quality : StageQuality; -flash.display.Stage.scaleMode : StageScaleMode; -flash.display.Stage.colorCorrection : ColorCorrection; -flash.display.Stage.colorCorrectionSupport : ColorCorrectionSupport; -flash.display.Stage.displayState : StageDisplayState; -flash.display.Stage.displayState : StageDisplayState; - -@:require(flash10) flash.display.Stage.colorCorrection -@:require(flash10) flash.display.Stage.colorCorrectionSupport - -@:require(flash10_1) flash.errors.DRMManagerError -@:require(flash10_1) flash.events.AccelerometerEvent -@:require(flash10_1) flash.events.DRMAuthenticateEvent -@:require(flash10_1) flash.events.DRMAuthenticationCompleteEvent -@:require(flash10_1) flash.events.DRMAuthenticationErrorEvent -@:require(flash10_1) flash.events.DRMCustomProperties -@:require(flash10_1) flash.events.DRMErrorEvent -@:require(flash10_1) flash.events.DRMStatusEvent -@:require(flash10_1) flash.events.GeolocationEvent -@:require(flash10_1) flash.events.GestureEvent -@:require(flash10_1) flash.events.GesturePhase -@:require(flash10_1) flash.events.PressAndTapGestureEvent -@:require(flash10_1) flash.events.TouchEvent -@:require(flash10_1) flash.events.TransformGestureEvent -@:require(flash10_1) flash.events.UncaughtErrorEvent; -@:require(flash10_1) flash.events.UncaughtErrorEvents; - -@:require(flash10) static flash.events.Event.CLEAR; -@:require(flash10) static flash.events.Event.COPY; -@:require(flash10) static flash.events.Event.CUT; -@:require(flash10) static flash.events.Event.EXIT_FRAME; -@:require(flash10) static flash.events.Event.FRAME_CONSTRUCTED; -@:require(flash10) static flash.events.Event.PASTE; -@:require(flash10) static flash.events.Event.SELECT_ALL; - -@:require(flash10) flash.events.ContextMenuEvent.isMouseTargetInaccessible -@:require(flash10) flash.events.FocusEvent.isRelatedObjectInaccessible -@:require(flash10) flash.events.MouseEvent.isRelatedObjectInaccessible - -flash.events.IEventDispatcher.$listener : Dynamic -> Void; -flash.events.EventDispatcher.$listener : Dynamic -> Void; - -enum flash.events.EventPhase; -enum flash.events.GesturePhase; - -flash.events.Event.eventPhase : EventPhase; - -flash.events.KeyboardEvent.keyLocation : flash.ui.KeyLocation; -flash.events.KeyboardEvent.$keyLocationValue : flash.ui.KeyLocation; -flash.events.KeyboardEvent.$keyLocation : flash.ui.KeyLocation; - -@:require(flash10_1) flash.events.ErrorEvent.errorID; - -@:require(flash10_1) flash.events.HTTPStatusEvent.responseHeaders; -@:require(flash10_1) flash.events.HTTPStatusEvent.responseURL; -@:require(flash10_1) static flash.events.HTTPStatusEvent.HTTP_RESPONSE_STATUS; - -@:require(flash10_1) flash.events.IMEEvent.imeClient; -@:require(flash10_1) static flash.events.IMEEvent.IME_START_COMPOSITION; - --flash.events.WeakFunctionClosure.new - --flash.external.ExternalInterface.new - -enum flash.filters.BitmapFilterType; -enum flash.filters.DisplacementMapFilterMode; - -flash.filters.BevelFilter.type : BitmapFilterType; -flash.filters.BevelFilter.$type : BitmapFilterType; - -flash.filters.DisplacementMapFilter.mode : DisplacementMapFilterMode; -flash.filters.DisplacementMapFilter.$mode : DisplacementMapFilterMode; - -flash.filters.GradientGlowFilter.type : BitmapFilterType; -flash.filters.GradientGlowFilter.$type : BitmapFilterType; - -enum flash.geom.Orientation3D; - -flash.geom.Matrix3D.$orientationStyle : Orientation3D; - -@:require(flash10) flash.geom.Matrix3D; -@:require(flash10) flash.geom.Utils3D; -@:require(flash10) flash.geom.Vector3D; -@:require(flash10) flash.geom.PerspectiveProjection; -@:require(flash10) flash.geom.Transform.matrix3D; -@:require(flash10) flash.geom.Transform.perspectiveProjection; -@:require(flash10) flash.geom.Transform.getRelativeMatrix3D; - --flash.geom.Utils3D.new - -@:require(flash10_1) static flash.media.Camera.isSupported; -@:require(flash10_1) static flash.media.Camera._scanHardware; - -enum flash.media.SoundCodec; - -flash.media.Microphone.codec : SoundCodec; - -@:require(flash10) flash.media.Microphone.codec; -@:require(flash10) flash.media.Microphone.encodeQuality; -@:require(flash10) flash.media.Microphone.framesPerPacket; - -@:require(flash10_1) flash.media.Microphone.enableVAD; -@:require(flash10_1) flash.media.Microphone.noiseSuppressionLevel; -@:require(flash10_1) static flash.media.Microphone.isSupported; - -@:require(flash10) flash.media.Sound.extract; - -@:require(flash10_1) flash.media.Sound.isURLInaccessible; - -@:require(flash10) flash.net.FileReference.data; -@:require(flash10) flash.net.FileReference.load; -@:require(flash10) flash.net.FileReference.save; - --flash.media.SoundMixer.new - -@:require(flash10_1) flash.net.LocalConnection.isPerUser; -@:require(flash10_1) static flash.net.LocalConnection.isSupported; - -flash.net.FileReference.$typeFilter : Array; -flash.net.FileReferenceList.fileList : Array; -flash.net.FileReferenceList.$typeFilter : Array; - -@:require(flash10_1) flash.net.GroupSpecifier; -@:require(flash10_1) flash.net.NetGroup; -@:require(flash10_1) flash.net.NetGroupInfo; -@:require(flash10_1) flash.net.NetStreamMulticastInfo; - -@:require(flash10) flash.net.NetConnection.farID; -@:require(flash10) flash.net.NetConnection.farNonce; -@:require(flash10) flash.net.NetConnection.maxPeerConnections; -@:require(flash10) flash.net.NetConnection.nearID; -@:require(flash10) flash.net.NetConnection.nearNonce; -@:require(flash10) flash.net.NetConnection.protocol; -@:require(flash10) flash.net.NetConnection.unconnectedPeerStreams; - -@:require(flash10) flash.net.NetStream.farID; -@:require(flash10) flash.net.NetStream.farNonce; -@:require(flash10) flash.net.NetStream.info; -@:require(flash10) flash.net.NetStream.maxPauseBufferTime; -@:require(flash10) flash.net.NetStream.nearNonce; -@:require(flash10) flash.net.NetStream.peerStreams; -@:require(flash10) flash.net.NetStream.onPeerConnect; -@:require(flash10) flash.net.NetStream.play2; -@:require(flash10) static flash.net.NetStream.CONNECT_TO_FMS; -@:require(flash10) static flash.net.NetStream.DIRECT_CONNECTIONS; - -@:require(flash10_1) flash.net.NetStream.audioReliable; -@:require(flash10_1) flash.net.NetStream.audioSampleAccess; -@:require(flash10_1) flash.net.NetStream.backBufferLength; -@:require(flash10_1) flash.net.NetStream.backBufferTime; -@:require(flash10_1) flash.net.NetStream.bufferTimeMax; -@:require(flash10_1) flash.net.NetStream.dataReliable; -@:require(flash10_1) flash.net.NetStream.inBufferSeek; -@:require(flash10_1) flash.net.NetStream.multicastAvailabilitySendToAll; -@:require(flash10_1) flash.net.NetStream.multicastAvailabilityUpdatePeriod; -@:require(flash10_1) flash.net.NetStream.multicastFetchPeriod; -@:require(flash10_1) flash.net.NetStream.multicastInfo; -@:require(flash10_1) flash.net.NetStream.multicastPushNeighborLimit; -@:require(flash10_1) flash.net.NetStream.multicastRelayMarginDuration; -@:require(flash10_1) flash.net.NetStream.multicastWindowDuration; -@:require(flash10_1) flash.net.NetStream.videoReliable; -@:require(flash10_1) flash.net.NetStream.videoSampleAccess; -@:require(flash10_1) flash.net.NetStream.appendBytes; -@:require(flash10_1) flash.net.NetStream.appendBytesAction; -@:require(flash10_1) flash.net.NetStream.attach; -@:require(flash10_1) flash.net.NetStream.step; - -@:require(flash10_1) flash.net.NetStreamInfo.videoLossRate; - -@:require(flash10_1) flash.net.NetStreamPlayOptions.offset; - -@:require(flash10_1) static flash.net.URLRequestMethod.DELETE; -@:require(flash10_1) static flash.net.URLRequestMethod.HEAD; -@:require(flash10_1) static flash.net.URLRequestMethod.OPTIONS; -@:require(flash10_1) static flash.net.URLRequestMethod.PUT; - -@:require(flash10) flash.net.Socket.timeout; -@:require(flash10) flash.net.XMLSocket.timeout; - --flash.net.ObjectEncoding.new --flash.net.URLRequestMethod.new - -enum flash.net.URLLoaderDataFormat; - -flash.net.Socket.endian : flash.utils.Endian; -flash.net.URLLoader.dataFormat : URLLoaderDataFormat; -flash.net.URLRequest.requestHeaders : Array; -flash.net.URLStream.endian : flash.utils.Endian; - -enum flash.printing.PrintJobOrientation; - -flash.printing.PrintJob.orientation : PrintJobOrientation; -@:require(flash10_1) static flash.printing.PrintJob.isSupported; - --flash.sampler.DeleteObjectSample.new --flash.sampler.NewObjectSample.new --flash.sampler.Sample.new -flash.sampler.Sample.stack : Array; --flash.sampler.StackFrame.new -@:require(flash10_1) flash.sampler.NewObjectSample.size; -@:require(flash10_1) flash.sampler.StackFrame.scriptID; - --flash.system.Capabilities.new --flash.system.IME.new --flash.system.FSCommand.new - -enum flash.system.IMEConversionMode; - -static flash.system.IME.conversionMode : IMEConversionMode - -@:require(flash10) flash.system.ApplicationDomain.domainMemory; -@:require(flash10) static flash.system.ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH; - -@:require(flash10) static flash.system.Capabilities.isEmbeddedInAcrobat; -@:require(flash10) static flash.system.Capabilities.maxLevelIDC; - -@:require(flash10_1) static flash.system.Capabilities.cpuArchitecture; -@:require(flash10_1) static flash.system.Capabilities.supports32BitProcesses; -@:require(flash10_1) static flash.system.Capabilities.supports64BitProcesses; -@:require(flash10_1) static flash.system.Capabilities.touchscreenType; -static flash.system.Capabilities.touchscreenType : TouchscreenType; - -enum flash.system.TouchscreenType; - - -@:require(flash10_1) static flash.system.IME.isSupported; -@:require(flash10_1) static flash.system.IME.compositionAbandoned; -@:require(flash10_1) static flash.system.IME.compositionSelectionChanged; - - -@:require(flash10) flash.system.JPEGLoaderContext; - - -@:require(flash10_1) flash.system.LoaderContext.allowCodeImport; -@:require(flash10_1) flash.system.LoaderContext.allowLoadBytesCodeExecution; - -@:require(flash10_1) static flash.system.Security.APPLICATION; -@:require(flash10_1) static flash.system.Security.duplicateSandboxBridgeInputArguments; -@:require(flash10_1) static flash.system.Security.duplicateSandboxBridgeOutputArgument; - -@:require(flash10_1) static flash.system.System.currentTime; -@:require(flash10_1) static flash.system.System.freeMemory; -@:require(flash10_1) static flash.system.System.preciseStartupTime; -@:require(flash10_1) static flash.system.System.privateMemory; -@:require(flash10_1) static flash.system.System.totalMemoryNumber; -@:require(flash10_1) static flash.system.System.disposeXML; -@:require(flash10_1) static flash.system.System.nativeConstructionOnly; - -enum flash.system.SecurityPanel; - --flash.system.Security.new -flash.system.Security.$panel : SecurityPanel --flash.system.SecurityDomain.new --flash.system.System.new -flash.system.SystemUpdater.$typer : SystemAdapterType; - -enum flash.text.AntiAliasType; -enum flash.text.GridFitType; -enum flash.text.FontStyle; -enum flash.text.FontType; -enum flash.text.TextDisplayMode; -enum flash.text.TextFieldType; -enum flash.text.TextFieldAutoSize; -enum flash.text.TextFormatAlign; -enum flash.text.TextFormatDisplay; -enum flash.text.TextColorType; - -flash.text.Font.fontStyle : FontStyle; -flash.text.Font.fontType : FontType; -static flash.text.Font.enumerateFonts : Array; -flash.text.TextField.autoSize : TextFieldAutoSize; -flash.text.TextField.antiAliasType : AntiAliasType; -flash.text.TextField.gridFitType : GridFitType; -flash.text.TextField.type : TextFieldType; - -flash.text.TextFormat.align : TextFormatAlign; -flash.text.TextFormat.blockIndent : Null -flash.text.TextFormat.bold : Null; -flash.text.TextFormat.bullet : Null; -flash.text.TextFormat.color : Null; -flash.text.TextFormat.display : TextFormatDisplay; -flash.text.TextFormat.indent : Null; -flash.text.TextFormat.italic : Null; -flash.text.TextFormat.kerning : Null; -flash.text.TextFormat.leading : Null; -flash.text.TextFormat.leftMargin : Null; -flash.text.TextFormat.letterSpacing : Null; -flash.text.TextFormat.rightMargin : Null; -flash.text.TextFormat.size : Null; -flash.text.TextFormat.tabStops : Array; -flash.text.TextFormat.underline : Null; -flash.text.TextFormat.$size : Null; -flash.text.TextFormat.$color : Null; -flash.text.TextFormat.$bold : Null; -flash.text.TextFormat.$italic : Null; -flash.text.TextFormat.$underline : Null; -flash.text.TextFormat.$align : TextFormatAlign; -flash.text.TextFormat.$leftMargin : Null; -flash.text.TextFormat.$rightMargin : Null; -flash.text.TextFormat.$indent : Null; -flash.text.TextFormat.$leading : Null; - -@:require(flash10) static flash.text.TextField.isFontCompatible; - --flash.text.TextRenderer.new -static flash.text.TextRenderer.antiAliasType : AntiAliasType; -static flash.text.TextRenderer.displayMode : TextDisplayMode; -flash.text.TextRenderer.$fontStyle : FontStyle; -flash.text.TextRenderer.$colorType : TextColorType; - -@:require(flash10_1) static flash.text.engine.FontDescription.isDeviceFontCompatible; -@:require(flash10_1) flash.text.engine.SpaceJustifier.maximumSpacing; -@:require(flash10_1) flash.text.engine.SpaceJustifier.minimumSpacing; -@:require(flash10_1) flash.text.engine.SpaceJustifier.optimumSpacing; -@:require(flash10_1) flash.text.engine.TextBlock.recreateTextLine; -@:require(flash10_1) flash.text.engine.TextBlock.releaseLineCreationData; -@:require(flash10_1) flash.text.engine.TextLine.hasTabs; - -flash.text.engine.ContentElement.textRotation : TextRotation; -flash.text.engine.ContentElement.$textRotation : TextRotation; - -flash.text.engine.EastAsianJustifier.justificationStyle : JustificationStyle; -flash.text.engine.EastAsianJustifier.$justificationStyle : JustificationStyle; -flash.text.engine.EastAsianJustifier.$lineJustification : LineJustification; - -enum flash.text.engine.BreakOpportunity; -enum flash.text.engine.CFFHinting; -enum flash.text.engine.DigitCase; -enum flash.text.engine.DigitWidth; -enum flash.text.engine.FontLookup; -enum flash.text.engine.FontPosture; -enum flash.text.engine.FontWeight; -enum flash.text.engine.JustificationStyle; -enum flash.text.engine.Kerning; -enum flash.text.engine.LigatureLevel; -enum flash.text.engine.LineJustification; -enum flash.text.engine.RenderingMode; -enum flash.text.engine.TabAlignment; -enum flash.text.engine.TextBaseline; -enum flash.text.engine.TextLineCreationResult; -enum flash.text.engine.TextLineValidity; -enum flash.text.engine.TextRotation; -enum flash.text.engine.TypographicCase; - - -flash.text.engine.ElementFormat.alignmentBaseline : TextBaseline; -flash.text.engine.ElementFormat.breakOpportunity : BreakOpportunity; -flash.text.engine.ElementFormat.digitCase : DigitCase; -flash.text.engine.ElementFormat.digitWidth : DigitWidth; -flash.text.engine.ElementFormat.dominantBaseline : TextBaseline; -flash.text.engine.ElementFormat.kerning : Kerning; -flash.text.engine.ElementFormat.ligatureLevel : LigatureLevel; -flash.text.engine.ElementFormat.textRotation : TextRotation; -flash.text.engine.ElementFormat.typographicCase : TypographicCase; -flash.text.engine.ElementFormat.$alignmentBaseline : TextBaseline; -flash.text.engine.ElementFormat.$breakOpportunity : BreakOpportunity; -flash.text.engine.ElementFormat.$digitCase : DigitCase; -flash.text.engine.ElementFormat.$digitWidth : DigitWidth; -flash.text.engine.ElementFormat.$dominantBaseline : TextBaseline; -flash.text.engine.ElementFormat.$kerning : Kerning; -flash.text.engine.ElementFormat.$ligatureLevel : LigatureLevel; -flash.text.engine.ElementFormat.$textRotation : TextRotation; -flash.text.engine.ElementFormat.$typographicCase : TypographicCase; - -flash.text.engine.FontDescription.cffHinting : CFFHinting; -flash.text.engine.FontDescription.fontLookup : FontLookup; -flash.text.engine.FontDescription.fontPosture : FontPosture; -flash.text.engine.FontDescription.fontWeight : FontWeight; -flash.text.engine.FontDescription.renderingMode : RenderingMode; -flash.text.engine.FontDescription.$cffHinting : CFFHinting; -flash.text.engine.FontDescription.$fontLookup : FontLookup; -flash.text.engine.FontDescription.$fontPosture : FontPosture; -flash.text.engine.FontDescription.$fontWeight : FontWeight; -flash.text.engine.FontDescription.$renderingMode : RenderingMode; - -flash.text.engine.GraphicElement.$textRotation : TextRotation; -flash.text.engine.GroupElement.$textRotation : TextRotation; -flash.text.engine.SpaceJustifier.$lineJustification : LineJustification; -flash.text.engine.TabStop.alignment : TabAlignment; -flash.text.engine.TabStop.$alignment : TabAlignment; - -flash.text.engine.TextBlock.baselineZero : TextBaseline; -flash.text.engine.TextBlock.lineRotation : TextRotation; -flash.text.engine.TextBlock.textLineCreationResult : TextLineCreationResult; -flash.text.engine.TextBlock.$baselineZero : TextBaseline; -flash.text.engine.TextBlock.$lineRotation : TextRotation; -flash.text.engine.TextBlock.$textLineCreationResult : TextLineCreationResult; - -flash.text.engine.TextElement.$textRotation : TextRotation; - -flash.text.engine.TextJustifier.lineJustification : LineJustification; -flash.text.engine.TextJustifier.$lineJustification : LineJustification; - -flash.text.engine.TextLine.baseline : TextBaseline; - --flash.trace.Trace.new - --static flash.xml.XMLList.length --static flash.xml.XML.length --flash.text.engine.TextElement.text - --flash.ui.Keyboard.new --flash.ui.Mouse.new - -enum flash.ui.MultitouchInputMode; - --flash.ui.Multitouch.new -flash.ui.Multitouch.inputMode : MultitouchInputMode; - -@:require(flash10) flash.ui.ContextMenu.clipboardItems; -@:require(flash10) flash.ui.ContextMenu.clipboardMenu; -@:require(flash10) flash.ui.ContextMenu.link; - -@:require(flash10_1) static flash.ui.ContextMenu.isSupported; - -@:require(flash10) static flash.ui.Mouse.cursor; -static flash.ui.Mouse.cursor : Dynamic; - -@:require(flash10_1) static flash.ui.Keyboard.A; -@:require(flash10_1) static flash.ui.Keyboard.B; -@:require(flash10_1) static flash.ui.Keyboard.C; -@:require(flash10_1) static flash.ui.Keyboard.D; -@:require(flash10_1) static flash.ui.Keyboard.E; -@:require(flash10_1) static flash.ui.Keyboard.F; -@:require(flash10_1) static flash.ui.Keyboard.G; -@:require(flash10_1) static flash.ui.Keyboard.H; -@:require(flash10_1) static flash.ui.Keyboard.I; -@:require(flash10_1) static flash.ui.Keyboard.J; -@:require(flash10_1) static flash.ui.Keyboard.K; -@:require(flash10_1) static flash.ui.Keyboard.L; -@:require(flash10_1) static flash.ui.Keyboard.M; -@:require(flash10_1) static flash.ui.Keyboard.N; -@:require(flash10_1) static flash.ui.Keyboard.O; -@:require(flash10_1) static flash.ui.Keyboard.P; -@:require(flash10_1) static flash.ui.Keyboard.Q; -@:require(flash10_1) static flash.ui.Keyboard.R; -@:require(flash10_1) static flash.ui.Keyboard.S; -@:require(flash10_1) static flash.ui.Keyboard.T; -@:require(flash10_1) static flash.ui.Keyboard.U; -@:require(flash10_1) static flash.ui.Keyboard.V; -@:require(flash10_1) static flash.ui.Keyboard.W; -@:require(flash10_1) static flash.ui.Keyboard.X; -@:require(flash10_1) static flash.ui.Keyboard.Y; -@:require(flash10_1) static flash.ui.Keyboard.Z; -@:require(flash10_1) static flash.ui.Keyboard.ALTERNATE; -@:require(flash10_1) static flash.ui.Keyboard.BACKQUOTE; -@:require(flash10_1) static flash.ui.Keyboard.BACKSLASH; -@:require(flash10_1) static flash.ui.Keyboard.COMMA; -@:require(flash10_1) static flash.ui.Keyboard.COMMAND; -@:require(flash10_1) static flash.ui.Keyboard.CharCodeStrings; -@:require(flash10_1) static flash.ui.Keyboard.EQUAL; -@:require(flash10_1) static flash.ui.Keyboard.LEFTBRACKET; -@:require(flash10_1) static flash.ui.Keyboard.MINUS; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_0; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_1; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_2; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_3; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_4; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_5; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_6; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_7; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_8; -@:require(flash10_1) static flash.ui.Keyboard.NUMBER_9; -@:require(flash10_1) static flash.ui.Keyboard.NUMPAD; -@:require(flash10_1) static flash.ui.Keyboard.PERIOD; -@:require(flash10_1) static flash.ui.Keyboard.QUOTE; -@:require(flash10_1) static flash.ui.Keyboard.RIGHTBRACKET; -@:require(flash10_1) static flash.ui.Keyboard.SEMICOLON; -@:require(flash10_1) static flash.ui.Keyboard.SLASH; -@:require(flash10_1) static flash.ui.Keyboard.hasVirtualKeyboard; -@:require(flash10_1) static flash.ui.Keyboard.physicalKeyboardType; - -enum flash.ui.KeyboardType; -enum flash.ui.KeyLocation; - -static flash.ui.Keyboard.physicalKeyboardType : KeyboardType; - -@:require(flash10_1) flash.ui.Multitouch; -static flash.ui.Multitouch.inputMode : MultitouchInputMode; -@:require(flash10_1) flash.ui.MultitouchInputMode; - -@:require(flash10_1) static flash.ui.Keyboard.STRING_BEGIN; -@:require(flash10_1) static flash.ui.Keyboard.STRING_BREAK; -@:require(flash10_1) static flash.ui.Keyboard.STRING_CLEARDISPLAY; -@:require(flash10_1) static flash.ui.Keyboard.STRING_CLEARLINE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETECHAR; -@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETELINE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_DOWNARROW; -@:require(flash10_1) static flash.ui.Keyboard.STRING_END; -@:require(flash10_1) static flash.ui.Keyboard.STRING_EXECUTE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F1; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F10; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F11; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F12; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F13; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F14; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F15; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F16; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F17; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F18; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F19; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F2; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F20; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F21; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F22; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F23; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F24; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F25; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F26; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F27; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F28; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F29; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F3; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F30; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F31; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F32; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F33; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F34; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F35; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F4; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F5; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F6; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F7; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F8; -@:require(flash10_1) static flash.ui.Keyboard.STRING_F9; -@:require(flash10_1) static flash.ui.Keyboard.STRING_FIND; -@:require(flash10_1) static flash.ui.Keyboard.STRING_HELP; -@:require(flash10_1) static flash.ui.Keyboard.STRING_HOME; -@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERT; -@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERTCHAR; -@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERTLINE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_LEFTARROW; -@:require(flash10_1) static flash.ui.Keyboard.STRING_MENU; -@:require(flash10_1) static flash.ui.Keyboard.STRING_MODESWITCH; -@:require(flash10_1) static flash.ui.Keyboard.STRING_NEXT; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PAGEDOWN; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PAGEUP; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PAUSE; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PREV; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PRINT; -@:require(flash10_1) static flash.ui.Keyboard.STRING_PRINTSCREEN; -@:require(flash10_1) static flash.ui.Keyboard.STRING_REDO; -@:require(flash10_1) static flash.ui.Keyboard.STRING_RESET; -@:require(flash10_1) static flash.ui.Keyboard.STRING_RIGHTARROW; -@:require(flash10_1) static flash.ui.Keyboard.STRING_SCROLLLOCK; -@:require(flash10_1) static flash.ui.Keyboard.STRING_SELECT; -@:require(flash10_1) static flash.ui.Keyboard.STRING_STOP; -@:require(flash10_1) static flash.ui.Keyboard.STRING_SYSREQ; -@:require(flash10_1) static flash.ui.Keyboard.STRING_SYSTEM; -@:require(flash10_1) static flash.ui.Keyboard.STRING_UNDO; -@:require(flash10_1) static flash.ui.Keyboard.STRING_UPARROW; -@:require(flash10_1) static flash.ui.Keyboard.STRING_USER; - -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_BEGIN; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_BREAK; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_CLEARDISPLAY; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_CLEARLINE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETECHAR; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETELINE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DOWNARROW; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_END; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_EXECUTE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F1; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F10; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F11; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F12; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F13; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F14; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F15; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F16; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F17; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F18; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F19; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F2; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F20; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F21; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F22; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F23; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F24; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F25; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F26; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F27; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F28; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F29; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F3; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F30; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F31; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F32; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F33; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F34; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F35; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F4; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F5; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F6; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F7; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F8; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F9; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_FIND; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_HELP; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_HOME; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERT; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERTCHAR; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERTLINE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_LEFTARROW; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_MENU; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_MODESWITCH; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_NEXT; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAGEDOWN; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAGEUP; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAUSE; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PREV; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PRINT; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PRINTSCREEN; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_REDO; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_RESET; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_RIGHTARROW; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SCROLLLOCK; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SELECT; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_STOP; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SYSREQ; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SYSTEM; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_UNDO; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_UPARROW; -@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_USER; - -@:require(flash10_1) static flash.ui.Mouse.supportsCursor; - -enum flash.utils.Endian; - -@:native("RegExp") flash.utils.RegExp; --static flash.utils.RegExp.length; - -flash.utils.ObjectInput.endian : Endian; -flash.utils.ObjectOutput.endian : Endian; -flash.utils.ByteArray.endian : Endian; -flash.utils.IDataInput.endian : Endian; -flash.utils.IDataOutput.endian : Endian; - -@:require(flash10) flash.utils.ByteArray.clear; -@:require(flash10) flash.utils.ByteArray.deflate; -@:require(flash10) flash.utils.ByteArray.inflate; - -@:require(flash10) flash.utils.SetIntervalTimer.clearArrayEntry; - --flash.utils.Namespace.toString --flash.utils.Namespace.valueOf --static flash.utils.Namespace.length - --flash.utils.QName.toString --flash.utils.QName.valueOf --static flash.utils.QName.length - -enum flash.xml.XMLNodeType; - -flash.xml.XMLNode.nodeType : XMLNodeType; -flash.xml.XMLNode.$type : XMLNodeType; - -flash.xml.XML.namespace : flash.utils.Namespace; -flash.xml.XML.parent : XML; -flash.xml.XMLList.namespace : flash.utils.Namespace; -flash.xml.XMLList.parent : XML; -flash.xml.XMLTag.type : XMLNodeType; - - -enum flash.system.SystemUpdaterType; - -@:require(flash10_1) flash.system.SystemUpdater; -flash.system.SystemUpdater.$type : SystemUpdaterType; - -@:require(flash10_1) flash.sensors.Accelerometer; -@:require(flash10_1) flash.sensors.Geolocation; - -@:require(flash10_1) flash.globalization.Collator; -@:require(flash10_1) flash.globalization.CurrencyFormatter; -@:require(flash10_1) flash.globalization.DateTimeFormatter; -@:require(flash10_1) flash.globalization.LocaleID; -@:require(flash10_1) flash.globalization.StringTools; -@:require(flash10_1) flash.globalization.NumberFormatter; -@:require(flash10_1) flash.globalization.NumberParseResult; - -enum flash.globalization.CollatorMode; -enum flash.globalization.DateTimeNameContext; -enum flash.globalization.DateTimeNameStyle; -enum flash.globalization.DateTimeStyle; -enum flash.globalization.LastOperationStatus; -enum flash.globalization.NationalDigitsType; - -flash.globalization.Collator.lastOperationStatus : LastOperationStatus; -flash.globalization.Collator.$initialMode : CollatorMode; -flash.globalization.CurrencyFormatter.lastOperationStatus : LastOperationStatus; - -flash.globalization.DateTimeFormatter.lastOperationStatus : LastOperationStatus; -flash.globalization.DateTimeFormatter.$dateStyle : DateTimeStyle; -flash.globalization.DateTimeFormatter.$nameStyle : DateTimeNameStyle; -flash.globalization.DateTimeFormatter.$timeStyle : DateTimeStyle; -flash.globalization.DateTimeFormatter.$context : DateTimeNameContext; -flash.globalization.DateTimeFormatter.getDateStyle : DateTimeStyle; -flash.globalization.DateTimeFormatter.getTimeStyle : DateTimeStyle; -flash.globalization.DateTimeFormatter.getDateTimePattern : DateTimeStyle; -flash.globalization.LocaleID.lastOperationStatus : LastOperationStatus; -flash.globalization.NumberFormatter.lastOperationStatus : LastOperationStatus; -flash.globalization.NumberFormatter.digitsType : NationalDigitsType; -flash.globalization.StringTools.lastOperationStatus : LastOperationStatus; - -// FP 10.2 - -@:require(flash10_2) flash.ui.MouseCursorData; -@:require(flash10_2) flash.events.StageVideoEvent; -@:require(flash10_2) flash.events.VideoEvent; -@:require(flash10_2) flash.media.MicrophoneEnhancedMode; -@:require(flash10_2) flash.media.MicrophoneEnhancedOptions; -@:require(flash10_2) flash.media.StageVideo; - -@:require(flash10_2) flash.display.Stage.color; -@:require(flash10_2) flash.display.Stage.stageVideos; - -@:require(flash10_2) flash.media.Microphone.enhancedOptions; -@:require(flash10_2) static flash.media.Microphone.getEnhancedMicrophone; - -@:require(flash10_2) static flash.system.Capabilities.allowsFullScreen; - -@:require(flash10_2) static flash.ui.Keyboard.AUDIO; -@:require(flash10_2) static flash.ui.Keyboard.BACK; -@:require(flash10_2) static flash.ui.Keyboard.BLUE; -@:require(flash10_2) static flash.ui.Keyboard.CHANNEL_DOWN; -@:require(flash10_2) static flash.ui.Keyboard.CHANNEL_UP; -@:require(flash10_2) static flash.ui.Keyboard.DVR; -@:require(flash10_2) static flash.ui.Keyboard.EXIT; -@:require(flash10_2) static flash.ui.Keyboard.FAST_FORWARD; -@:require(flash10_2) static flash.ui.Keyboard.GREEN; -@:require(flash10_2) static flash.ui.Keyboard.GUIDE; -@:require(flash10_2) static flash.ui.Keyboard.HELP; -@:require(flash10_2) static flash.ui.Keyboard.INFO; -@:require(flash10_2) static flash.ui.Keyboard.INPUT; -@:require(flash10_2) static flash.ui.Keyboard.LAST; -@:require(flash10_2) static flash.ui.Keyboard.LIVE; -@:require(flash10_2) static flash.ui.Keyboard.MASTER_SHELL; -@:require(flash10_2) static flash.ui.Keyboard.MENU; -@:require(flash10_2) static flash.ui.Keyboard.NEXT; -@:require(flash10_2) static flash.ui.Keyboard.PAUSE; -@:require(flash10_2) static flash.ui.Keyboard.PLAY; -@:require(flash10_2) static flash.ui.Keyboard.PREVIOUS; -@:require(flash10_2) static flash.ui.Keyboard.RECORD; -@:require(flash10_2) static flash.ui.Keyboard.RED; -@:require(flash10_2) static flash.ui.Keyboard.REWIND; -@:require(flash10_2) static flash.ui.Keyboard.SEARCH; -@:require(flash10_2) static flash.ui.Keyboard.SETUP; -@:require(flash10_2) static flash.ui.Keyboard.SKIP_BACKWARD; -@:require(flash10_2) static flash.ui.Keyboard.SKIP_FORWARD; -@:require(flash10_2) static flash.ui.Keyboard.STOP; -@:require(flash10_2) static flash.ui.Keyboard.SUBTITLE; -@:require(flash10_2) static flash.ui.Keyboard.VOD; -@:require(flash10_2) static flash.ui.Keyboard.YELLOW; - -@:require(flash10_2) static flash.ui.Mouse.registerCursor; - -enum flash.media.MicrophoneEnhancedMode; - -flash.media.MicrophoneEnhancedOptions.mode : MicrophoneEnhancedMode; - -enum flash.display.FocusDirection; - - -// FLASH 11 FEATURES - --flash.automation.Configuration.new - -@:require(flash11) flash.display.DisplayObjectContainer.removeChildren; -@:require(flash11) flash.display.Graphics.cubicCurveTo; -@:require(flash11) flash.display.GraphicsPath.cubicCurveTo; - -@:require(flash11) flash.display.InteractiveObject.needsSoftKeyboard; -@:require(flash11) flash.display.InteractiveObject.softKeyboardInputAreaOfInterest; -@:require(flash11) flash.display.InteractiveObject.requestSoftKeyboard; - -@:require(flash11) flash.display.MovieClip.isPlaying; - -@:require(flash11) flash.display.Stage.allowsFullScreen; -@:require(flash11) flash.display.Stage.displayContextInfo; -@:require(flash11) flash.display.Stage.softKeyboardRect; -@:require(flash11) flash.display.Stage.stage3Ds; -@:require(flash11) flash.display.Stage3D; - --flash.display.Stage.constructor; --flash.display.Stage.hasOwnProperty; --flash.display.Stage.isPrototypeOf; --flash.display.Stage.propertyIsEnumerable; --flash.display.Stage.setPropertyIsEnumerable; --flash.display.Stage.toLocaleString; --flash.display.Stage.valueOf; - -enum flash.display3D.Context3DBlendFactor; -enum flash.display3D.; - -@:require(flash11) static flash.events.Event.CONTEXT3D_CREATE; -@:require(flash11) static flash.events.Event.TEXT_INTERACTION_MODE_CHANGE; - -@:require(flash11) static flash.events.StageVideoEvent.RENDER_STATUS_AVAILABLE; -@:require(flash11) static flash.events.StageVideoEvent.STAGE_VIDEO_STATE; - -@:require(flash11) flash.geom.Matrix3D.copyColumnFrom; -@:require(flash11) flash.geom.Matrix3D.copyColumnTo; -@:require(flash11) flash.geom.Matrix3D.copyFrom; -@:require(flash11) flash.geom.Matrix3D.copyRawDataFrom; -@:require(flash11) flash.geom.Matrix3D.copyRawDataTo; -@:require(flash11) flash.geom.Matrix3D.copyRowFrom; -@:require(flash11) flash.geom.Matrix3D.copyRowTo; -@:require(flash11) flash.geom.Matrix3D.copyToMatrix3D; - -@:require(flash11) flash.geom.Matrix.copyColumnFrom; -@:require(flash11) flash.geom.Matrix.copyColumnTo; -@:require(flash11) flash.geom.Matrix.copyFrom; -@:require(flash11) flash.geom.Matrix.copyRowFrom; -@:require(flash11) flash.geom.Matrix.copyRowTo; -@:require(flash11) flash.geom.Matrix.setTo; - -@:require(flash11) flash.geom.Point.copyFrom; -@:require(flash11) flash.geom.Point.setTo; - -@:require(flash11) flash.geom.Rectangle.copyFrom; -@:require(flash11) flash.geom.Rectangle.setTo; - -@:require(flash11) flash.geom.Vector3D.copyFrom; -@:require(flash11) flash.geom.Vector3D.setTo; - - - -@:require(flash11) flash.media.Sound.loadCompressedDataFromByteArray; -@:require(flash11) flash.media.Sound.loadPCMFromByteArray; - -@:require(flash11) flash.net.Socket.bytesPending; - --flash.display3D.Context3DClearMask.new; -enum flash.display3D.Context3DCompareMode; -enum flash.display3D.Context3DProgramType; -enum flash.display3D.Context3DRenderMode; -enum flash.display3D.Context3DStencilAction; -enum flash.display3D.Context3DTextureFormat; -enum flash.display3D.Context3DTriangleFace; -enum flash.display3D.Context3DVertexBufferFormat; - --flash.display.Stage3D.new; --flash.display3D.Context3D.new; --flash.display3D.IndexBuffer3D.new; --flash.display3D.Program3D.new; --flash.display3D.VertexBuffer3D.new; --flash.display3D.textures.CubeTexture.new; --flash.display3D.textures.TextureBase.new; --flash.display3D.textures.Texture.new; - -flash.display3D.Context3D.$sourceFactor : Context3DBlendFactor; -flash.display3D.Context3D.$destinationFactor : Context3DBlendFactor; -flash.display3D.Context3D.$format : Context3DTextureFormat; -flash.display3D.Context3D.$triangleFaceToCull : Context3DTriangleFace; -flash.display3D.Context3D.$triangleFace : Context3DTriangleFace; -flash.display3D.Context3D.$passCompareMode : Context3DCompareMode; -flash.display3D.Context3D.$compareMode : Context3DCompareMode; -flash.display3D.Context3D.$programType : Context3DProgramType; -flash.display3D.Context3D.$actionOnBothPass : Context3DStencilAction; -flash.display3D.Context3D.$actionOnDepthFail : Context3DStencilAction; -flash.display3D.Context3D.$actionOnDepthPassStencilFail : Context3DStencilAction; -flash.display3D.Context3D.$setVertexBufferAt__format : Context3DVertexBufferFormat; - -@:require(flash11) flash.net.NetStream.useHardwareDecoder; -@:require(flash11) flash.net.NetStream.videoStreamSettings; - -@:require(flash11) flash.net.SecureSocket; -@:require(flash11) flash.net.NetMonitor; - -@:require(flash11) static flash.system.Capabilities.hasMultiChannelAudio; - -@:require(flash11) flash.system.LoaderContext.imageDecodingPolicy; -@:require(flash11) flash.system.LoaderContext.parameters; -@:require(flash11) flash.system.LoaderContext.requestedContentParent; - -enum flash.system.ImageDecodingPolicy; - -flash.system.LoaderContext.imageDecodingPolicy : ImageDecodingPolicy; - -@:require(flash11) static flash.system.Security.pageDomain; - -@:require(flash11) static flash.system.System.processCPUUsage; -@:require(flash11) static flash.system.System.pauseForGCIfCollectionImminent; - -@:require(flash11) static flash.ui.Mouse.supportsNativeCursor; -@:require(flash11) static flash.ui.Mouse.unregisterCursor; - --flash.ui.MouseCursor.new; - -@:require(flash11) flash.utils.CompressionAlgorithm; -enum flash.utils.CompressionAlgorithm; - -@:require(flash11) flash.xml.XML.toJSON; -@:require(flash11) flash.xml.XMLList.toJSON; - -flash.utils.ByteArray.$algorithm : CompressionAlgorithm; - -@:require(flash11) flash.text.TextField.textInteractionMode; - -enum flash.text.TextInteractionMode; - -flash.text.TextField.textInteractionMode : TextInteractionMode; - -// 11.2 - -enum flash.display.BitmapCompressColorSpace; - -@:require(flash11_2) flash.display.BitmapData.compress; -@:require(flash11_2) flash.media.Camera.position; -@:require(flash11_2) flash.net.NetStream.dispose; - -@:require(flash11_2) flash.display.StageWorker; -@:require(flash11_2) flash.display.Worker; -@:require(flash11_2) flash.events.GameInputEvent; -@:require(flash11_2) flash.events.ThrottleEvent; - -flash.events.ThrottleEvent.$type : ThrottleType; - -enum flash.events.ThrottleType; - -@:require(flash11_2) flash.ui.GameInput; -@:require(flash11_2) flash.ui.GameInputDevice; --flash.ui.GameInput.new; - -@:require(flash11_2) flash.utils.Telemetry; - -enum flash.ui.GameInputFinger; -enum flash.ui.GameInputHand; -enum flash.ui.GameInputControlType; - -flash.ui.GameInputControl.finger : flash.ui.GameInputFinger; -flash.ui.GameInputControl.hand : flash.ui.GameInputHand; -flash.ui.GameInputControl.type : flash.ui.GameInputControlType; - - -// 11.2 - -@:require(flash11_2) flash.display3D.Context3D.setProgramConstantsFromByteArray -@:require(flash11_2) flash.display.Stage.mouseLock; - -@:require(flash11_2) flash.events.MouseEvent.movementX; -@:require(flash11_2) flash.events.MouseEvent.movementY; - -@:require(flash11_2) static flash.events.MouseEvent.CONTEXT_MENU; -@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_CLICK; -@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_MOUSE_DOWN; -@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_MOUSE_UP; -@:require(flash11_2) static flash.events.MouseEvent.RIGHT_CLICK; -@:require(flash11_2) static flash.events.MouseEvent.RIGHT_MOUSE_DOWN; -@:require(flash11_2) static flash.events.MouseEvent.RIGHT_MOUSE_UP; - - -// 11.3 - -@:require(flash11_3) flash.display.BitmapData.drawWithQuality - -flash.display.BitmapData.$quality : StageQuality; - -enum flash.display.BitmapEncodingColorSpace; - -flash.display.JPEGXREncoderOptions.$colorSpace : BitmapEncodingColorSpace; -flash.display.JPEGXREncoderOptions.colorSpace : BitmapEncodingColorSpace; - -@:require(flash11_3) flash.display.BitmapData.encode -@:require(flash11_3) flash.display.Stage.allowsFullScreenInteractive - -@:require(flash11_3) static flash.events.Event.FRAME_LABEL; -@:require(flash11_3) static flash.events.Event.SUSPEND; - -@:require(flash11_3) static flash.events.FullScreenEvent.FULL_SCREEN_INTERACTIVE_ACCEPTED; -@:require(flash11_3) flash.events.FullScreenEvent.interactive; - -@:require(flash11_3) static flash.events.MouseEvent.RELEASE_OUTSIDE; - -@:require(flash11_3) flash.net.NetStream.useJitterBuffer; - -@:require(flash11_3) flash.system.ApplicationDomain.getQualifiedDefinitionNames; - -@:require(flash11_3) flash.system.SecurityDomain.domainID; - -@:require(flash11_3) flash.system.ApplicationInstaller; -@:require(flash11_3) flash.system.AuthorizedFeatures; -@:require(flash11_3) flash.system.AuthorizedFeaturesLoader; - -@:require(flash11_3) static flash.events.Event.TEXTURE_READY; - - -// 11.4 - -@:require(flash11_4) flash.display3D.Context3D.createRectangleTexture -@:require(flash11_4) flash.display.BitmapData.copyPixelsToByteArray; - -@:require(flash11_4) flash.concurrent.Mutex; -@:require(flash11_4) flash.concurrent.Condition; - -enum flash.display3D.Context3DProfile; - -flash.display.Stage3D.$profile : flash.display3D.Context3DProfile; - -@:require(flash11_4) flash.display.LoaderInfo.childSandboxBridge; -@:require(flash11_4) flash.display.LoaderInfo.parentSandboxBridge; - -@:require(flash11_4) flash.display.Stage.contentsScaleFactor; - - -@:require(flash11_4) flash.media.Camera.copyToByteArray; -@:require(flash11_4) flash.media.Camera.copyToVector; -@:require(flash11_4) flash.media.Camera.drawToBitmapData; -@:require(flash11_4) flash.media.StageVideo.attachCamera; - -@:require(flash11_4) flash.net.URLStream.diskCacheEnabled; -@:require(flash11_4) flash.net.URLStream.length; -@:require(flash11_4) flash.net.URLStream.position; -@:require(flash11_4) flash.net.URLStream.stop; - -@:require(flash11_4) flash.system.AuthorizedFeatures.enableDiskCache; -@:require(flash11_4) flash.system.AuthorizedFeatures.isFeatureEnabled; -@:require(flash11_4) flash.system.AuthorizedFeatures.isNegativeToken; -@:require(flash11_4) flash.system.AuthorizedFeaturesLoader.makeGlobal; - -@:require(flash11_4) flash.utils.ByteArray.shareable; -@:require(flash11_4) flash.utils.ByteArray.atomicCompareAndSwapIntAt; -@:require(flash11_4) flash.utils.ByteArray.atomicCompareAndSwapLength; - -//not supported @:require(flash11_4) flash.utils.CompressionAlgorithm.LZMA; - -@:require(flash11_4) flash.system.Worker; -@:require(flash11_4) flash.system.WorkerDomain; - -@:require(flash11_4) flash.system.MessageChannel; - --flash.system.Worker.new; --flash.system.MessageChannel.new; - -flash.system.Worker.state : WorkerState; -flash.system.MessageChannel.state : MessageChannelState; - -enum flash.system.WorkerState; - - -// --- 11.6 API - -enum flash.display3D.Context3DMipFilter -enum flash.display3D.Context3DTextureFilter -enum flash.display3D.Context3DWrapMode -enum flash.system.ApplicationInstallerMode - -@:require(flash11_6) flash.display3D.Context3D.setSamplerStateAt -flash.display3D.Context3D.$wrap : Context3DWrapMode; -flash.display3D.Context3D.$filter : Context3DTextureFilter; -flash.display3D.Context3D.$mipfilter : Context3DMipFilter; - --flash.display.DisplayObject.metaData - -@:require(flash11_6) flash.display.Graphics.readGraphicsData - -@:require(flash11_7) flash.media.StageVideo.attachAVStream; -@:require(flash11_7) static flash.net.SharedObject.preventBackup; -@:require(flash11_7) flash.system.AuthorizedFeatures.enableHLSPlayback; -@:require(flash11_7) flash.system.AuthorizedFeaturesLoader.loadAuthorizedFeaturesFromData; - - +// types patches configuration for playerglobal.swc + +flash.display.DisplayObject.filters : Array; + +-flash.accessibility.Accessibility.new +@:require(flash10_1) flash.accessibility.ISearchableText +@:require(flash10_1) flash.accessibility.ISimpleTextSelection + +@:require(flash10_1) flash.automation.ActionGenerator +@:require(flash10_1) flash.automation.AutomationAction +@:require(flash10_1) flash.automation.Configuration +@:require(flash10_1) flash.automation.KeyboardAutomationAction +@:require(flash10_1) flash.automation.MouseAutomationAction +@:require(flash10_1) flash.automation.StageCapture +@:require(flash10_1) flash.automation.StageCaptureEvent + +-flash.desktop.Clipboard.new +flash.desktop.Clipboard.formats : Array; +flash.desktop.Clipboard.$format : ClipboardFormats; +flash.desktop.Clipboard.$transferMode : ClipboardTransferMode; + +enum flash.desktop.ClipboardFormats; +enum flash.desktop.ClipboardTransferMode; + +enum flash.display.PixelSnapping; +enum flash.display.BlendMode; + +@:require(flash10) flash.desktop.Clipboard +@:require(flash10) flash.desktop.ClipboardFormats +@:require(flash10) flash.desktop.ClipboardTransferMode + +flash.display.Bitmap.pixelSnapping : PixelSnapping; +flash.display.Bitmap.$pixelSnapping : PixelSnapping; +flash.display.BitmapData.$blendMode : BlendMode; +flash.display.BitmapData.$redArray : Array; +flash.display.BitmapData.$greenArray : Array; +flash.display.BitmapData.$blueArray : Array; +flash.display.BitmapData.$alphaArray : Array; +flash.display.BitmapData.$offsets : Array; +@:require(flash10) flash.display.BitmapData.setVector +@:require(flash10) flash.display.BitmapData.getVector +@:require(flash10) flash.display.BitmapData.histogram + +@:require(flash10_1) flash.display.Loader.uncaughtErrorEvents; +@:require(flash10_1) flash.display.LoaderInfo.isURLInaccessible; +@:require(flash10_1) flash.display.LoaderInfo.uncaughtErrorEvents; + +@:require(flash10_1) flash.display.ColorCorrection +@:require(flash10_1) flash.display.ColorCorrectionSupport +@:require(flash10_1) flash.display.FocusDirection +@:require(flash10_1) flash.display.NativeMenu +@:require(flash10_1) flash.display.NativeMenuItem + +@:require(flash10) flash.display.DisplayObject.blendShader +@:require(flash10) flash.display.DisplayObject.rotationX +@:require(flash10) flash.display.DisplayObject.rotationY +@:require(flash10) flash.display.DisplayObject.rotationZ +@:require(flash10) flash.display.DisplayObject.scaleZ +@:require(flash10) flash.display.DisplayObject.z +@:require(flash10) flash.display.DisplayObject.globalToLocal3D +@:require(flash10) flash.display.DisplayObject.local3DToGlobal +-flash.display.DisplayObject.new +flash.display.DisplayObject.blendMode : BlendMode; +flash.display.DisplayObject.opaqueBackground : Null; +flash.display.DisplayObjectContainer.getObjectsUnderPoint : Array; + +@:require(flash10_1) flash.display.Sprite.startTouchDrag; +@:require(flash10_1) flash.display.Sprite.stopTouchDrag; + +@:require(flash10_1) flash.display.Stage.wmodeGPU; + +enum flash.display.GradientType; +enum flash.display.CapsStyle; +enum flash.display.JointStyle; +enum flash.display.GraphicsPathWinding; +enum flash.display.TriangleCulling; +enum flash.display.InterpolationMethod; +enum flash.display.LineScaleMode; +enum flash.display.ShaderParameterType; +enum flash.display.ShaderPrecision; +enum flash.display.SpreadMethod; +enum flash.display.StageAlign; +enum flash.display.StageDisplayState; +enum flash.display.StageQuality; +enum flash.display.StageScaleMode; +-flash.display.SWFVersion.new + +flash.display.Graphics.$type : GradientType; +flash.display.Graphics.$colors : Array; +flash.display.Graphics.$spreadMethod : SpreadMethod; +flash.display.Graphics.$interpolationMethod : InterpolationMethod; +flash.display.Graphics.$scaleMode : LineScaleMode; +flash.display.Graphics.$caps : CapsStyle; +flash.display.Graphics.$joints : JointStyle; +flash.display.Graphics.$winding : GraphicsPathWinding; +flash.display.Graphics.$culling : TriangleCulling; +@:require(flash10) flash.display.Graphics.beginShaderFill +@:require(flash10) flash.display.Graphics.copyFrom +@:require(flash10) flash.display.Graphics.drawGraphicsData +@:require(flash10) flash.display.Graphics.drawPath +@:require(flash10) flash.display.Graphics.drawTriangles +@:require(flash10) flash.display.Graphics.lineBitmapStyle +@:require(flash10) flash.display.Graphics.lineShaderStyle + + +flash.display.GraphicsGradientFill.type : GradientType; +flash.display.GraphicsGradientFill.colors : Array; +flash.display.GraphicsGradientFill.spreadMethod : SpreadMethod; +flash.display.GraphicsGradientFill.interpolationMethod : InterpolationMethod; +flash.display.GraphicsGradientFill.alphas : Array; +flash.display.GraphicsGradientFill.ratios : Array; +flash.display.GraphicsGradientFill.$type : GradientType; +flash.display.GraphicsGradientFill.$colors : Array; +flash.display.GraphicsGradientFill.$spreadMethod : SpreadMethod; +flash.display.GraphicsGradientFill.$interpolationMethod : InterpolationMethod; +flash.display.GraphicsGradientFill.$alphas : Array; +flash.display.GraphicsGradientFill.$ratios : Array; +flash.display.GraphicsGradientFill.$matrix : flash.geom.Matrix; + +flash.display.GraphicsPath.winding : GraphicsPathWinding; +flash.display.GraphicsPath.$winding : GraphicsPathWinding; + +flash.display.GraphicsStroke.scaleMode : LineScaleMode; +flash.display.GraphicsStroke.caps : CapsStyle; +flash.display.GraphicsStroke.joints : JointStyle; +flash.display.GraphicsStroke.$scaleMode : LineScaleMode; +flash.display.GraphicsStroke.$caps : CapsStyle; +flash.display.GraphicsStroke.$joints : JointStyle; + +flash.display.GraphicsTrianglePath.culling : TriangleCulling; +flash.display.GraphicsTrianglePath.$culling : TriangleCulling; + + +@:require(flash10) flash.display.Loader.unloadAndStop + +enum flash.display.ActionScriptVersion; +enum flash.display.ColorCorrection; +enum flash.display.ColorCorrectionSupport; + +-flash.display.LoaderInfo.new +flash.display.LoaderInfo.parameters : Dynamic; +flash.display.LoaderInfo.actionScriptVersion : ActionScriptVersion; + +-flash.display.MorphShape.new + +@:require(flash10) flash.display.MovieClip.currentFrameLabel +flash.display.MovieClip.currentLabels : Array; +flash.display.MovieClip.scenes : Array; + +flash.display.Scene.labels : Array; +flash.display.Scene.$labels : Array; + +@:require(flash10) flash.display.Shader; +flash.display.Shader.precisionHint : ShaderPrecision; + +-flash.display.ShaderParameter.new +flash.display.ShaderParameter.type : ShaderParameterType; + +-flash.display.Stage.new +flash.display.Stage.align : StageAlign; +flash.display.Stage.quality : StageQuality; +flash.display.Stage.scaleMode : StageScaleMode; +flash.display.Stage.colorCorrection : ColorCorrection; +flash.display.Stage.colorCorrectionSupport : ColorCorrectionSupport; +flash.display.Stage.displayState : StageDisplayState; +flash.display.Stage.displayState : StageDisplayState; + +@:require(flash10) flash.display.Stage.colorCorrection +@:require(flash10) flash.display.Stage.colorCorrectionSupport + +@:require(flash10_1) flash.errors.DRMManagerError +@:require(flash10_1) flash.events.AccelerometerEvent +@:require(flash10_1) flash.events.DRMAuthenticateEvent +@:require(flash10_1) flash.events.DRMAuthenticationCompleteEvent +@:require(flash10_1) flash.events.DRMAuthenticationErrorEvent +@:require(flash10_1) flash.events.DRMCustomProperties +@:require(flash10_1) flash.events.DRMErrorEvent +@:require(flash10_1) flash.events.DRMStatusEvent +@:require(flash10_1) flash.events.GeolocationEvent +@:require(flash10_1) flash.events.GestureEvent +@:require(flash10_1) flash.events.GesturePhase +@:require(flash10_1) flash.events.PressAndTapGestureEvent +@:require(flash10_1) flash.events.TouchEvent +@:require(flash10_1) flash.events.TransformGestureEvent +@:require(flash10_1) flash.events.UncaughtErrorEvent; +@:require(flash10_1) flash.events.UncaughtErrorEvents; + +@:require(flash10) static flash.events.Event.CLEAR; +@:require(flash10) static flash.events.Event.COPY; +@:require(flash10) static flash.events.Event.CUT; +@:require(flash10) static flash.events.Event.EXIT_FRAME; +@:require(flash10) static flash.events.Event.FRAME_CONSTRUCTED; +@:require(flash10) static flash.events.Event.PASTE; +@:require(flash10) static flash.events.Event.SELECT_ALL; + +@:require(flash10) flash.events.ContextMenuEvent.isMouseTargetInaccessible +@:require(flash10) flash.events.FocusEvent.isRelatedObjectInaccessible +@:require(flash10) flash.events.MouseEvent.isRelatedObjectInaccessible + +flash.events.IEventDispatcher.$listener : Dynamic -> Void; +flash.events.EventDispatcher.$listener : Dynamic -> Void; + +enum flash.events.EventPhase; +enum flash.events.GesturePhase; + +flash.events.Event.eventPhase : EventPhase; + +flash.events.KeyboardEvent.keyLocation : flash.ui.KeyLocation; +flash.events.KeyboardEvent.$keyLocationValue : flash.ui.KeyLocation; +flash.events.KeyboardEvent.$keyLocation : flash.ui.KeyLocation; + +@:require(flash10_1) flash.events.ErrorEvent.errorID; + +@:require(flash10_1) flash.events.HTTPStatusEvent.responseHeaders; +@:require(flash10_1) flash.events.HTTPStatusEvent.responseURL; +@:require(flash10_1) static flash.events.HTTPStatusEvent.HTTP_RESPONSE_STATUS; + +@:require(flash10_1) flash.events.IMEEvent.imeClient; +@:require(flash10_1) static flash.events.IMEEvent.IME_START_COMPOSITION; + +-flash.events.WeakFunctionClosure.new + +-flash.external.ExternalInterface.new + +enum flash.filters.BitmapFilterType; +enum flash.filters.DisplacementMapFilterMode; + +flash.filters.BevelFilter.type : BitmapFilterType; +flash.filters.BevelFilter.$type : BitmapFilterType; + +flash.filters.DisplacementMapFilter.mode : DisplacementMapFilterMode; +flash.filters.DisplacementMapFilter.$mode : DisplacementMapFilterMode; + +flash.filters.GradientGlowFilter.type : BitmapFilterType; +flash.filters.GradientGlowFilter.$type : BitmapFilterType; + +enum flash.geom.Orientation3D; + +flash.geom.Matrix3D.$orientationStyle : Orientation3D; + +@:require(flash10) flash.geom.Matrix3D; +@:require(flash10) flash.geom.Utils3D; +@:require(flash10) flash.geom.Vector3D; +@:require(flash10) flash.geom.PerspectiveProjection; +@:require(flash10) flash.geom.Transform.matrix3D; +@:require(flash10) flash.geom.Transform.perspectiveProjection; +@:require(flash10) flash.geom.Transform.getRelativeMatrix3D; + +-flash.geom.Utils3D.new + +@:require(flash10_1) static flash.media.Camera.isSupported; +@:require(flash10_1) static flash.media.Camera._scanHardware; + +enum flash.media.SoundCodec; + +flash.media.Microphone.codec : SoundCodec; + +@:require(flash10) flash.media.Microphone.codec; +@:require(flash10) flash.media.Microphone.encodeQuality; +@:require(flash10) flash.media.Microphone.framesPerPacket; + +@:require(flash10_1) flash.media.Microphone.enableVAD; +@:require(flash10_1) flash.media.Microphone.noiseSuppressionLevel; +@:require(flash10_1) static flash.media.Microphone.isSupported; + +@:require(flash10) flash.media.Sound.extract; + +@:require(flash10_1) flash.media.Sound.isURLInaccessible; + +@:require(flash10) flash.net.FileReference.data; +@:require(flash10) flash.net.FileReference.load; +@:require(flash10) flash.net.FileReference.save; + +-flash.media.SoundMixer.new + +@:require(flash10_1) flash.net.LocalConnection.isPerUser; +@:require(flash10_1) static flash.net.LocalConnection.isSupported; + +flash.net.FileReference.$typeFilter : Array; +flash.net.FileReferenceList.fileList : Array; +flash.net.FileReferenceList.$typeFilter : Array; + +@:require(flash10_1) flash.net.GroupSpecifier; +@:require(flash10_1) flash.net.NetGroup; +@:require(flash10_1) flash.net.NetGroupInfo; +@:require(flash10_1) flash.net.NetStreamMulticastInfo; + +@:require(flash10) flash.net.NetConnection.farID; +@:require(flash10) flash.net.NetConnection.farNonce; +@:require(flash10) flash.net.NetConnection.maxPeerConnections; +@:require(flash10) flash.net.NetConnection.nearID; +@:require(flash10) flash.net.NetConnection.nearNonce; +@:require(flash10) flash.net.NetConnection.protocol; +@:require(flash10) flash.net.NetConnection.unconnectedPeerStreams; + +@:require(flash10) flash.net.NetStream.farID; +@:require(flash10) flash.net.NetStream.farNonce; +@:require(flash10) flash.net.NetStream.info; +@:require(flash10) flash.net.NetStream.maxPauseBufferTime; +@:require(flash10) flash.net.NetStream.nearNonce; +@:require(flash10) flash.net.NetStream.peerStreams; +@:require(flash10) flash.net.NetStream.onPeerConnect; +@:require(flash10) flash.net.NetStream.play2; +@:require(flash10) static flash.net.NetStream.CONNECT_TO_FMS; +@:require(flash10) static flash.net.NetStream.DIRECT_CONNECTIONS; + +@:require(flash10_1) flash.net.NetStream.audioReliable; +@:require(flash10_1) flash.net.NetStream.audioSampleAccess; +@:require(flash10_1) flash.net.NetStream.backBufferLength; +@:require(flash10_1) flash.net.NetStream.backBufferTime; +@:require(flash10_1) flash.net.NetStream.bufferTimeMax; +@:require(flash10_1) flash.net.NetStream.dataReliable; +@:require(flash10_1) flash.net.NetStream.inBufferSeek; +@:require(flash10_1) flash.net.NetStream.multicastAvailabilitySendToAll; +@:require(flash10_1) flash.net.NetStream.multicastAvailabilityUpdatePeriod; +@:require(flash10_1) flash.net.NetStream.multicastFetchPeriod; +@:require(flash10_1) flash.net.NetStream.multicastInfo; +@:require(flash10_1) flash.net.NetStream.multicastPushNeighborLimit; +@:require(flash10_1) flash.net.NetStream.multicastRelayMarginDuration; +@:require(flash10_1) flash.net.NetStream.multicastWindowDuration; +@:require(flash10_1) flash.net.NetStream.videoReliable; +@:require(flash10_1) flash.net.NetStream.videoSampleAccess; +@:require(flash10_1) flash.net.NetStream.appendBytes; +@:require(flash10_1) flash.net.NetStream.appendBytesAction; +@:require(flash10_1) flash.net.NetStream.attach; +@:require(flash10_1) flash.net.NetStream.step; + +@:require(flash10_1) flash.net.NetStreamInfo.videoLossRate; + +@:require(flash10_1) flash.net.NetStreamPlayOptions.offset; + +@:require(flash10_1) static flash.net.URLRequestMethod.DELETE; +@:require(flash10_1) static flash.net.URLRequestMethod.HEAD; +@:require(flash10_1) static flash.net.URLRequestMethod.OPTIONS; +@:require(flash10_1) static flash.net.URLRequestMethod.PUT; + +@:require(flash10) flash.net.Socket.timeout; +@:require(flash10) flash.net.XMLSocket.timeout; + +-flash.net.ObjectEncoding.new +-flash.net.URLRequestMethod.new + +enum flash.net.URLLoaderDataFormat; + +flash.net.Socket.endian : flash.utils.Endian; +flash.net.URLLoader.dataFormat : URLLoaderDataFormat; +flash.net.URLRequest.requestHeaders : Array; +flash.net.URLStream.endian : flash.utils.Endian; + +enum flash.printing.PrintJobOrientation; + +flash.printing.PrintJob.orientation : PrintJobOrientation; +@:require(flash10_1) static flash.printing.PrintJob.isSupported; + +-flash.sampler.DeleteObjectSample.new +-flash.sampler.NewObjectSample.new +-flash.sampler.Sample.new +flash.sampler.Sample.stack : Array; +-flash.sampler.StackFrame.new +@:require(flash10_1) flash.sampler.NewObjectSample.size; +@:require(flash10_1) flash.sampler.StackFrame.scriptID; + +-flash.system.Capabilities.new +-flash.system.IME.new +-flash.system.FSCommand.new + +enum flash.system.IMEConversionMode; + +static flash.system.IME.conversionMode : IMEConversionMode + +@:require(flash10) flash.system.ApplicationDomain.domainMemory; +@:require(flash10) static flash.system.ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH; + +@:require(flash10) static flash.system.Capabilities.isEmbeddedInAcrobat; +@:require(flash10) static flash.system.Capabilities.maxLevelIDC; + +@:require(flash10_1) static flash.system.Capabilities.cpuArchitecture; +@:require(flash10_1) static flash.system.Capabilities.supports32BitProcesses; +@:require(flash10_1) static flash.system.Capabilities.supports64BitProcesses; +@:require(flash10_1) static flash.system.Capabilities.touchscreenType; +static flash.system.Capabilities.touchscreenType : TouchscreenType; + +enum flash.system.TouchscreenType; + + +@:require(flash10_1) static flash.system.IME.isSupported; +@:require(flash10_1) static flash.system.IME.compositionAbandoned; +@:require(flash10_1) static flash.system.IME.compositionSelectionChanged; + + +@:require(flash10) flash.system.JPEGLoaderContext; + + +@:require(flash10_1) flash.system.LoaderContext.allowCodeImport; +@:require(flash10_1) flash.system.LoaderContext.allowLoadBytesCodeExecution; + +@:require(flash10_1) static flash.system.Security.APPLICATION; +@:require(flash10_1) static flash.system.Security.duplicateSandboxBridgeInputArguments; +@:require(flash10_1) static flash.system.Security.duplicateSandboxBridgeOutputArgument; + +@:require(flash10_1) static flash.system.System.currentTime; +@:require(flash10_1) static flash.system.System.freeMemory; +@:require(flash10_1) static flash.system.System.preciseStartupTime; +@:require(flash10_1) static flash.system.System.privateMemory; +@:require(flash10_1) static flash.system.System.totalMemoryNumber; +@:require(flash10_1) static flash.system.System.disposeXML; +@:require(flash10_1) static flash.system.System.nativeConstructionOnly; + +enum flash.system.SecurityPanel; + +-flash.system.Security.new +flash.system.Security.$panel : SecurityPanel +-flash.system.SecurityDomain.new +-flash.system.System.new +flash.system.SystemUpdater.$typer : SystemAdapterType; + +enum flash.text.AntiAliasType; +enum flash.text.GridFitType; +enum flash.text.FontStyle; +enum flash.text.FontType; +enum flash.text.TextDisplayMode; +enum flash.text.TextFieldType; +enum flash.text.TextFieldAutoSize; +enum flash.text.TextFormatAlign; +enum flash.text.TextFormatDisplay; +enum flash.text.TextColorType; + +flash.text.Font.fontStyle : FontStyle; +flash.text.Font.fontType : FontType; +static flash.text.Font.enumerateFonts : Array; +flash.text.TextField.autoSize : TextFieldAutoSize; +flash.text.TextField.antiAliasType : AntiAliasType; +flash.text.TextField.gridFitType : GridFitType; +flash.text.TextField.type : TextFieldType; + +flash.text.TextFormat.align : TextFormatAlign; +flash.text.TextFormat.blockIndent : Null +flash.text.TextFormat.bold : Null; +flash.text.TextFormat.bullet : Null; +flash.text.TextFormat.color : Null; +flash.text.TextFormat.display : TextFormatDisplay; +flash.text.TextFormat.indent : Null; +flash.text.TextFormat.italic : Null; +flash.text.TextFormat.kerning : Null; +flash.text.TextFormat.leading : Null; +flash.text.TextFormat.leftMargin : Null; +flash.text.TextFormat.letterSpacing : Null; +flash.text.TextFormat.rightMargin : Null; +flash.text.TextFormat.size : Null; +flash.text.TextFormat.tabStops : Array; +flash.text.TextFormat.underline : Null; +flash.text.TextFormat.$size : Null; +flash.text.TextFormat.$color : Null; +flash.text.TextFormat.$bold : Null; +flash.text.TextFormat.$italic : Null; +flash.text.TextFormat.$underline : Null; +flash.text.TextFormat.$align : TextFormatAlign; +flash.text.TextFormat.$leftMargin : Null; +flash.text.TextFormat.$rightMargin : Null; +flash.text.TextFormat.$indent : Null; +flash.text.TextFormat.$leading : Null; + +@:require(flash10) static flash.text.TextField.isFontCompatible; + +-flash.text.TextRenderer.new +static flash.text.TextRenderer.antiAliasType : AntiAliasType; +static flash.text.TextRenderer.displayMode : TextDisplayMode; +flash.text.TextRenderer.$fontStyle : FontStyle; +flash.text.TextRenderer.$colorType : TextColorType; + +@:require(flash10_1) static flash.text.engine.FontDescription.isDeviceFontCompatible; +@:require(flash10_1) flash.text.engine.SpaceJustifier.maximumSpacing; +@:require(flash10_1) flash.text.engine.SpaceJustifier.minimumSpacing; +@:require(flash10_1) flash.text.engine.SpaceJustifier.optimumSpacing; +@:require(flash10_1) flash.text.engine.TextBlock.recreateTextLine; +@:require(flash10_1) flash.text.engine.TextBlock.releaseLineCreationData; +@:require(flash10_1) flash.text.engine.TextLine.hasTabs; + +flash.text.engine.ContentElement.textRotation : TextRotation; +flash.text.engine.ContentElement.$textRotation : TextRotation; + +flash.text.engine.EastAsianJustifier.justificationStyle : JustificationStyle; +flash.text.engine.EastAsianJustifier.$justificationStyle : JustificationStyle; +flash.text.engine.EastAsianJustifier.$lineJustification : LineJustification; + +enum flash.text.engine.BreakOpportunity; +enum flash.text.engine.CFFHinting; +enum flash.text.engine.DigitCase; +enum flash.text.engine.DigitWidth; +enum flash.text.engine.FontLookup; +enum flash.text.engine.FontPosture; +enum flash.text.engine.FontWeight; +enum flash.text.engine.JustificationStyle; +enum flash.text.engine.Kerning; +enum flash.text.engine.LigatureLevel; +enum flash.text.engine.LineJustification; +enum flash.text.engine.RenderingMode; +enum flash.text.engine.TabAlignment; +enum flash.text.engine.TextBaseline; +enum flash.text.engine.TextLineCreationResult; +enum flash.text.engine.TextLineValidity; +enum flash.text.engine.TextRotation; +enum flash.text.engine.TypographicCase; + + +flash.text.engine.ElementFormat.alignmentBaseline : TextBaseline; +flash.text.engine.ElementFormat.breakOpportunity : BreakOpportunity; +flash.text.engine.ElementFormat.digitCase : DigitCase; +flash.text.engine.ElementFormat.digitWidth : DigitWidth; +flash.text.engine.ElementFormat.dominantBaseline : TextBaseline; +flash.text.engine.ElementFormat.kerning : Kerning; +flash.text.engine.ElementFormat.ligatureLevel : LigatureLevel; +flash.text.engine.ElementFormat.textRotation : TextRotation; +flash.text.engine.ElementFormat.typographicCase : TypographicCase; +flash.text.engine.ElementFormat.$alignmentBaseline : TextBaseline; +flash.text.engine.ElementFormat.$breakOpportunity : BreakOpportunity; +flash.text.engine.ElementFormat.$digitCase : DigitCase; +flash.text.engine.ElementFormat.$digitWidth : DigitWidth; +flash.text.engine.ElementFormat.$dominantBaseline : TextBaseline; +flash.text.engine.ElementFormat.$kerning : Kerning; +flash.text.engine.ElementFormat.$ligatureLevel : LigatureLevel; +flash.text.engine.ElementFormat.$textRotation : TextRotation; +flash.text.engine.ElementFormat.$typographicCase : TypographicCase; + +flash.text.engine.FontDescription.cffHinting : CFFHinting; +flash.text.engine.FontDescription.fontLookup : FontLookup; +flash.text.engine.FontDescription.fontPosture : FontPosture; +flash.text.engine.FontDescription.fontWeight : FontWeight; +flash.text.engine.FontDescription.renderingMode : RenderingMode; +flash.text.engine.FontDescription.$cffHinting : CFFHinting; +flash.text.engine.FontDescription.$fontLookup : FontLookup; +flash.text.engine.FontDescription.$fontPosture : FontPosture; +flash.text.engine.FontDescription.$fontWeight : FontWeight; +flash.text.engine.FontDescription.$renderingMode : RenderingMode; + +flash.text.engine.GraphicElement.$textRotation : TextRotation; +flash.text.engine.GroupElement.$textRotation : TextRotation; +flash.text.engine.SpaceJustifier.$lineJustification : LineJustification; +flash.text.engine.TabStop.alignment : TabAlignment; +flash.text.engine.TabStop.$alignment : TabAlignment; + +flash.text.engine.TextBlock.baselineZero : TextBaseline; +flash.text.engine.TextBlock.lineRotation : TextRotation; +flash.text.engine.TextBlock.textLineCreationResult : TextLineCreationResult; +flash.text.engine.TextBlock.$baselineZero : TextBaseline; +flash.text.engine.TextBlock.$lineRotation : TextRotation; +flash.text.engine.TextBlock.$textLineCreationResult : TextLineCreationResult; + +flash.text.engine.TextElement.$textRotation : TextRotation; + +flash.text.engine.TextJustifier.lineJustification : LineJustification; +flash.text.engine.TextJustifier.$lineJustification : LineJustification; + +flash.text.engine.TextLine.baseline : TextBaseline; + +-flash.trace.Trace.new + +-static flash.xml.XMLList.length +-static flash.xml.XML.length +-flash.text.engine.TextElement.text + +-flash.ui.Keyboard.new +-flash.ui.Mouse.new + +enum flash.ui.MultitouchInputMode; + +-flash.ui.Multitouch.new +flash.ui.Multitouch.inputMode : MultitouchInputMode; + +@:require(flash10) flash.ui.ContextMenu.clipboardItems; +@:require(flash10) flash.ui.ContextMenu.clipboardMenu; +@:require(flash10) flash.ui.ContextMenu.link; + +@:require(flash10_1) static flash.ui.ContextMenu.isSupported; + +@:require(flash10) static flash.ui.Mouse.cursor; +static flash.ui.Mouse.cursor : Dynamic; + +@:require(flash10_1) static flash.ui.Keyboard.A; +@:require(flash10_1) static flash.ui.Keyboard.B; +@:require(flash10_1) static flash.ui.Keyboard.C; +@:require(flash10_1) static flash.ui.Keyboard.D; +@:require(flash10_1) static flash.ui.Keyboard.E; +@:require(flash10_1) static flash.ui.Keyboard.F; +@:require(flash10_1) static flash.ui.Keyboard.G; +@:require(flash10_1) static flash.ui.Keyboard.H; +@:require(flash10_1) static flash.ui.Keyboard.I; +@:require(flash10_1) static flash.ui.Keyboard.J; +@:require(flash10_1) static flash.ui.Keyboard.K; +@:require(flash10_1) static flash.ui.Keyboard.L; +@:require(flash10_1) static flash.ui.Keyboard.M; +@:require(flash10_1) static flash.ui.Keyboard.N; +@:require(flash10_1) static flash.ui.Keyboard.O; +@:require(flash10_1) static flash.ui.Keyboard.P; +@:require(flash10_1) static flash.ui.Keyboard.Q; +@:require(flash10_1) static flash.ui.Keyboard.R; +@:require(flash10_1) static flash.ui.Keyboard.S; +@:require(flash10_1) static flash.ui.Keyboard.T; +@:require(flash10_1) static flash.ui.Keyboard.U; +@:require(flash10_1) static flash.ui.Keyboard.V; +@:require(flash10_1) static flash.ui.Keyboard.W; +@:require(flash10_1) static flash.ui.Keyboard.X; +@:require(flash10_1) static flash.ui.Keyboard.Y; +@:require(flash10_1) static flash.ui.Keyboard.Z; +@:require(flash10_1) static flash.ui.Keyboard.ALTERNATE; +@:require(flash10_1) static flash.ui.Keyboard.BACKQUOTE; +@:require(flash10_1) static flash.ui.Keyboard.BACKSLASH; +@:require(flash10_1) static flash.ui.Keyboard.COMMA; +@:require(flash10_1) static flash.ui.Keyboard.COMMAND; +@:require(flash10_1) static flash.ui.Keyboard.CharCodeStrings; +@:require(flash10_1) static flash.ui.Keyboard.EQUAL; +@:require(flash10_1) static flash.ui.Keyboard.LEFTBRACKET; +@:require(flash10_1) static flash.ui.Keyboard.MINUS; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_0; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_1; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_2; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_3; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_4; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_5; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_6; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_7; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_8; +@:require(flash10_1) static flash.ui.Keyboard.NUMBER_9; +@:require(flash10_1) static flash.ui.Keyboard.NUMPAD; +@:require(flash10_1) static flash.ui.Keyboard.PERIOD; +@:require(flash10_1) static flash.ui.Keyboard.QUOTE; +@:require(flash10_1) static flash.ui.Keyboard.RIGHTBRACKET; +@:require(flash10_1) static flash.ui.Keyboard.SEMICOLON; +@:require(flash10_1) static flash.ui.Keyboard.SLASH; +@:require(flash10_1) static flash.ui.Keyboard.hasVirtualKeyboard; +@:require(flash10_1) static flash.ui.Keyboard.physicalKeyboardType; + +enum flash.ui.KeyboardType; +enum flash.ui.KeyLocation; + +static flash.ui.Keyboard.physicalKeyboardType : KeyboardType; + +@:require(flash10_1) flash.ui.Multitouch; +static flash.ui.Multitouch.inputMode : MultitouchInputMode; +@:require(flash10_1) flash.ui.MultitouchInputMode; + +@:require(flash10_1) static flash.ui.Keyboard.STRING_BEGIN; +@:require(flash10_1) static flash.ui.Keyboard.STRING_BREAK; +@:require(flash10_1) static flash.ui.Keyboard.STRING_CLEARDISPLAY; +@:require(flash10_1) static flash.ui.Keyboard.STRING_CLEARLINE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETECHAR; +@:require(flash10_1) static flash.ui.Keyboard.STRING_DELETELINE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_DOWNARROW; +@:require(flash10_1) static flash.ui.Keyboard.STRING_END; +@:require(flash10_1) static flash.ui.Keyboard.STRING_EXECUTE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F1; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F10; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F11; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F12; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F13; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F14; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F15; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F16; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F17; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F18; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F19; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F2; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F20; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F21; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F22; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F23; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F24; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F25; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F26; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F27; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F28; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F29; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F3; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F30; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F31; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F32; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F33; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F34; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F35; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F4; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F5; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F6; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F7; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F8; +@:require(flash10_1) static flash.ui.Keyboard.STRING_F9; +@:require(flash10_1) static flash.ui.Keyboard.STRING_FIND; +@:require(flash10_1) static flash.ui.Keyboard.STRING_HELP; +@:require(flash10_1) static flash.ui.Keyboard.STRING_HOME; +@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERT; +@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERTCHAR; +@:require(flash10_1) static flash.ui.Keyboard.STRING_INSERTLINE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_LEFTARROW; +@:require(flash10_1) static flash.ui.Keyboard.STRING_MENU; +@:require(flash10_1) static flash.ui.Keyboard.STRING_MODESWITCH; +@:require(flash10_1) static flash.ui.Keyboard.STRING_NEXT; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PAGEDOWN; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PAGEUP; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PAUSE; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PREV; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PRINT; +@:require(flash10_1) static flash.ui.Keyboard.STRING_PRINTSCREEN; +@:require(flash10_1) static flash.ui.Keyboard.STRING_REDO; +@:require(flash10_1) static flash.ui.Keyboard.STRING_RESET; +@:require(flash10_1) static flash.ui.Keyboard.STRING_RIGHTARROW; +@:require(flash10_1) static flash.ui.Keyboard.STRING_SCROLLLOCK; +@:require(flash10_1) static flash.ui.Keyboard.STRING_SELECT; +@:require(flash10_1) static flash.ui.Keyboard.STRING_STOP; +@:require(flash10_1) static flash.ui.Keyboard.STRING_SYSREQ; +@:require(flash10_1) static flash.ui.Keyboard.STRING_SYSTEM; +@:require(flash10_1) static flash.ui.Keyboard.STRING_UNDO; +@:require(flash10_1) static flash.ui.Keyboard.STRING_UPARROW; +@:require(flash10_1) static flash.ui.Keyboard.STRING_USER; + +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_BEGIN; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_BREAK; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_CLEARDISPLAY; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_CLEARLINE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETECHAR; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DELETELINE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_DOWNARROW; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_END; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_EXECUTE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F1; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F10; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F11; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F12; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F13; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F14; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F15; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F16; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F17; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F18; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F19; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F2; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F20; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F21; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F22; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F23; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F24; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F25; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F26; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F27; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F28; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F29; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F3; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F30; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F31; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F32; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F33; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F34; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F35; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F4; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F5; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F6; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F7; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F8; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_F9; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_FIND; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_HELP; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_HOME; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERT; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERTCHAR; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_INSERTLINE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_LEFTARROW; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_MENU; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_MODESWITCH; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_NEXT; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAGEDOWN; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAGEUP; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PAUSE; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PREV; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PRINT; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_PRINTSCREEN; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_REDO; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_RESET; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_RIGHTARROW; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SCROLLLOCK; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SELECT; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_STOP; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SYSREQ; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_SYSTEM; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_UNDO; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_UPARROW; +@:require(flash10_1) static flash.ui.Keyboard.KEYNAME_USER; + +@:require(flash10_1) static flash.ui.Mouse.supportsCursor; + +enum flash.utils.Endian; + +@:native("RegExp") flash.utils.RegExp; +-static flash.utils.RegExp.length; + +flash.utils.ObjectInput.endian : Endian; +flash.utils.ObjectOutput.endian : Endian; +flash.utils.ByteArray.endian : Endian; +flash.utils.IDataInput.endian : Endian; +flash.utils.IDataOutput.endian : Endian; + +@:require(flash10) flash.utils.ByteArray.clear; +@:require(flash10) flash.utils.ByteArray.deflate; +@:require(flash10) flash.utils.ByteArray.inflate; + +@:require(flash10) flash.utils.SetIntervalTimer.clearArrayEntry; + +-flash.utils.Namespace.toString +-flash.utils.Namespace.valueOf +-static flash.utils.Namespace.length + +-flash.utils.QName.toString +-flash.utils.QName.valueOf +-static flash.utils.QName.length + +enum flash.xml.XMLNodeType; + +flash.xml.XMLNode.nodeType : XMLNodeType; +flash.xml.XMLNode.$type : XMLNodeType; + +flash.xml.XML.namespace : flash.utils.Namespace; +flash.xml.XML.parent : XML; +flash.xml.XMLList.namespace : flash.utils.Namespace; +flash.xml.XMLList.parent : XML; +flash.xml.XMLTag.type : XMLNodeType; + + +enum flash.system.SystemUpdaterType; + +@:require(flash10_1) flash.system.SystemUpdater; +flash.system.SystemUpdater.$type : SystemUpdaterType; + +@:require(flash10_1) flash.sensors.Accelerometer; +@:require(flash10_1) flash.sensors.Geolocation; + +@:require(flash10_1) flash.globalization.Collator; +@:require(flash10_1) flash.globalization.CurrencyFormatter; +@:require(flash10_1) flash.globalization.DateTimeFormatter; +@:require(flash10_1) flash.globalization.LocaleID; +@:require(flash10_1) flash.globalization.StringTools; +@:require(flash10_1) flash.globalization.NumberFormatter; +@:require(flash10_1) flash.globalization.NumberParseResult; + +enum flash.globalization.CollatorMode; +enum flash.globalization.DateTimeNameContext; +enum flash.globalization.DateTimeNameStyle; +enum flash.globalization.DateTimeStyle; +enum flash.globalization.LastOperationStatus; +enum flash.globalization.NationalDigitsType; + +flash.globalization.Collator.lastOperationStatus : LastOperationStatus; +flash.globalization.Collator.$initialMode : CollatorMode; +flash.globalization.CurrencyFormatter.lastOperationStatus : LastOperationStatus; + +flash.globalization.DateTimeFormatter.lastOperationStatus : LastOperationStatus; +flash.globalization.DateTimeFormatter.$dateStyle : DateTimeStyle; +flash.globalization.DateTimeFormatter.$nameStyle : DateTimeNameStyle; +flash.globalization.DateTimeFormatter.$timeStyle : DateTimeStyle; +flash.globalization.DateTimeFormatter.$context : DateTimeNameContext; +flash.globalization.DateTimeFormatter.getDateStyle : DateTimeStyle; +flash.globalization.DateTimeFormatter.getTimeStyle : DateTimeStyle; +flash.globalization.DateTimeFormatter.getDateTimePattern : DateTimeStyle; +flash.globalization.LocaleID.lastOperationStatus : LastOperationStatus; +flash.globalization.NumberFormatter.lastOperationStatus : LastOperationStatus; +flash.globalization.NumberFormatter.digitsType : NationalDigitsType; +flash.globalization.StringTools.lastOperationStatus : LastOperationStatus; + +// FP 10.2 + +@:require(flash10_2) flash.ui.MouseCursorData; +@:require(flash10_2) flash.events.StageVideoEvent; +@:require(flash10_2) flash.events.VideoEvent; +@:require(flash10_2) flash.media.MicrophoneEnhancedMode; +@:require(flash10_2) flash.media.MicrophoneEnhancedOptions; +@:require(flash10_2) flash.media.StageVideo; + +@:require(flash10_2) flash.display.Stage.color; +@:require(flash10_2) flash.display.Stage.stageVideos; + +@:require(flash10_2) flash.media.Microphone.enhancedOptions; +@:require(flash10_2) static flash.media.Microphone.getEnhancedMicrophone; + +@:require(flash10_2) flash.system.Capabilities.allowsFullScreen; + +@:require(flash10_2) static flash.ui.Keyboard.AUDIO; +@:require(flash10_2) static flash.ui.Keyboard.BACK; +@:require(flash10_2) static flash.ui.Keyboard.BLUE; +@:require(flash10_2) static flash.ui.Keyboard.CHANNEL_DOWN; +@:require(flash10_2) static flash.ui.Keyboard.CHANNEL_UP; +@:require(flash10_2) static flash.ui.Keyboard.DVR; +@:require(flash10_2) static flash.ui.Keyboard.EXIT; +@:require(flash10_2) static flash.ui.Keyboard.FAST_FORWARD; +@:require(flash10_2) static flash.ui.Keyboard.GREEN; +@:require(flash10_2) static flash.ui.Keyboard.GUIDE; +@:require(flash10_2) static flash.ui.Keyboard.HELP; +@:require(flash10_2) static flash.ui.Keyboard.INFO; +@:require(flash10_2) static flash.ui.Keyboard.INPUT; +@:require(flash10_2) static flash.ui.Keyboard.LAST; +@:require(flash10_2) static flash.ui.Keyboard.LIVE; +@:require(flash10_2) static flash.ui.Keyboard.MASTER_SHELL; +@:require(flash10_2) static flash.ui.Keyboard.MENU; +@:require(flash10_2) static flash.ui.Keyboard.NEXT; +@:require(flash10_2) static flash.ui.Keyboard.PAUSE; +@:require(flash10_2) static flash.ui.Keyboard.PLAY; +@:require(flash10_2) static flash.ui.Keyboard.PREVIOUS; +@:require(flash10_2) static flash.ui.Keyboard.RECORD; +@:require(flash10_2) static flash.ui.Keyboard.RED; +@:require(flash10_2) static flash.ui.Keyboard.REWIND; +@:require(flash10_2) static flash.ui.Keyboard.SEARCH; +@:require(flash10_2) static flash.ui.Keyboard.SETUP; +@:require(flash10_2) static flash.ui.Keyboard.SKIP_BACKWARD; +@:require(flash10_2) static flash.ui.Keyboard.SKIP_FORWARD; +@:require(flash10_2) static flash.ui.Keyboard.STOP; +@:require(flash10_2) static flash.ui.Keyboard.SUBTITLE; +@:require(flash10_2) static flash.ui.Keyboard.VOD; +@:require(flash10_2) static flash.ui.Keyboard.YELLOW; + +@:require(flash10_2) static flash.ui.Mouse.registerCursor; + +enum flash.media.MicrophoneEnhancedMode; + +flash.media.MicrophoneEnhancedOptions.mode : MicrophoneEnhancedMode; + +enum flash.display.FocusDirection; + + +// FLASH 11 FEATURES + +-flash.automation.Configuration.new + +@:require(flash11) flash.display.DisplayObjectContainer.removeChildren; +@:require(flash11) flash.display.Graphics.cubicCurveTo; +@:require(flash11) flash.display.GraphicsPath.cubicCurveTo; + +@:require(flash11) flash.display.InteractiveObject.needsSoftKeyboard; +@:require(flash11) flash.display.InteractiveObject.softKeyboardInputAreaOfInterest; +@:require(flash11) flash.display.InteractiveObject.requestSoftKeyboard; + +@:require(flash11) flash.display.MovieClip.isPlaying; + +@:require(flash11) flash.display.Stage.displayContextInfo; +@:require(flash11) flash.display.Stage.softKeyboardRect; +@:require(flash11) flash.display.Stage.stage3Ds; +@:require(flash11) flash.display.Stage3D; + +-flash.display.Stage.constructor; +-flash.display.Stage.hasOwnProperty; +-flash.display.Stage.isPrototypeOf; +-flash.display.Stage.propertyIsEnumerable; +-flash.display.Stage.setPropertyIsEnumerable; +-flash.display.Stage.toLocaleString; +-flash.display.Stage.valueOf; + +enum flash.display3D.Context3DBlendFactor; +enum flash.display3D.; + +@:require(flash11) static flash.events.Event.CONTEXT3D_CREATE; +@:require(flash11) static flash.events.Event.TEXT_INTERACTION_MODE_CHANGE; + +@:require(flash11) static flash.events.StageVideoEvent.RENDER_STATUS_AVAILABLE; +@:require(flash11) static flash.events.StageVideoEvent.STAGE_VIDEO_STATE; + +@:require(flash11) flash.geom.Matrix3D.copyColumnFrom; +@:require(flash11) flash.geom.Matrix3D.copyColumnTo; +@:require(flash11) flash.geom.Matrix3D.copyFrom; +@:require(flash11) flash.geom.Matrix3D.copyRawDataFrom; +@:require(flash11) flash.geom.Matrix3D.copyRawDataTo; +@:require(flash11) flash.geom.Matrix3D.copyRowFrom; +@:require(flash11) flash.geom.Matrix3D.copyRowTo; +@:require(flash11) flash.geom.Matrix3D.copyToMatrix3D; + +@:require(flash11) flash.geom.Matrix.copyColumnFrom; +@:require(flash11) flash.geom.Matrix.copyColumnTo; +@:require(flash11) flash.geom.Matrix.copyFrom; +@:require(flash11) flash.geom.Matrix.copyRowFrom; +@:require(flash11) flash.geom.Matrix.copyRowTo; +@:require(flash11) flash.geom.Matrix.setTo; + +@:require(flash11) flash.geom.Point.copyFrom; +@:require(flash11) flash.geom.Point.setTo; + +@:require(flash11) flash.geom.Rectangle.copyFrom; +@:require(flash11) flash.geom.Rectangle.setTo; + +@:require(flash11) flash.geom.Vector3D.copyFrom; +@:require(flash11) flash.geom.Vector3D.setTo; + + + +@:require(flash11) flash.media.Sound.loadCompressedDataFromByteArray; +@:require(flash11) flash.media.Sound.loadPCMFromByteArray; + +@:require(flash11) flash.net.Socket.bytesPending; + +-flash.display3D.Context3DClearMask.new; +enum flash.display3D.Context3DCompareMode; +enum flash.display3D.Context3DProgramType; +enum flash.display3D.Context3DRenderMode; +enum flash.display3D.Context3DStencilAction; +enum flash.display3D.Context3DTextureFormat; +enum flash.display3D.Context3DTriangleFace; +enum flash.display3D.Context3DVertexBufferFormat; + +-flash.display.Stage3D.new; +-flash.display3D.Context3D.new; +-flash.display3D.IndexBuffer3D.new; +-flash.display3D.Program3D.new; +-flash.display3D.VertexBuffer3D.new; +-flash.display3D.textures.CubeTexture.new; +-flash.display3D.textures.TextureBase.new; +-flash.display3D.textures.Texture.new; + +flash.display3D.Context3D.$sourceFactor : Context3DBlendFactor; +flash.display3D.Context3D.$destinationFactor : Context3DBlendFactor; +flash.display3D.Context3D.$format : Context3DTextureFormat; +flash.display3D.Context3D.$triangleFaceToCull : Context3DTriangleFace; +flash.display3D.Context3D.$triangleFace : Context3DTriangleFace; +flash.display3D.Context3D.$passCompareMode : Context3DCompareMode; +flash.display3D.Context3D.$compareMode : Context3DCompareMode; +flash.display3D.Context3D.$programType : Context3DProgramType; +flash.display3D.Context3D.$actionOnBothPass : Context3DStencilAction; +flash.display3D.Context3D.$actionOnDepthFail : Context3DStencilAction; +flash.display3D.Context3D.$actionOnDepthPassStencilFail : Context3DStencilAction; +flash.display3D.Context3D.$setVertexBufferAt__format : Context3DVertexBufferFormat; + +@:require(flash11) flash.net.NetStream.useHardwareDecoder; +@:require(flash11) flash.net.NetStream.videoStreamSettings; + +@:require(flash11) flash.net.SecureSocket; +@:require(flash11) flash.net.NetMonitor; + +@:require(flash11) static flash.system.Capabilities.hasMultiChannelAudio; + +@:require(flash11) flash.system.LoaderContext.imageDecodingPolicy; +@:require(flash11) flash.system.LoaderContext.parameters; +@:require(flash11) flash.system.LoaderContext.requestedContentParent; + +enum flash.system.ImageDecodingPolicy; + +flash.system.LoaderContext.imageDecodingPolicy : ImageDecodingPolicy; + +@:require(flash11) static flash.system.Security.pageDomain; + +@:require(flash11) static flash.system.System.processCPUUsage; +@:require(flash11) static flash.system.System.pauseForGCIfCollectionImminent; + +@:require(flash11) static flash.ui.Mouse.supportsNativeCursor; +@:require(flash11) static flash.ui.Mouse.unregisterCursor; + +-flash.ui.MouseCursor.new; + +@:require(flash11) flash.utils.CompressionAlgorithm; +enum flash.utils.CompressionAlgorithm; + +@:require(flash11) flash.xml.XML.toJSON; +@:require(flash11) flash.xml.XMLList.toJSON; + +flash.utils.ByteArray.$algorithm : CompressionAlgorithm; + +@:require(flash11) flash.text.TextField.textInteractionMode; + +enum flash.text.TextInteractionMode; + +flash.text.TextField.textInteractionMode : TextInteractionMode; + +// 11.2 + +enum flash.display.BitmapCompressColorSpace; + +@:require(flash11_2) flash.display.BitmapData.compress; +@:require(flash11_2) flash.media.Camera.position; +@:require(flash11_2) flash.net.NetStream.dispose; + +@:require(flash11_2) flash.display.StageWorker; +@:require(flash11_2) flash.display.Worker; +@:require(flash11_8) flash.events.GameInputEvent; +@:require(flash11_2) flash.events.ThrottleEvent; + +flash.events.ThrottleEvent.$type : ThrottleType; + +enum flash.events.ThrottleType; + +@:require(flash11_8) flash.ui.GameInput; +@:require(flash11_8) flash.ui.GameInputDevice; +-flash.ui.GameInput.new; + +@:require(flash11_2) flash.utils.Telemetry; + +enum flash.ui.GameInputFinger; +enum flash.ui.GameInputHand; +enum flash.ui.GameInputControlType; + +flash.ui.GameInputControl.finger : flash.ui.GameInputFinger; +flash.ui.GameInputControl.hand : flash.ui.GameInputHand; +flash.ui.GameInputControl.type : flash.ui.GameInputControlType; + + +// 11.2 + +@:require(flash11_2) flash.display3D.Context3D.setProgramConstantsFromByteArray +@:require(flash11_2) flash.display.Stage.mouseLock; + +@:require(flash11_2) flash.events.MouseEvent.movementX; +@:require(flash11_2) flash.events.MouseEvent.movementY; + +@:require(flash11_2) static flash.events.MouseEvent.CONTEXT_MENU; +@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_CLICK; +@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_MOUSE_DOWN; +@:require(flash11_2) static flash.events.MouseEvent.MIDDLE_MOUSE_UP; +@:require(flash11_2) static flash.events.MouseEvent.RIGHT_CLICK; +@:require(flash11_2) static flash.events.MouseEvent.RIGHT_MOUSE_DOWN; +@:require(flash11_2) static flash.events.MouseEvent.RIGHT_MOUSE_UP; + + +// 11.3 + +@:require(flash11_3) flash.display.BitmapData.drawWithQuality + +flash.display.BitmapData.$quality : StageQuality; + +enum flash.display.BitmapEncodingColorSpace; + +flash.display.JPEGXREncoderOptions.$colorSpace : BitmapEncodingColorSpace; +flash.display.JPEGXREncoderOptions.colorSpace : BitmapEncodingColorSpace; + +@:require(flash11_3) flash.display.BitmapData.encode +@:require(flash11_3) flash.display.Stage.allowsFullScreenInteractive + +@:require(flash11_3) static flash.events.Event.FRAME_LABEL; +@:require(flash11_3) static flash.events.Event.SUSPEND; + +@:require(flash11_3) static flash.events.FullScreenEvent.FULL_SCREEN_INTERACTIVE_ACCEPTED; +@:require(flash11_3) flash.events.FullScreenEvent.interactive; + +@:require(flash11_3) static flash.events.MouseEvent.RELEASE_OUTSIDE; + +@:require(flash11_3) flash.net.NetStream.useJitterBuffer; + +@:require(flash11_3) flash.system.ApplicationDomain.getQualifiedDefinitionNames; + +@:require(flash11_3) flash.system.SecurityDomain.domainID; + +@:require(flash11_3) flash.system.ApplicationInstaller; +@:require(flash11_3) flash.system.AuthorizedFeatures; +@:require(flash11_3) flash.system.AuthorizedFeaturesLoader; + +@:require(flash11_3) static flash.events.Event.TEXTURE_READY; + + +// 11.4 + +@:require(flash11_4) flash.display.BitmapData.copyPixelsToByteArray; + +@:require(flash11_4) flash.concurrent.Mutex; +@:require(flash11_4) flash.concurrent.Condition; + +enum flash.display3D.Context3DProfile; + +flash.display.Stage3D.$profile : flash.display3D.Context3DProfile; + +@:require(flash11_4) flash.display.LoaderInfo.childSandboxBridge; +@:require(flash11_4) flash.display.LoaderInfo.parentSandboxBridge; + +@:require(flash11_4) flash.display.Stage.contentsScaleFactor; + + +@:require(flash11_4) flash.media.Camera.copyToByteArray; +@:require(flash11_4) flash.media.Camera.copyToVector; +@:require(flash11_4) flash.media.Camera.drawToBitmapData; +@:require(flash11_4) flash.media.StageVideo.attachCamera; + +@:require(flash11_4) flash.net.URLStream.diskCacheEnabled; +@:require(flash11_4) flash.net.URLStream.length; +@:require(flash11_4) flash.net.URLStream.position; +@:require(flash11_4) flash.net.URLStream.stop; + +@:require(flash11_4) flash.system.AuthorizedFeatures.enableDiskCache; +@:require(flash11_4) flash.system.AuthorizedFeatures.isFeatureEnabled; +@:require(flash11_4) flash.system.AuthorizedFeatures.isNegativeToken; +@:require(flash11_4) flash.system.AuthorizedFeaturesLoader.makeGlobal; + +@:require(flash11_4) flash.utils.ByteArray.shareable; +@:require(flash11_4) flash.utils.ByteArray.atomicCompareAndSwapIntAt; +@:require(flash11_4) flash.utils.ByteArray.atomicCompareAndSwapLength; + +//not supported @:require(flash11_4) flash.utils.CompressionAlgorithm.LZMA; + +@:require(flash11_4) flash.system.Worker; +@:require(flash11_4) flash.system.WorkerDomain; + +@:require(flash11_4) flash.system.MessageChannel; + +-flash.system.Worker.new; +-flash.system.MessageChannel.new; + +flash.system.Worker.state : WorkerState; +flash.system.MessageChannel.state : MessageChannelState; + +enum flash.system.WorkerState; + + +// --- 11.6 API + +enum flash.display3D.Context3DMipFilter +enum flash.display3D.Context3DTextureFilter +enum flash.display3D.Context3DWrapMode +enum flash.system.ApplicationInstallerMode + +@:require(flash11_6) flash.display3D.Context3D.setSamplerStateAt +flash.display3D.Context3D.$wrap : Context3DWrapMode; +flash.display3D.Context3D.$filter : Context3DTextureFilter; +flash.display3D.Context3D.$mipfilter : Context3DMipFilter; + +-flash.display.DisplayObject.metaData + +@:require(flash11_6) flash.display.Graphics.readGraphicsData + +@:require(flash11_7) flash.media.StageVideo.attachAVStream; +@:require(flash11_7) static flash.net.SharedObject.preventBackup; +@:require(flash11_7) flash.system.AuthorizedFeatures.enableHLSPlayback; +@:require(flash11_7) flash.system.AuthorizedFeaturesLoader.loadAuthorizedFeaturesFromData; + + +@:require(flash11_8) flash.display.DisplayObjectContainer.stopAllMovieClips +@:require(flash11_8) flash.display3D.Context3D.createRectangleTexture + +@:require(flash12) flash.display.Stage3D.requestContext3DMatchingProfiles +@:require(flash12) flash.display3D.Context3D.profile + +flash.display3D.Context3D.$bufferUsage : Context3DBufferUsage +enum flash.display3D.Context3DBufferUsage + +@:native("flash.profiler.Telemetry") flash.utils.Telemetry + +@:require(flash12) flash.display3D.Context3DBufferUsage + + diff --git a/extra/haxelib_src/.travis.yml b/extra/haxelib_src/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..da1248d01cdf6fb7c351cb24eb71cb2194e58841 --- /dev/null +++ b/extra/haxelib_src/.travis.yml @@ -0,0 +1,8 @@ +language: haxe + +haxe: + - development + - "3.1.3" + +script: + - ./test.sh \ No newline at end of file diff --git a/extra/haxelib_src/Package.hx b/extra/haxelib_src/Package.hx new file mode 100644 index 0000000000000000000000000000000000000000..e283915790ee1055bb36879b85d1cbda64dfd1a5 --- /dev/null +++ b/extra/haxelib_src/Package.hx @@ -0,0 +1,63 @@ +import Sys.*; +import sys.*; +import sys.io.*; +import haxe.io.*; + +class Package { + static function cp(srcFile:String, destFile:String):Void { + File.saveBytes(destFile, File.getBytes(srcFile)); + } + + static function zip(srcFolder:String, destFile:String):Void { + switch (Sys.systemName()) { + case "Linux", "Mac": + command("zip", ["-r", destFile, srcFolder]); + case "Windows": + command("7za", ["a", "-tzip", "-r", destFile, srcFolder]); + } + } + + /** + Make directory recursively. + It is needed for Haxe 3.1.3, which FileSystem.createDirectory is not recursive. + */ + static function mkdir(path:String):Void { + #if (haxe_ver < 3.2) + path = Path.normalize(path); + + if (FileSystem.exists(path)) { + return; + } + + var parent = path.substring(0, path.lastIndexOf("/")); + if (parent != "") + mkdir(parent); + #end + + FileSystem.createDirectory(path); + } + + static function main():Void { + mkdir("package/src/tools/haxelib"); + + for (file in [ + "Data.hx", + "Main.hx", + "Rebuild.hx", + "SemVer.hx", + "SiteApi.hx", + "ConvertXml.hx", + ]) { + cp('src/tools/haxelib/$file', 'package/src/tools/haxelib/$file'); + } + cp("haxelib.json", "package/haxelib.json"); + + setCwd("package"); + + var zipFile = "package.zip"; + if (FileSystem.exists(zipFile)) { + FileSystem.deleteFile(zipFile); + } + zip(".", zipFile); + } +} \ No newline at end of file diff --git a/extra/haxelib_src/README.md b/extra/haxelib_src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2446612ee71a8eb174b437629101373ed2ca0b0b --- /dev/null +++ b/extra/haxelib_src/README.md @@ -0,0 +1,50 @@ +# Haxelib + +For more documentation, please refer to [haxe.org](http://haxe.org/haxelib) + +[![TravisCI Build Status](https://travis-ci.org/HaxeFoundation/haxelib.svg?branch=master)](https://travis-ci.org/HaxeFoundation/haxelib) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HaxeFoundation/haxelib?branch=master&svg=true)](https://ci.appveyor.com/project/HaxeFoundation/haxelib) + +## Per-project setup + +Currently haxelib has two ways to have project local setups. + +1. Using `haxelib newrepo` +2. Using `haxelib install all` + +### Using haxelib newrepo + +When using `haxelib newrepo` you can have a project-local haxelib repository. This feature is quite new and a little rough around the edges. + +Caveats: + +- if you mistakenly run a haxelib command in a subdirectory of your project, it will be executed on the global repo (to be fixed) +- there may be some issues with `haxelib run` and `haxelib selfupdate` (to be fixed) +- libraries get downloaded for each project +- it requires a recent Haxe version (after 3.1.3) to work properly with ndlls. + +### Using haxelib install all + +Haxe allows you to define specific versions of the libraries you want to use with `-lib :`. If you make sure to use this in all your hxmls, then `haxelib install all --always` (the `--always` avoiding you being prompted for confirmation) will be able to ensure the libraries your project needs are available in the necessary versions. If in fact you run this in a checkout hook, your get to track your dependencies in your git repo (some other VCSs should allow for a similar setup), allowing you to have a well defined and replicable setup for any state (commit/branch/etc.). + +Disadvantages: + +- the approach requires you to define all dependencies with specific versions and then running `haxelib install all` to grab them +- with this approach, any other project that does not have specific versions defined may be affected, as under some circumstances `haxelib install all` may set the global "current" version of the libraries (to be fixed) + +Advantages: + +- as pointed out above, this approach allows defining a *versionable* and *replicable* state. +- you don't have to download libraries for each project, which does make a difference for heavy weights like openfl and hxcpp + +#### Sidestepping haxelib git issues + +Because you cannot specify git versions with `-lib` paremeters, we suggest using git submodules instead, as again they provide an adequate way of definining a *versionable* and *replicable* state. + +### Combining both approaches + +You can of course combine both approaches, giving you the isolation provided by the first one, and the replicability provided by the second one. + +### Future solutions + +A solution that combines the strengths of both approaches is in the making. Stay tuned. diff --git a/extra/haxelib_src/appveyor.yml b/extra/haxelib_src/appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..b3c94e8f2323d24508f4a8c81461a74751379c3f --- /dev/null +++ b/extra/haxelib_src/appveyor.yml @@ -0,0 +1,11 @@ +version: "{build}" + +install: + - cinst 7zip.commandline -y + - cinst haxe -y + +build_script: + - haxe test.hxml + +test_script: + - neko bin/test.n diff --git a/extra/haxelib_src/haxelib.hxml b/extra/haxelib_src/haxelib.hxml new file mode 100644 index 0000000000000000000000000000000000000000..07f5bf280920eb4f940eed686400be72c2783b81 --- /dev/null +++ b/extra/haxelib_src/haxelib.hxml @@ -0,0 +1,3 @@ +-cp src +-neko bin/haxelib.n +-main tools.haxelib.Main diff --git a/std/tools/hxinst/hxinst.hxproj b/extra/haxelib_src/haxelib.hxproj similarity index 68% rename from std/tools/hxinst/hxinst.hxproj rename to extra/haxelib_src/haxelib.hxproj index ca0600d140fe6a4b25cbf6d44525e01747115613..4e1f3beb1365f77457b969c762fa07cd2257058d 100644 --- a/std/tools/hxinst/hxinst.hxproj +++ b/extra/haxelib_src/haxelib.hxproj @@ -4,7 +4,7 @@ - + @@ -15,15 +15,15 @@ - + @@ -31,7 +31,7 @@ - + @@ -40,11 +40,12 @@ - + nekotools boot bin/haxelib.n diff --git a/extra/haxelib_src/haxelib.json b/extra/haxelib_src/haxelib.json new file mode 100644 index 0000000000000000000000000000000000000000..db877601b2c5db62cb15bf2a046919cd385c3102 --- /dev/null +++ b/extra/haxelib_src/haxelib.json @@ -0,0 +1,11 @@ +{ + "name": "haxelib_client", + "url" : "http://haxe.org/haxelib", + "license": "GPL", + "tags": ["haxelib", "core"], + "description": "The haxelib client", + "classPath": "src", + "version": "3.2.0-rc.3", + "releasenote": "Correct behavior for locating base path", + "contributors": ["back2dos", "ncannasse", "jason", "Simn"] +} diff --git a/extra/haxelib_src/haxelib.sh b/extra/haxelib_src/haxelib.sh new file mode 100755 index 0000000000000000000000000000000000000000..b4d08f41163aabb62744ba50f0c1cc0358120194 --- /dev/null +++ b/extra/haxelib_src/haxelib.sh @@ -0,0 +1,3 @@ +#!/bin/sh +haxe haxelib.hxml +exec neko bin/haxelib "$@" diff --git a/extra/haxelib_src/haxelib_script.sh b/extra/haxelib_src/haxelib_script.sh new file mode 100755 index 0000000000000000000000000000000000000000..16c52a56e2d1d5b73e9543e799b9103b09dea373 --- /dev/null +++ b/extra/haxelib_src/haxelib_script.sh @@ -0,0 +1,4 @@ +#!/bin/sh +OLDCWD=`pwd` +cd src +exec haxe --run tools.haxelib.Main -cwd $OLDCWD $@ diff --git a/extra/haxelib_src/legacyhaxelib.hxml b/extra/haxelib_src/legacyhaxelib.hxml new file mode 100644 index 0000000000000000000000000000000000000000..e4699a65b5047f3ba49a4a2d3e46f72e29c0404f --- /dev/null +++ b/extra/haxelib_src/legacyhaxelib.hxml @@ -0,0 +1,3 @@ +-cp src +-neko bin/legacyhaxelib.n +-main tools.legacyhaxelib.Main \ No newline at end of file diff --git a/extra/haxelib_src/legacyhaxelib.sh b/extra/haxelib_src/legacyhaxelib.sh new file mode 100755 index 0000000000000000000000000000000000000000..c367c0159967b4cac70a44e06711cfcfd7abbaad --- /dev/null +++ b/extra/haxelib_src/legacyhaxelib.sh @@ -0,0 +1,3 @@ +#!/bin/sh +haxe legacyhaxelib.hxml +exec neko bin/legacyhaxelib "$@" diff --git a/extra/haxelib_src/package.sh b/extra/haxelib_src/package.sh new file mode 100755 index 0000000000000000000000000000000000000000..49e2a240de524197177a30a28b8d1451d71cb5b4 --- /dev/null +++ b/extra/haxelib_src/package.sh @@ -0,0 +1,2 @@ +#!/bin/bash +haxe --run Package \ No newline at end of file diff --git a/extra/haxelib_src/prepare.hxml b/extra/haxelib_src/prepare.hxml new file mode 100644 index 0000000000000000000000000000000000000000..3fcec8d3453f518f8cd380ac714d7db39fc0a1f2 --- /dev/null +++ b/extra/haxelib_src/prepare.hxml @@ -0,0 +1,5 @@ +-cp testing +-cp src +-main PrepareServer +-x bin/prepare +-lib hx2compat \ No newline at end of file diff --git a/extra/haxelib_src/run.bat b/extra/haxelib_src/run.bat new file mode 100644 index 0000000000000000000000000000000000000000..335fe77b074cd6215edcf009254bf89dd84f443c --- /dev/null +++ b/extra/haxelib_src/run.bat @@ -0,0 +1,3 @@ +cd bin +haxelib +pause \ No newline at end of file diff --git a/extra/haxelib_src/schema.json b/extra/haxelib_src/schema.json new file mode 100644 index 0000000000000000000000000000000000000000..855f8d9dd7ae8ecc83ab3c6327cfcb1eb82532cd --- /dev/null +++ b/extra/haxelib_src/schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "A haxelib project", + "type": "object", + "properties": { + "name": { "$ref": "#/definitions/projectName" }, + "license": { + "description": "The open source license under which the project is licensed", + "enum": ["GPL", "LGPL", "BSD", "Public", "MIT"] + }, + "tags": { + "type": "array", + "items": { "$ref": "#/definitions/haxelibTag" }, + "uniqueItems": true + }, + "description": { + "type": "string" + }, + "classPath": { + "description": "The folder in the package which contains the source files for this haxelib", + "type": "string" + }, + "contributors": { + "type": "array", + "items": { "$ref": "#/definitions/userName" }, + "minItems": 1, + "uniqueItems": true + }, + "releasenote": { + "type": "string" + }, + "version": { "$ref": "#/definitions/semver" }, + "url": { + "type": "string", + "format": "uri" + }, + "dependencies": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/dependancyVersion" } + } + }, + "additionalProperties": true, + "required": ["name", "license", "releasenote", "contributors", "version"], + "definitions": { + "userName": { + "description": "The name of a user", + "type": "string", + "minLength": 3, + "pattern": "^[A-Za-z0-9_.-]{3,}$" + }, + "projectName": { + "description": "The name of a haxelib project", + "type": "string", + "minLength": 3, + "pattern": "^[A-Za-z0-9_.-]{3,}$" + }, + "haxelibTag": { + "description": "A keyword or term associated with a haxelib project", + "type": "string", + "minLength": 2, + "pattern": "^[A-Za-z0-9_.-]{2,}$" + }, + "semver": { + "type": "string", + "pattern": "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-(alpha|beta|rc)(\\.([0-9]+))?)?$" + }, + "dependancyVersion": { + "oneOf": [ + { "$ref": "#/definitions/semver" }, + { + "type": "string", + "maxLength": 0 + } + ] + } + } + +} diff --git a/extra/haxelib_src/site.bat b/extra/haxelib_src/site.bat new file mode 100644 index 0000000000000000000000000000000000000000..04dc13323f9d53e9711dda53c6ba203b7ef4c2d4 --- /dev/null +++ b/extra/haxelib_src/site.bat @@ -0,0 +1,4 @@ +@echo off +cd server +nekotools server -rewrite +pause diff --git a/extra/haxelib_src/site.hxml b/extra/haxelib_src/site.hxml new file mode 100644 index 0000000000000000000000000000000000000000..aab1e7da6080a6562521114783d86907ffdd7921 --- /dev/null +++ b/extra/haxelib_src/site.hxml @@ -0,0 +1,21 @@ +-cp src +-neko server/index.n +-main tools.haxelib.Site +-dce no + +--next + +-cp src +-neko server/api/3.0/index.n +-main tools.haxelib.Repo +-dce no +-D haxelib_api + +--next + +-cp src +-neko server/legacy/index.n +-main tools.legacyhaxelib.Site +-lib hx2compat +-D haxelib_site +-dce no \ No newline at end of file diff --git a/std/tools/haxedoc/haxedoc.hxproj b/extra/haxelib_src/site.hxproj similarity index 78% rename from std/tools/haxedoc/haxedoc.hxproj rename to extra/haxelib_src/site.hxproj index 950e7625fcc33c63b07817d93d39539e1737c5bb..1e5c08ee221dd3c8c37347b8dc04fb1539ae0043 100644 --- a/std/tools/haxedoc/haxedoc.hxproj +++ b/extra/haxelib_src/site.hxproj @@ -4,7 +4,7 @@ - + @@ -15,15 +15,15 @@ - + @@ -31,7 +31,7 @@ - + @@ -44,7 +44,8 @@ diff --git a/extra/haxelib_src/site.sh b/extra/haxelib_src/site.sh new file mode 100755 index 0000000000000000000000000000000000000000..408020d861b240de97a43ea1a720aea978485e40 --- /dev/null +++ b/extra/haxelib_src/site.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Build the site, copy components over + +mkdir -p server/legacy +mkdir -p server/api/3.0 + +haxe site.hxml + +cp src/tools/haxelib/.htaccess server/ +cp -ar src/tools/haxelib/tmpl server/ +cp src/tools/haxelib/haxelib.css server/ +cp src/tools/haxelib/dbconfig.json.example server/ + +cp src/tools/legacyhaxelib/.htaccess server/legacy/ +cp src/tools/legacyhaxelib/website.mtt server/legacy/ +cp src/tools/legacyhaxelib/haxelib.css server/legacy/ + +# If the databases don't exist, run "setup" + +if [ ! -f server/haxelib.db ]; +then + cd server + neko index.n setup + cd .. +fi + +if [ ! -f server/legacy/haxelib.db ]; +then + cd server/legacy + neko index.n setup + cd ../.. +fi + +# Make sure the server folders are writeable. + +chmod a+w server +chmod a+w server/tmp +chmod a+w server/files +chmod a+w server/files/3.0 +chmod a+w server/legacy +chmod a+w server/haxelib.db +chmod a+w server/legacy/haxelib.db + + +cd server +# starting server on port 2000, because binding port 80 requires root privileges, +# which might be a bad idea +nekotools server -rewrite diff --git a/extra/haxelib_src/src/tools/haxelib/.htaccess b/extra/haxelib_src/src/tools/haxelib/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..e3aab222abc2ee0af566f24737786acf159ecb29 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/.htaccess @@ -0,0 +1,23 @@ +# Set index.n to come before index.php + +DirectoryIndex index.n index.php index.html + +RewriteEngine On + +# Rewrite rules to send Haxe remoting calls on "/" to "haxelib1/". If it matches, that's [L], the last rule - go their immediately. + +RewriteBase / +RewriteCond %{HTTP:X-Haxe-Remoting}: 1 +RewriteRule ^index.n$ legacy/index.n [L] + +# Enable rewrite for the new site's pages, only if the file or dir doesn't exist + +RewriteBase / +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^(.*)$ index.n/$1 [L] + +# Get our stuff gzipped + +SetOutputFilter DEFLATE +AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/ConvertXml.hx b/extra/haxelib_src/src/tools/haxelib/ConvertXml.hx new file mode 100644 index 0000000000000000000000000000000000000000..a4f97c5f1f4ce6348d72e33a97c53ae88a04709e --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/ConvertXml.hx @@ -0,0 +1,79 @@ +package tools.haxelib; +import haxe.Json; + +class ConvertXml +{ + public static function convert(inXml:String) { + // Set up the default JSON structure + var json = { + "name": "", + "url" : "", + "license": "", + "tags": [], + "description": "", + "version": "0.0.1", + "releasenote": "", + "contributors": [], + "dependencies": {} + }; + + // Parse the XML and set the JSON + var xml = Xml.parse(inXml); + var project = xml.firstChild(); + json.name = project.get("name"); + json.license = project.get("license"); + json.url = project.get("url"); + for (node in project) + { + switch (node.nodeType) + { + case Xml.Element: + switch (node.nodeName) + { + case "tag": + json.tags.push(node.get("v")); + case "user": + json.contributors.push(node.get("name")); + case "version": + json.version = node.get("name"); + json.releasenote = node.firstChild().toString(); + case "description": + json.description = node.firstChild().toString(); + case "depends": + var name = node.get("name"); + var version = node.get("version"); + if (version == null) version = ""; + Reflect.setField(json.dependencies, name, version); + default: + } + default: + } + } + + return json; + } + + public static function prettyPrint(json:Dynamic, indent="") { + var sb = new StringBuf(); + sb.add("{\n"); + + var firstRun = true; + for (f in Reflect.fields(json)) + { + if (!firstRun) sb.add(",\n"); + firstRun = false; + + var value = switch (f) { + case "dependencies": + var d = Reflect.field(json, f); + prettyPrint(d, indent + " "); + default: + Json.stringify(Reflect.field(json, f)); + } + sb.add(indent+' "$f": $value'); + } + + sb.add('\n$indent}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Data.hx b/extra/haxelib_src/src/tools/haxelib/Data.hx new file mode 100644 index 0000000000000000000000000000000000000000..f9b66db4ee0b74606b11b3cf09bc4ee315e6189c --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Data.hx @@ -0,0 +1,369 @@ +/* + * Copyright (C)2005-2012 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 tools.haxelib; + +import haxe.ds.Option; +import haxe.zip.Reader; +import haxe.zip.Entry; +import haxe.Json; +import tools.haxelib.Validator; + +using StringTools; + +typedef UserInfos = { + var name : String; + var fullname : String; + var email : String; + var projects : Array; +} + +typedef VersionInfos = { + var date : String; + var name : SemVer;//TODO: this should eventually be called `number` + var comments : String; +} + +typedef ProjectInfos = { + var name : String; + var desc : String; + var website : String; + var owner : String; + var license : String; + var curversion : String; + var versions : Array; + var tags : List; +} + +abstract DependencyVersion(String) to String from SemVer { + inline function new(s:String) + this = s; + + @:to function toValidatable():Validatable + return + if (this == '') { validate: function () return None } + else @:privateAccess new SemVer(this); + + static public function isValid(s:String) + return toValidatable(s).validate() == None; + + static public var DEFAULT(default, null) = new DependencyVersion(''); +} + +abstract Dependencies(Dynamic) from Dynamic { + @:to public function toArray():Array { + var fields = Reflect.fields(this); + fields.sort(Reflect.compare); + return [for (f in fields) { + name: f, + version: (Reflect.field(this, f) : DependencyVersion), + }]; + } + public inline function iterator() + return toArray().iterator(); +} + +@:enum abstract DependencyType(String) { + var Haxelib = null; + var Git = 'git'; + var Mercurial = 'hg'; +} + +typedef Dependency = { + name : String, + ?version : DependencyVersion, + ?type: DependencyType, + ?url: String, + ?subDir: String, + ?branch: String, +} + +typedef Infos = { + var name : ProjectName; + @:optional var url : String; + @:optional var description : String; + var license : License; + var version : SemVer; + @:optional var classPath : String; + var releasenote : String; + @:requires('Specify at least one contributor' => _.length > 0) + var contributors : Array; + @:optional var tags : Array; + @:optional var dependencies : Dependencies; + @:optional var main:String; +} + +@:enum abstract License(String) to String { + var Gpl = 'GPL'; + var Lgpl = 'LGPL'; + var Mit = 'MIT'; + var Bsd = 'BSD'; + var Public = 'Public'; + var Apache = 'Apache'; +} + +abstract ProjectName(String) to String { + static var RESERVED_NAMES = ["haxe", "all"]; + static var RESERVED_EXTENSIONS = ['.zip', '.hxml']; + inline function new(s:String) + this = s; + + @:to function toValidatable():Validatable + return { + validate: + function ():Option<{ error: String }> { + for (r in rules) + if (!r.check(this)) + return Some( { + error: r.msg.replace('%VALUE', '`' + Json.stringify(this) + '`') + }); + return None; + } + } + + static var rules = {//using an array because order might matter + var a = new Array<{ msg: String, check:String->Bool }>(); + + function add(m, r) + a.push( { msg: m, check: r } ); + + add("%VALUE is not a String", Std.is.bind(_, String)); + add("%VALUE is too short", function (s) return s.length >= 3); + add("%VALUE contains invalid characters", Data.alphanum.match); + add("%VALUE is a reserved name", function(s) return RESERVED_NAMES.indexOf(s.toLowerCase()) == -1); + add("%VALUE ends with a reserved suffix", function(s) { + s = s.toLowerCase(); + for (ext in RESERVED_EXTENSIONS) + if (s.endsWith(ext)) return false; + return true; + }); + + a; + } + + public function validate() + return toValidatable().validate(); + + static public function ofString(s:String) + return switch new ProjectName(s) { + case _.toValidatable().validate() => Some({ error: e }): throw e; + case v: v; + } + + static public var DEFAULT(default, null) = new ProjectName('unknown'); +} + +class Data { + + public static var JSON = "haxelib.json"; + public static var XML = "haxelib.xml"; + public static var DOCXML = "haxedoc.xml"; + public static var REPOSITORY = "files/3.0"; + public static var alphanum = ~/^[A-Za-z0-9_.-]+$/; + + + public static function safe( name : String ) { + if( !alphanum.match(name) ) + throw "Invalid parameter : "+name; + return name.split(".").join(","); + } + + public static function unsafe( name : String ) { + return name.split(",").join("."); + } + + public static function fileName( lib : String, ver : String ) { + return safe(lib)+"-"+safe(ver)+".zip"; + } + + static public function getLatest(info:ProjectInfos, ?preview:SemVer.Preview->Bool):Null { + if (info.versions.length == 0) return null; + if (preview == null) + preview = function (p) return p == null; + + var versions = info.versions.copy(); + versions.sort(function (a, b) return -SemVer.compare(a.name, b.name)); + + for (v in versions) + if (preview(v.name.preview)) return v.name; + + return versions[0].name; + } + + /** + Return the directory that contains *haxelib.json*. + If it is at the root, `""`. + If it is in a folder, the path including a trailing slash is returned. + */ + public static function locateBasePath( zip : List ):String { + var f = getJson(zip); + return f.fileName.substr(0, f.fileName.length - JSON.length); + } + + static function getJson(zip:List) + return switch topmost(zip, fileNamed(JSON)) { + case Some(f): f; + default: throw 'No $JSON found'; + } + + static function fileNamed(name:String) + return function (f:Entry) return f.fileName.endsWith(name); + + static function topmost(zip:List, predicate:Entry->Bool):Option { + var best:Entry = null, + bestDepth = 0xFFFF; + + for (f in zip) + if (predicate(f)) { + var depth = f.fileName.replace('\\', '/').split('/').length;//TODO: consider Path.normalize + if ((depth == bestDepth && f.fileName < best.fileName) || depth < bestDepth) { + best = f; + bestDepth = depth; + } + } + + return + if (best == null) + None; + else + Some(best); + } + + public static function readDoc( zip : List ) : Null + return switch topmost(zip, fileNamed(DOCXML)) { + case Some(f): Reader.unzip(f).toString(); + case None: null; + } + + + public static function readInfos( zip : List, check : Bool ) : Infos + return readData(Reader.unzip(getJson(zip)).toString(), check); + + public static function checkClassPath( zip : List, infos : Infos ) { + if ( infos.classPath != "" ) { + var basePath = Data.locateBasePath(zip); + var cp = basePath + infos.classPath; + + for( f in zip ) { + if( StringTools.startsWith(f.fileName,cp) ) + return; + } + throw 'Class path `${infos.classPath}` not found'; + } + } + + static function doCheck(doc:Infos) + //return Validator.validate(doc); + return //This is generated from the above macro, which seems not to run in --run mode + (function(v:tools.haxelib.Data.Infos) { + if (!Reflect.isObject(v)) throw "object expected"; + if (Reflect.hasField(v, "classPath") && v.classPath != null) (function(v:StdTypes.Null) if (!Std.is(v, String)) throw "String expected")(v.classPath); + if (!Reflect.hasField(v, "contributors")) throw ("missing field " + "contributors") else { + (function(v:Array) { + if (!Std.is(v, Array)) throw "Array expected"; + for (v in v) (function(v:String) if (!Std.is(v, String)) throw "String expected")(v); + })(v.contributors); + (function(v:Array) { + if (!(v.length > 0)) throw 'Specify at least one contributor'; + })(v.contributors); + }; + if (Reflect.hasField(v, "dependencies") && v.dependencies != null) (function(v:StdTypes.Null) { + if (!Reflect.isObject(v)) throw "object expected"; + for (f in Reflect.fields(v)) { + var v:tools.haxelib.Data.DependencyVersion = Reflect.field(v, f); + switch ((v : tools.haxelib.Validator.Validatable)).validate() { + case Some({ error : e }):{ + throw e; + }; + case None: + }; + }; + })(v.dependencies); + if (Reflect.hasField(v, "description") && v.description != null) (function(v:StdTypes.Null) if (!Std.is(v, String)) throw "String expected")(v.description); + if (!Reflect.hasField(v, "license")) throw ("missing field " + "license") else (function(v:tools.haxelib.Data.License) if (!Lambda.has([tools.haxelib.Data.License.Gpl, tools.haxelib.Data.License.Lgpl, tools.haxelib.Data.License.Mit, tools.haxelib.Data.License.Bsd, tools.haxelib.Data.License.Public, tools.haxelib.Data.License.Apache], v)) throw 'Invalid value ' + v + ' for ' + "License")(v.license); + if (Reflect.hasField(v, "main") && v.main != null) (function(v:StdTypes.Null) if (!Std.is(v, String)) throw "String expected")(v.main); + if (!Reflect.hasField(v, "name")) throw ("missing field " + "name") else (function(v:tools.haxelib.Data.ProjectName) switch ((v : tools.haxelib.Validator.Validatable)).validate() { + case Some({ error : e }):{ + throw e; + }; + case None: + })(v.name); + if (!Reflect.hasField(v, "releasenote")) throw ("missing field " + "releasenote") else (function(v:String) if (!Std.is(v, String)) throw "String expected")(v.releasenote); + if (Reflect.hasField(v, "tags") && v.tags != null) (function(v:StdTypes.Null>) { + if (!Std.is(v, Array)) throw "Array expected"; + for (v in v) (function(v:String) if (!Std.is(v, String)) throw "String expected")(v); + })(v.tags); + if (Reflect.hasField(v, "url") && v.url != null) (function(v:StdTypes.Null) if (!Std.is(v, String)) throw "String expected")(v.url); + if (!Reflect.hasField(v, "version")) throw ("missing field " + "version") else (function(v:tools.haxelib.SemVer) switch ((v : tools.haxelib.Validator.Validatable)).validate() { + case Some({ error : e }):{ + throw e; + }; + case None: + })(v.version); + })(doc); + + public static function readData( jsondata: String, check : Bool ) : Infos { + var doc:Infos = + try Json.parse(jsondata) + catch ( e : Dynamic ) + if (check) + throw 'JSON parse error: $e'; + else { + name : ProjectName.DEFAULT, + url : '', + version : SemVer.DEFAULT, + releasenote: 'No haxelib.json found', + license: Mit, + description: 'No haxelib.json found', + contributors: [], + } + + if (check) + doCheck(doc); + else { + if (!doc.version.valid) + doc.version = SemVer.DEFAULT; + } + + //TODO: we have really weird ways to go about nullability and defaults + + if (doc.dependencies == null) + doc.dependencies = {}; + + for (dep in doc.dependencies) + if (!DependencyVersion.isValid(dep.version)) + Reflect.setField(doc.dependencies, dep.name, DependencyVersion.DEFAULT);//TODO: this is pure evil + + if (doc.classPath == null) + doc.classPath = ''; + + if (doc.name.validate() != None) + doc.name = ProjectName.DEFAULT; + + if (doc.description == null) + doc.description = ''; + + if (doc.url == null) + doc.url = ''; + + return doc; + } +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Main.hx b/extra/haxelib_src/src/tools/haxelib/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..dc1881558690279dbd35394472ed1ccacc58a926 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Main.hx @@ -0,0 +1,1652 @@ +/* + * Copyright (C)2005-2012 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 tools.haxelib; + +import haxe.crypto.Md5; +import haxe.*; +import haxe.io.BytesOutput; +import haxe.io.Path; +import haxe.zip.*; +import sys.io.File; +import sys.FileSystem; +import sys.io.*; +import haxe.ds.Option; +import tools.haxelib.Vcs; + +using StringTools; +using Lambda; +using tools.haxelib.Data; + +enum Answer { + Yes; + No; +} + +private enum CommandCategory { + Basic; + Information; + Development; + Miscellaneous; +} + +class SiteProxy extends haxe.remoting.Proxy { +} + +class Progress extends haxe.io.Output { + + var o : haxe.io.Output; + var cur : Int; + var max : Int; + var start : Float; + + public function new(o) { + this.o = o; + cur = 0; + start = Timer.stamp(); + } + + function bytes(n) { + cur += n; + if( max == null ) + Sys.print(cur+" bytes\r"); + else + Sys.print(cur+"/"+max+" ("+Std.int((cur*100.0)/max)+"%)\r"); + } + + public override function writeByte(c) { + o.writeByte(c); + bytes(1); + } + + public override function writeBytes(s,p,l) { + var r = o.writeBytes(s,p,l); + bytes(r); + return r; + } + + public override function close() { + super.close(); + o.close(); + var time = Timer.stamp() - start; + var speed = (cur / time) / 1024; + time = Std.int(time * 10) / 10; + speed = Std.int(speed * 10) / 10; + Sys.print("Download complete : "+cur+" bytes in "+time+"s ("+speed+"KB/s)\n"); + } + + public override function prepare(m) { + max = m; + } + +} + +class ProgressIn extends haxe.io.Input { + + var i : haxe.io.Input; + var pos : Int; + var tot : Int; + + public function new( i, tot ) { + this.i = i; + this.pos = 0; + this.tot = tot; + } + + public override function readByte() { + var c = i.readByte(); + doRead(1); + return c; + } + + public override function readBytes(buf,pos,len) { + var k = i.readBytes(buf,pos,len); + doRead(k); + return k; + } + + function doRead( nbytes : Int ) { + pos += nbytes; + Sys.print( Std.int((pos * 100.0) / tot) + "%\r" ); + } + +} + +enum CliError +{ + CwdUnavailable(pwd:String); + CantSetSwd_DirNotExist(dir:String); +} + +class Cli +{ + public var defaultAnswer(get, set):Answer; + private static var defaultAnswer_global:Answer; + + public var cwd(get_cwd, set_cwd):String; + private static var cwd_cache:String = null; + + + public function new() + defaultAnswer = null; + + + function get_cwd():String + { + var result:String = null; + + try + { + cwd_cache = Sys.getCwd(); + } + catch(error:String) + tryFixGetCwdError(error); + + return cwd_cache; + } + + function set_cwd(value:String):String + { + //TODO: For call `FileSystem.isDirectory(value)` we can get an exeption "std@sys_file_type": + if(value != null && cwd_cache != value && FileSystem.exists(value) && FileSystem.isDirectory(value)) + Sys.setCwd(cwd_cache = value); + else + throw CliError.CantSetSwd_DirNotExist(value); + return cwd_cache; + } + + + function tryFixGetCwdError(error:String) + { + switch(error) + { + case "std@get_cwd" | "std@file_path" | "std@file_full_path": + { + var pwd = Sys.getEnv("PWD"); + // This is a magic for issue #196: + // if we have $PWD then we can re-set it again. + // Works for case: `$ mkdir temp; cd temp; rm -r ../temp; mkdir ../temp; haxelib upgrade;` + if(pwd != null) + { + if(FileSystem.exists(pwd) && FileSystem.isDirectory(pwd)) + // Trying fix it: setting cwd to pwd + Sys.setCwd(cwd_cache = pwd); + else + // Can't fix it. + throw CliError.CwdUnavailable(pwd); + } + else throw CliError.CwdUnavailable(pwd); + } + default: throw error; + } + } + + + function get_defaultAnswer():Answer + { + return defaultAnswer_global; + } + + function set_defaultAnswer(value:Answer):Answer + { + defaultAnswer_global = value; + return defaultAnswer_global; + } + + + public function ask(question):Answer + { + if(defaultAnswer != null) + return defaultAnswer; + + while(true) + { + Sys.print(question + " [y/n/a] ? "); + try{ + switch(Sys.stdin().readLine()) + { + case "n": return No; + case "y": return Yes; + case "a": return defaultAnswer = Yes; + } + } + catch(e:haxe.io.Eof) + { + Sys.println("n"); + return No; + } + } + return null; + } + + public function command(cmd:String, args:Array) + { + var p = new sys.io.Process(cmd, args); + var code = p.exitCode(); + return {code:code, out:(code == 0 ? p.stdout.readAll().toString() : p.stderr.readAll().toString())}; + } + + public function print(str):Void + { + Sys.print(str + "\n"); + } +} + +class Main { + + static var VERSION = SemVer.ofString('3.2.0-rc.3'); + static var APIVERSION = SemVer.ofString('3.0.0'); + static var REPNAME = "lib"; + static var REPODIR = ".haxelib"; + static var SERVER = { + host : "lib.haxe.org", + port : 80, + dir : "", + url : "index.n", + apiVersion : APIVERSION.major+"."+APIVERSION.minor, + }; + + var cli:Cli; + var argcur : Int; + var args : Array; + var commands : List<{ name : String, doc : String, f : Void -> Void, net : Bool, cat : CommandCategory }>; + var siteUrl : String; + var site : SiteProxy; + + + function new() + { + cli = new Cli(); + args = Sys.args(); + + commands = new List(); + addCommand("install", install, "install a given library, or all libraries from a hxml file", Basic); + addCommand("upgrade", upgrade, "upgrade all installed libraries", Basic); + addCommand("update", update, "update a single library", Basic); + addCommand("remove", remove, "remove a given library/version", Basic, false); + addCommand("list", list, "list all installed libraries", Basic, false); + addCommand("set", set, "set the current version for a library", Basic, false); + + addCommand("search", search, "list libraries matching a word", Information); + addCommand("info", info, "list information on a given library", Information); + addCommand("user", user, "list information on a given user", Information); + addCommand("config", config, "print the repository path", Information, false); + addCommand("path", path, "give paths to libraries", Information, false); + addCommand("version", version, "print the currently using haxelib version", Information, false); + addCommand("help", usage, "display this list of options", Information, false); + + addCommand("submit", submit, "submit or update a library package", Development); + addCommand("register", register, "register a new user", Development); + addCommand("local", local, "install the specified package locally", Development, false); + addCommand("dev", dev, "set the development directory for a given library", Development, false); + //TODO: generate command about VCS by Vcs.getAll() + addCommand("git", function()doVcs(VcsID.Git), "use Git repository as library", Development); + addCommand("hg", function()doVcs(VcsID.Hg), "use Mercurial (hg) repository as library", Development); + + addCommand("setup", setup, "set the haxelib repository path", Miscellaneous, false); + addCommand("newrepo", newRepo, "[EXPERIMENTAL] create a new local repository", Miscellaneous, false); + addCommand("deleterepo", deleteRepo, "delete the local repository", Miscellaneous, false); + addCommand("selfupdate", updateSelf, "update haxelib itself", Miscellaneous); + addCommand("convertxml", convertXml, "convert haxelib.xml file to haxelib.json", Miscellaneous); + addCommand("run", run, "run the specified library with parameters", Miscellaneous, false); + addCommand("proxy", proxy, "setup the Http proxy", Miscellaneous); + + initSite(); + } + + + + function initSite() { + siteUrl = "http://" + SERVER.host + ":" + SERVER.port + "/" + SERVER.dir; + var remotingUrl = siteUrl + "api/" + SERVER.apiVersion + "/" + SERVER.url; + site = new SiteProxy(haxe.remoting.HttpConnection.urlConnect(remotingUrl).api); + } + + function param( name, ?passwd ) { + if( args.length > argcur ) + return args[argcur++]; + Sys.print(name+" : "); + if( passwd ) { + var s = new StringBuf(); + do switch Sys.getChar(false) { + case 10, 13: break; + case c: s.addChar(c); + } + while (true); + print(""); + return s.toString(); + } + return Sys.stdin().readLine(); + } + + inline function ask(question) + return cli.ask(question); + + function paramOpt() { + if( args.length > argcur ) + return args[argcur++]; + return null; + } + + function addCommand( name, f, doc, cat, ?net = true ) { + commands.add({ name : name, doc : doc, f : f, net : net, cat : cat }); + } + + function version() { + print(VERSION); + } + + function usage() { + var cats = []; + var maxLength = 0; + for( c in commands ) { + if (c.name.length > maxLength) maxLength = c.name.length; + var i = c.cat.getIndex(); + if (cats[i] == null) cats[i] = [c]; + else cats[i].push(c); + } + + print("Haxe Library Manager " + VERSION + " - (c)2006-2015 Haxe Foundation"); + print(" Usage: haxelib [command] [options]"); + + for (cat in cats) { + print(" " + cat[0].cat.getName()); + for (c in cat) { + print(" " + StringTools.rpad(c.name, " ", maxLength) + ": " +c.doc); + } + } + + print(" Available switches"); + for (f in Reflect.fields(ABOUT_SETTINGS)) + print(' --' + f.rpad(' ', maxLength-2) + ": " + Reflect.field(ABOUT_SETTINGS, f)); + } + static var ABOUT_SETTINGS = { + global : "force global repo if a local one exists", + debug : "run in debug mode", + flat : "do not use --recursive cloning for git", + always : "answer all questions with yes", + never : "answer all questions with no" + } + + var settings: { + debug : Bool, + flat : Bool, + always : Bool, + never : Bool, + global : Bool, + }; + function process() { + argcur = 0; + var rest = []; + settings = { + debug: false, + always: false, + never: false, + flat: false, + global: false, + }; + + function parseSwitch(s:String) { + return + if (s.startsWith('--')) + Some(s.substr(2)); + else if (s.startsWith('-')) + Some(s.substr(1)); + else + None; + } + + while ( argcur < args.length) { + var a = args[argcur++]; + switch( a ) { + case '-cwd': cli.cwd = args[argcur++]; + case "-notimeout": + haxe.remoting.HttpConnection.TIMEOUT = 0; + case "-R": + var path = args[argcur++]; + var r = ~/^(http:\/\/)?([^:\/]+)(:[0-9]+)?\/?(.*)$/; + if( !r.match(path) ) + throw "Invalid repository format '"+path+"'"; + SERVER.host = r.matched(2); + if( r.matched(3) != null ) + SERVER.port = Std.parseInt(r.matched(3).substr(1)); + SERVER.dir = r.matched(4); + if (SERVER.dir.length > 0 && !SERVER.dir.endsWith("/")) SERVER.dir += "/"; + initSite(); + case parseSwitch(_) => Some(s) if (Reflect.hasField(settings, s)): + //if (!Reflect.hasField(settings, s)) { + //print('unknown switch $a'); + //Sys.exit(1); + //} + Reflect.setField(settings, s, true); + case 'run': + rest = rest.concat(args.slice(argcur - 1)); + break; + default: + rest.push(a); + } + } + + cli.defaultAnswer = + switch [settings.always, settings.never] { + case [true, true]: + print('--always and --never are mutually exclusive'); + Sys.exit(1); + null; + case [true, _]: Yes; + case [_, true]: No; + default: null; + } + + argcur = 0; + args = rest; + + var cmd = args[argcur++]; + if( cmd == null ) { + usage(); + Sys.exit(1); + } + for( c in commands ) + if( c.name == cmd ) { + try { + if( c.net ) loadProxy(); + c.f(); + } catch( e : Dynamic ) { + if( e == "std@host_resolve" ) { + print("Host "+SERVER.host+" was not found"); + print("Please ensure that your internet connection is on"); + print("If you don't have an internet connection or if you are behing a proxy"); + print("please download manually the file from http://lib.haxe.org/files/3.0/"); + print("and run 'haxelib local ' to install the Library."); + print("You can also setup the proxy with 'haxelib proxy'."); + Sys.exit(1); + } + if( e == "Blocked" ) { + print("Http connection timeout. Try running haxelib -notimeout to disable timeout"); + Sys.exit(1); + } + if( settings.debug ) + neko.Lib.rethrow(e); + print(Std.string(e)); + Sys.exit(1); + } + return; + } + print("Unknown command "+cmd); + usage(); + Sys.exit(1); + } + + // ---- COMMANDS -------------------- + + function search() { + var word = param("Search word"); + var l = site.search(word); + for( s in l ) + print(s.name); + print(l.length+" libraries found"); + } + + function info() { + var prj = param("Library name"); + var inf = site.infos(prj); + print("Name: "+inf.name); + print("Tags: "+inf.tags.join(", ")); + print("Desc: "+inf.desc); + print("Website: "+inf.website); + print("License: "+inf.license); + print("Owner: "+inf.owner); + print("Version: "+inf.getLatest()); + print("Releases: "); + if( inf.versions.length == 0 ) + print(" (no version released yet)"); + for( v in inf.versions ) + print(" "+v.date+" "+v.name+" : "+v.comments); + } + + function user() { + var uname = param("User name"); + var inf = site.user(uname); + print("Id: "+inf.name); + print("Name: "+inf.fullname); + print("Mail: "+inf.email); + print("Libraries: "); + if( inf.projects.length == 0 ) + print(" (no libraries)"); + for( p in inf.projects ) + print(" "+p); + } + + function register() { + doRegister(param("User")); + print("Registration successful"); + } + + function doRegister(name) { + var email = param("Email"); + var fullname = param("Fullname"); + var pass = param("Password",true); + var pass2 = param("Confirm",true); + if( pass != pass2 ) + throw "Password does not match"; + pass = Md5.encode(pass); + site.register(name,pass,email,fullname); + return pass; + } + + function submit() { + var file = param("Package"), + data = null; + var zip = + if (FileSystem.isDirectory(file)) { + var ret = new List(), + out = new BytesOutput(); + function seek(dir:String) { + for (name in FileSystem.readDirectory(dir)) if (!name.startsWith('.')) { + var full = '$dir/$name'; + if (FileSystem.isDirectory(full)) seek(full); + else { + var blob = File.getBytes(full); + ret.push({ + fileName: full.substr(file.length+1), + fileSize : blob.length, + fileTime : FileSystem.stat(full).mtime, + compressed : false, + dataSize : blob.length, + data : blob, + crc32: null,//TODO: consider calculating this one + }); + } + } + } + seek(file); + new Writer(out).write(ret); + data = out.getBytes(); + ret; + } + else { + data = File.getBytes(file); + Reader.readZip(File.read(file, true)); + } + + var infos = Data.readInfos(zip,true); + Data.checkClassPath(zip, infos); + + var user:String = infos.contributors[0]; + + if (infos.contributors.length > 1) + do { + print("Which of these users are you: " + infos.contributors); + user = param("User"); + } while ( !Lambda.has(infos.contributors, user) ); + + var password; + if( site.isNewUser(user) ) { + print("This is your first submission as '"+user+"'"); + print("Please enter the following informations for registration"); + password = doRegister(user); + } else { + password = Md5.encode(param("Password",true)); + var attempts = 5; + while ( !site.checkPassword(user, password)) { + print ("Invalid password for " + user); + if (--attempts == 0) + throw 'Failed to input correct password'; + password = Md5.encode(param('Password ($attempts more attempt${attempts == 1 ? "" : "s"})', true)); + } + } + site.checkDeveloper(infos.name,user); + + // check dependencies validity + for( d in infos.dependencies ) { + var infos = site.infos(d.name); + if( d.version == "" ) + continue; + var found = false; + for( v in infos.versions ) + if( v.name == d.version ) { + found = true; + break; + } + if( !found ) + throw "Library " + d.name + " does not have version " + d.version; + } + + // check if this version already exists + + var sinfos = try site.infos(infos.name) catch( _ : Dynamic ) null; + if( sinfos != null ) + for( v in sinfos.versions ) + if( v.name == infos.version && ask("You're about to overwrite existing version '"+v.name+"', please confirm") == No ) + throw "Aborted"; + + // query a submit id that will identify the file + var id = site.getSubmitId(); + + // directly send the file data over Http + var h = new Http("http://"+SERVER.host+":"+SERVER.port+"/"+SERVER.url); + h.onError = function(e) { throw e; }; + h.onData = print; + h.fileTransfer("file",id,new ProgressIn(new haxe.io.BytesInput(data),data.length),data.length); + print("Sending data.... "); + h.request(true); + + // processing might take some time, make sure we wait + print("Processing file.... "); + haxe.remoting.HttpConnection.TIMEOUT = 1000; + // ask the server to register the sent file + var msg = site.processSubmit(id,user,password); + print(msg); + } + + function install() { + var prj = param("Library name or hxml file:"); + + // No library given, install libraries listed in *.hxml in given directory + if( prj == "all") + { + installFromAllHxml(); + return; + } + + if( sys.FileSystem.exists(prj) && !sys.FileSystem.isDirectory(prj) ) { + // *.hxml provided, install all libraries/versions in this hxml file + if( prj.endsWith(".hxml") ) + { + installFromHxml(prj); + return; + } + // *.zip provided, install zip as haxe library + if( prj.endsWith(".zip") ) + { + doInstallFile(prj,true,true); + return; + } + } + + // Name provided that wasn't a local hxml or zip, so try to install it from server + var inf = site.infos(prj); + var reqversion = paramOpt(); + var version = getVersion(inf, reqversion); + doInstall(inf.name,version,version == inf.getLatest()); + } + + function getVersion( inf:ProjectInfos, ?reqversion:String ) + { + if( inf.versions.length == 0 ) + throw "The library "+inf.name+" has not yet released a version"; + var version = if( reqversion != null ) reqversion else inf.getLatest(); + var found = false; + for( v in inf.versions ) + if( v.name == version ) { + found = true; + break; + } + if( !found ) + throw "No such version "+version+" for library "+inf.name; + + return version; + } + + function installFromHxml( path ) + { + var hxml = sys.io.File.getContent(path); + var lines = hxml.split("\n"); + var targets = [ + '-java ' => 'hxjava', + '-cpp ' => 'hxcpp', + '-cs ' => 'hxcs', + ]; + var libsToInstall = new Map(); + for (l in lines) { + l = l.trim(); + for (target in targets.keys()) + if (l.startsWith(target)) { + var lib = targets[target]; + if (!libsToInstall.exists(lib)) + libsToInstall[lib] = { name: lib, version: null } + } + + if (l.startsWith("-lib")) + { + var key = l.substr(5); + var parts = key.split(":"); + var libName = parts[0].trim(); + var libVersion = if (parts.length > 1) parts[1].trim() else null; + + switch libsToInstall[key] { + case null, { version: null } : + libsToInstall.set(key, { name:libName, version:libVersion } ); + default: + } + } + } + installMany(libsToInstall); + } + + function installFromAllHxml() + { + var hxmlFiles = sys.FileSystem.readDirectory(cli.cwd).filter(function (f) return f.endsWith(".hxml")); + if (hxmlFiles.length > 0) + { + for (file in hxmlFiles) + { + if (file.endsWith(".hxml")) + { + print('Installing all libraries from $file:'); + installFromHxml(cli.cwd+file); + } + } + } + else + { + print ("No hxml files found in the current directory."); + } + } + + function installMany( libs:Iterable<{name:String,version:String}>, ?setCurrent=true ) + { + if (Lambda.count(libs) == 0) return; + + // Check the version numbers are all good + // TODO: can we collapse this into a single API call? It's getting too slow otherwise. + print("Loading info about the required libraries"); + for (l in libs) + { + var inf = site.infos(l.name); + l.version = getVersion(inf, l.version); + } + + // Print a list with all the info + print("Haxelib is going to install these libraries:"); + for (l in libs) + { + var vString = (l.version == null) ? "" : " - " + l.version; + print(" " + l.name + vString); + } + + // Install if they confirm + if (ask("Continue?") != No) + { + for (l in libs) + { + doInstall(l.name, l.version, setCurrent); + } + } + } + + function doInstall( project, version, setcurrent ) { + var rep = getRepository(); + + // check if exists already + if( FileSystem.exists(rep+Data.safe(project)+"/"+Data.safe(version)) ) { + print("You already have "+project+" version "+version+" installed"); + setCurrent(project,version,true); + return; + } + + // download to temporary file + var filename = Data.fileName(project,version); + var filepath = rep+filename; + var out = try File.write(filepath,true) + catch (e:Dynamic) throw 'Failed to write to $filepath: $e'; + + var progress = new Progress(out); + var h = new Http(siteUrl+Data.REPOSITORY+"/"+filename); + h.onError = function(e) { + progress.close(); + FileSystem.deleteFile(filepath); + throw e; + }; + print("Downloading "+filename+"..."); + h.customRequest(false,progress); + + doInstallFile(filepath, setcurrent); + try { + site.postInstall(project, version); + } catch (e:Dynamic) {} + } + + function doInstallFile(filepath,setcurrent,?nodelete) { + // read zip content + var f = File.read(filepath,true); + var zip = Reader.readZip(f); + f.close(); + var infos = Data.readInfos(zip,false); + // create directories + var pdir = getRepository() + Data.safe(infos.name); + safeDir(pdir); + pdir += "/"; + var target = pdir + Data.safe(infos.version); + safeDir(target); + target += "/"; + + // locate haxelib.json base path + var basepath = Data.locateBasePath(zip); + + // unzip content + for( zipfile in zip ) { + var n = zipfile.fileName; + if( n.startsWith(basepath) ) { + // remove basepath + n = n.substr(basepath.length,n.length-basepath.length); + if( n.charAt(0) == "/" || n.charAt(0) == "\\" || n.split("..").length > 1 ) + throw "Invalid filename : "+n; + var dirs = ~/[\/\\]/g.split(n); + var path = ""; + var file = dirs.pop(); + for( d in dirs ) { + path += d; + safeDir(target+path); + path += "/"; + } + if( file == "" ) { + if( path != "" ) print(" Created "+path); + continue; // was just a directory + } + path += file; + print(" Install "+path); + var data = Reader.unzip(zipfile); + File.saveBytes(target+path,data); + } + } + + // set current version + if( setcurrent || !FileSystem.exists(pdir+".current") ) { + File.saveContent(pdir + ".current", infos.version); + print(" Current version is now "+infos.version); + } + + // end + if( !nodelete ) + FileSystem.deleteFile(filepath); + print("Done"); + + // process dependencies + doInstallDependencies(infos.dependencies); + + return infos; + } + + function doInstallDependencies( dependencies:Array ) + { + for( d in dependencies ) { + print("Installing dependency "+d.name+" "+d.version); + if( d.version == "" ) + d.version = site.infos(d.name).getLatest(); + + switch d.type { + case Haxelib: + doInstall(d.name, d.version, false); + case Git: + doVcs(VcsID.Git, d.name, d.url, d.branch, d.subDir, d.version); + //TODO: add mercurial-dependency type to schema.json (https://github.com/HaxeFoundation/haxelib/blob/master/schema.json#L38) + case Mercurial: + doVcs(VcsID.Hg, d.name, d.url, d.branch, d.subDir, d.version); + } + } + } + + function safeDir( dir ) { + if( FileSystem.exists(dir) ) { + if( !FileSystem.isDirectory(dir) ) + throw ("A file is preventing "+dir+" to be created"); + } + try { + FileSystem.createDirectory(dir); + } catch( e : Dynamic ) { + throw "You don't have enough user rights to create the directory "+dir; + } + return true; + } + + function safeDelete( file ) { + try { + FileSystem.deleteFile(file); + return true; + } catch (e:Dynamic) { + if( Sys.systemName() == "Windows") { + try { + Sys.command("attrib", ["-R", file]); + FileSystem.deleteFile(file); + return true; + } catch (e:Dynamic) { + } + } + return false; + } + } + + function getRepository( ?setup : Bool ) { + + if( !setup && !settings.global && FileSystem.exists(REPODIR) && FileSystem.isDirectory(REPODIR) ) { + var absolutePath = Path.join([cli.cwd, REPODIR]);//TODO: we actually might want to get the real path here + return Path.addTrailingSlash(absolutePath); + } + + var win = Sys.systemName() == "Windows"; + var haxepath = Sys.getEnv("HAXEPATH"); + if( haxepath != null ) + haxepath = Path.addTrailingSlash( haxepath ); + var envPath = Sys.getEnv("HAXELIB_PATH"); + var config_file; + if( win ) + config_file = Sys.getEnv("HOMEDRIVE") + Sys.getEnv("HOMEPATH"); + else + config_file = Sys.getEnv("HOME"); + config_file += "/.haxelib"; + var rep = if (envPath != null) + envPath + else try + File.getContent(config_file) + catch( e : Dynamic ) try + File.getContent("/etc/.haxelib") + catch( e : Dynamic ) { + if( setup ) { + (if (win) + haxepath; + else if (FileSystem.exists("/usr/share/haxe")) + "/usr/share/haxe"; + else + "/usr/lib/haxe")+REPNAME; + } else if( win ) { + // Windows have a default directory (no need for setup) + if( haxepath == null ) + throw "HAXEPATH environment variable not defined, please run haxesetup.exe first"; + var rep = haxepath+REPNAME; + try { + safeDir(rep); + } catch( e : String ) { + throw "Error accessing Haxelib repository: $e"; + } + return Path.addTrailingSlash( rep ); + } else + throw "This is the first time you are runing haxelib. Please run `haxelib setup` first"; + } + rep = rep.trim(); + if( setup ) { + if( args.length <= argcur ) { + print("Please enter haxelib repository path with write access"); + print("Hit enter for default (" + rep + ")"); + } + var line = param("Path"); + if( line != "" ) + rep = line; + if( !FileSystem.exists(rep) ) { + try { + FileSystem.createDirectory(rep); + } catch( e : Dynamic ) { + print("Failed to create directory '"+rep+"' ("+Std.string(e)+"), maybe you need appropriate user rights"); + print("Check also that the parent directory exists"); + Sys.exit(1); + } + } + rep = try FileSystem.fullPath(rep) catch( e : Dynamic ) rep; + File.saveContent(config_file, rep); + } else if( !FileSystem.exists(rep) ) { + throw "haxelib Repository "+rep+" does not exist. Please run `haxelib setup` again"; + } else if ( !FileSystem.isDirectory(rep) ) { + throw "haxelib Repository "+rep+" exists, but was a file, not a directory. Please remove it and run `haxelib setup` again."; + } + return rep+"/"; + } + + function setup() { + var path = getRepository(true); + print("haxelib repository is now "+path); + } + + function config() { + print(getRepository()); + } + + function getCurrent( dir ) { + return (FileSystem.exists(dir+"/.dev")) ? "dev" : File.getContent(dir + "/.current").trim(); + } + + function getDev( dir ) { + return File.getContent(dir + "/.dev").trim(); + } + + function list() { + var rep = getRepository(); + var folders = FileSystem.readDirectory(rep); + var filter = paramOpt(); + if ( filter != null ) + folders = folders.filter( function (f) return f.toLowerCase().indexOf(filter.toLowerCase()) > -1 ); + var all = []; + for( p in folders ) { + if( p.charAt(0) == "." ) + continue; + var versions = new Array(); + var current = try getCurrent(rep + p) catch(e:Dynamic) continue; + var dev = try File.getContent(rep+p+"/.dev").trim() catch( e : Dynamic ) null; + for( v in FileSystem.readDirectory(rep+p) ) { + if( v.charAt(0) == "." ) + continue; + v = Data.unsafe(v); + if( dev == null && v == current ) + v = "["+v+"]"; + versions.push(v); + } + if( dev != null ) + versions.push("[dev:"+dev+"]"); + all.push(Data.unsafe(p) + ": "+versions.join(" ")); + } + all.sort(function(s1, s2) return Reflect.compare(s1.toLowerCase(), s2.toLowerCase())); + for (p in all) { + print(p); + } + } + + function upgrade() { + var state = { rep : getRepository(), prompt : true, updated : false }; + for( p in FileSystem.readDirectory(state.rep) ) { + if( p.charAt(0) == "." || !FileSystem.isDirectory(state.rep+"/"+p) ) + continue; + var p = Data.unsafe(p); + print("Checking " + p); + try doUpdate(p, state) + catch (e:Dynamic) + if (e != VcsError.VcsUnavailable) neko.Lib.rethrow(e); + } + if( state.updated ) + print("Done"); + else + print("All libraries are up-to-date"); + } + + function doUpdate( p : String, state ) { + var rep = state.rep; + + //TODO: get content from `.current` and use vcs only if there "dev". + + var vcs:Vcs = Vcs.getVcsForDevLib(rep + "/" + p); + if(vcs != null) + { + if(!vcs.available) + throw VcsError.VcsUnavailable; + + var oldCwd = cli.cwd; + cli.cwd = (rep + "/" + p + "/" + vcs.directory); + var success = vcs.update(p, cast settings); + + state.updated = success; + cli.cwd = oldCwd; + } + else + { + var inf = try site.infos(p) catch( e : Dynamic ) { Sys.println(e); return; }; + if( !FileSystem.exists(rep+Data.safe(p)+"/"+Data.safe(inf.getLatest())) ) { + if( state.prompt ) + switch ask("Update "+p+" to "+inf.getLatest()) { + case Yes: + case No: + return; + } + doInstall(p,inf.getLatest(),true); + state.updated = true; + } else + setCurrent(p, inf.getLatest(), true); + } + } + function updateByName(prj:String) { + var state = { rep : getRepository(), prompt : false, updated : false }; + doUpdate(prj,state); + return state.updated; + } + function update() { + var prj = param('Library'); + if (!updateByName(prj)) + print(prj + " is up to date"); + } + + //recursively follow symlink + static function realPath(path:String):String { + return switch (new Process('readlink', [path.endsWith("\n") ? path.substr(0, path.length-1) : path]).stdout.readAll().toString()) { + case "": //it is not a symlink + path; + case targetPath: + if (targetPath.startsWith("/")) { + realPath(targetPath); + } else { + realPath(new Path(path).dir + "/" + targetPath); + } + } + } + + function rebuildSelf() { + var win = Sys.systemName() == "Windows"; + var haxepath = + if (win) Sys.getEnv("HAXEPATH"); + else new Path(realPath(new Process('which', ['haxelib']).stdout.readAll().toString())).dir + '/'; + + cli.cwd = haxepath; + function tryBuild() { + var p = new Process('haxe', ['-neko', 'test.n', '-lib', 'haxelib_client', '-main', 'tools.haxelib.Main', '--no-output']); + return + if (p.exitCode() == 0) None; + else Some(p.stderr.readAll().toString()); + } + + + switch tryBuild() { + case None: + + if (haxepath == null) + throw (win ? 'HAXEPATH environment variable not defined' : 'unable to locate haxelib through `which haxelib`'); + else + haxepath = Path.addTrailingSlash(haxepath); + + if (win) { + Sys.command('start', ['haxe', '-lib', 'haxelib_client', '--run', 'tools.haxelib.Rebuild']); + print('rebuild launched'); + } + else { + var p = new Process('haxelib', ['path', 'haxelib_client']); + if (p.exitCode() == 0) { + var args = []; + var classPath = ""; + for (arg in p.stdout.readAll().toString().split('\n')) { + arg = arg.trim(); + if (arg.charAt(0) == '-') + args.push(arg); + else if (arg.length > 0) + classPath = arg; + }; + + var file = haxepath+'haxelib'; + try File.saveContent( + file, + '#!/bin/sh' + +'\n'+'OLDCWD=`pwd`' + +'\n'+'cd $classPath' + +'\n'+'exec haxe '+args.join(' ')+" --run tools.haxelib.Main -cwd $OLDCWD $@" + ) + catch (e:Dynamic) + throw 'Error writing file $file. Please ensure you have write permissions. \n ' + Std.string(e); + } + else throw p.stdout.readAll(); + } + case Some(error): + throw 'Error compiling haxelib client: $error'; + } + + } + + function updateSelf() { + settings.global = true; + if (updateByName('haxelib_client')) + print("Haxelib successfully updated."); + else + print("Haxelib was already up to date..."); + + rebuildSelf(); + } + + function deleteRec(dir) + { + if(!FileSystem.exists(dir)) return; + + for(p in FileSystem.readDirectory(dir)) + { + var path = Path.join([dir, p]); + + if(isBrokenSymlink(path)) + safeDelete(path); + else + if(FileSystem.isDirectory(path)) + { + // if isSymLink: + if(Sys.systemName() != "Windows" && path != FileSystem.fullPath(path)) + safeDelete(path); + else + deleteRec(path); + } + else + safeDelete(path); + } + FileSystem.deleteDirectory(dir); + } + + function isBrokenSymlink(path:String):Bool + { + var errors:Int = 0; + function isNeeded(error:String):Bool + { + return switch(error) + { + case "std@sys_file_type" | + "std@file_full_path": true; + default: false; + } + } + + try{ FileSystem.isDirectory(path); } + catch(error:String) + if(isNeeded(error)) + errors++; + + try{ FileSystem.fullPath(path); } + catch(error:String) + if(isNeeded(error)) + errors++; + + return errors == 2; + } + + function remove() { + var prj = param("Library"); + var version = paramOpt(); + var rep = getRepository(); + var pdir = rep + Data.safe(prj); + if( version == null ) { + if( !FileSystem.exists(pdir) ) + throw "Library "+prj+" is not installed"; + deleteRec(pdir); + print("Library "+prj+" removed"); + return; + } + + var vdir = pdir + "/" + Data.safe(version); + if( !FileSystem.exists(vdir) ) + throw "Library "+prj+" does not have version "+version+" installed"; + + var cur = getCurrent(pdir); + if( cur == version ) + throw "Can't remove current version of library "+prj; + deleteRec(vdir); + print("Library "+prj+" version "+version+" removed"); + } + + function set() { + var prj = param("Library"); + var version = param("Version"); + setCurrent(prj,version,false); + } + + function setCurrent( prj : String, version : String, doAsk : Bool ) { + var pdir = getRepository() + Data.safe(prj); + var vdir = pdir + "/" + Data.safe(version); + if( !FileSystem.exists(vdir) ){ + print("Library "+prj+" version "+version+" is not installed"); + if(ask("Would you like to install it?") != No) + doInstall(prj, version, true); + return; + } + if( getCurrent(pdir) == version ) + return; + if( doAsk && ask("Set "+prj+" to version "+version) == No ) + return; + File.saveContent(pdir+"/.current",version); + print("Library "+prj+" current version is now "+version); + } + + function checkRec( prj : String, version : String, l : List<{ project : String, version : String, info : Infos }> ) { + var pdir = getRepository() + Data.safe(prj); + if( !FileSystem.exists(pdir) ) + throw "Library "+prj+" is not installed : run 'haxelib install "+prj+"'"; + var version = if( version != null ) version else getCurrent(pdir); + var vdir = pdir + "/" + Data.safe(version); + if( vdir.endsWith("dev") ) + vdir = getDev(pdir); + if( !FileSystem.exists(vdir) ) + throw "Library "+prj+" version "+version+" is not installed"; + for( p in l ) + if( p.project == prj ) { + if( p.version == version ) + return; + throw "Library "+prj+" has two version included "+version+" and "+p.version; + } + var json = try File.getContent(vdir+"/"+Data.JSON) catch( e : Dynamic ) null; + var inf = Data.readData(json,false); + l.add({ project : prj, version : version, info: inf }); + for( d in inf.dependencies ) + if( !Lambda.exists(l, function(e) return e.project == d.name) ) + checkRec(d.name,if( d.version == "" ) null else d.version,l); + } + + function path() { + var list = new List(); + while( argcur < args.length ) { + var a = args[argcur++].split(":"); + checkRec(a[0],a[1],list); + } + var rep = getRepository(); + for( d in list ) { + var pdir = Data.safe(d.project)+"/"+Data.safe(d.version)+"/"; + var dir = rep + pdir; + try { + dir = getDev(rep+Data.safe(d.project)); + dir = Path.addTrailingSlash(dir); + pdir = dir; + } catch( e : Dynamic ) {} + var ndir = dir + "ndll"; + if( FileSystem.exists(ndir) ) { + var sysdir = ndir+"/"+Sys.systemName(); + var is64 = neko.Lib.load("std", "sys_is64", 0)(); + if( is64 ) sysdir += "64"; + // if( !FileSystem.exists(sysdir) ) + // throw "Library "+d.project+" version "+d.version+" does not have a neko dll for your system"; + Sys.println("-L "+pdir+"ndll/"); + } + try { + var f = File.getContent(dir + "extraParams.hxml"); + Sys.println(f.trim()); + } catch( e : Dynamic ) {} + if (d.info.classPath != "") { + var cp = d.info.classPath; + dir = Path.addTrailingSlash( dir + cp ); + } + Sys.println(dir); + Sys.println("-D " + d.project + "="+d.info.version); + } + } + + function dev() { + var rep = getRepository(); + var project = param("Library"); + var dir = paramOpt(); + var proj = rep + Data.safe(project); + if( !FileSystem.exists(proj) ) { + FileSystem.createDirectory(proj); + } + var devfile = proj+"/.dev"; + if( dir == null ) { + if( FileSystem.exists(devfile) ) + FileSystem.deleteFile(devfile); + print("Development directory disabled"); + } + else { + while ( dir.endsWith("/") || dir.endsWith("\\") ) { + dir = dir.substr(0,-1); + } + dir = FileSystem.fullPath(dir); + if (!FileSystem.exists(dir)) + print('Directory $dir does not exist'); + else + try { + File.saveContent(devfile, dir); + print("Development directory set to "+dir); + } + catch (e:Dynamic) { + print('Could not write to $devfile'); + } + + } + } + + + function removeExistingDevLib(proj:String):Void + { + //TODO: ask if existing repo have changes. + + // find existing repo: + var vcs:Vcs = Vcs.getVcsForDevLib(proj); + // remove existing repos: + while(vcs != null) + { + deleteRec(proj + "/" + vcs.directory); + vcs = Vcs.getVcsForDevLib(proj); + } + } + + function doVcs(id:VcsID, ?libName:String, ?url:String, ?branch:String, ?subDir:String, ?version:String) + { + // Prepare check vcs.available: + var vcs = Vcs.get(id); + if(vcs == null || !vcs.available) + return print('Could not use $id, please make sure it is installed and available in your PATH.'); + + // if called with known values: + if(libName != null && url != null) + doVcsInstall(vcs, libName, url, branch, subDir, version); + else + doVcsInstall(vcs, + param("Library name"), + param(vcs.name + " path"), + paramOpt(), + paramOpt(), + paramOpt() + ); + } + + function doVcsInstall(vcs:Vcs, libName:String, url:String, ?branch:String, ?subDir:String, ?version:String) + { + var rep = getRepository(); + var proj = rep + Data.safe(libName); + + // find & remove all existing repos: + removeExistingDevLib(proj); + // currently we already kill all dev-repos for all supported Vcs. + + + var libPath = proj + "/" + vcs.directory; + + // prepare for new repo + if(FileSystem.exists(libPath)) + deleteRec(libPath); + + + print("Installing " +libName + " from " +url); + + try + { + vcs.clone(libPath, url, branch, version, cast settings); + } + catch(error:VcsError) + { + var message = switch(error) + { + case VcsError.VcsUnavailable(vcs): + 'Could not use ${vcs.executable}, please make sure it is installed and available in your PATH.'; + case VcsError.CantCloneRepo(vcs, repo, stderr): + 'Could not clone ${vcs.name} repository' + (stderr != null ? ":\n" + stderr : "."); + case VcsError.CantCheckoutBranch(vcs, branch, stderr): + 'Could not checkout branch, tag or path "$branch": ' + stderr; + case VcsError.CantCheckoutVersion(vcs, version, stderr): + 'Could not checkout tag "$version": ' + stderr; + } + print(message); + deleteRec(libPath); + } + + + // finish it! + var devPath = libPath + (subDir == null ? "" : "/" + subDir); + + cli.cwd = proj; + + File.saveContent(".dev", devPath); + + print('Library $libName set to use ${vcs.name}.'); + + if(branch != null) + print(' Branch/Tag/Rev: $branch'); + print(' Path: $devPath'); + + cli.cwd = libPath; + + if(FileSystem.exists("haxelib.json")) + doInstallDependencies( + Data.readData(File.getContent("haxelib.json"), false).dependencies + ); + } + + + function run() { + var rep = getRepository(); + var project = param("Library"); + var temp = project.split(":"); + project = temp[0]; + var pdir = rep + Data.safe(project); + if( !FileSystem.exists(pdir) ) + throw "Library "+project+" is not installed"; + pdir += "/"; + var version = temp[1] != null ? temp[1] : getCurrent(pdir); + var dev = try getDev(pdir) catch ( e : Dynamic ) null; + var vdir = dev != null ? dev : pdir + Data.safe(version); + + args.push(cli.cwd); + cli.cwd = vdir; + + var callArgs = + switch try [Data.readData(File.getContent(vdir + '/haxelib.json'), false), null] catch (e:Dynamic) [null, e] { + case [null, e]: + throw 'Error parsing haxelib.json for $project@$version: $e'; + case [{ main: null }, _]: + if( !FileSystem.exists('$vdir/run.n') ) + throw 'Library $project version $version does not have a run script'; + ["neko", "run.n"]; + case [{ main: cls, dependencies: _.toArray() => deps }, _]: + deps = switch deps { case null: []; default: deps.copy(); }; + deps.push( { name: project, version: DependencyVersion.DEFAULT } ); + var args = []; + for (d in deps) { + args.push('-lib'); + args.push(d.name + if (d.version == '') '' else ':${d.version}'); + } + args.unshift('haxe'); + args.push('--run'); + args.push(cls); + args; + default: throw 'assert'; + } + + for (i in argcur...args.length) + callArgs.push(args[i]); + + Sys.putEnv("HAXELIB_RUN", "1"); + var cmd = callArgs.shift(); + Sys.exit(Sys.command(cmd, callArgs)); + } + + function local() { + var file = param("Package"); + if (doInstallFile(file, true, true).name == 'haxelib_client') + if (ask('You have updated haxelib. Do you wish to rebuild it?') != No) { + rebuildSelf(); + } + } + + inline function command(cmd:String, args:Array) + return cli.command(cmd, args); + + function proxy() { + var rep = getRepository(); + var host = param("Proxy host"); + if( host == "" ) { + if( FileSystem.exists(rep + "/.proxy") ) { + FileSystem.deleteFile(rep + "/.proxy"); + print("Proxy disabled"); + } else + print("No proxy specified"); + return; + } + var port = Std.parseInt(param("Proxy port")); + var authName = param("Proxy user login"); + var authPass = authName == "" ? "" : param("Proxy user pass"); + var proxy = { + host : host, + port : port, + auth : authName == "" ? null : { user : authName, pass : authPass }, + }; + Http.PROXY = proxy; + print("Testing proxy..."); + try Http.requestUrl("http://www.google.com") catch( e : Dynamic ) { + print("Proxy connection failed"); + return; + } + File.saveContent(rep + "/.proxy", haxe.Serializer.run(proxy)); + print("Proxy setup done"); + } + + function loadProxy() { + var rep = getRepository(); + try Http.PROXY = haxe.Unserializer.run(File.getContent(rep + "/.proxy")) catch( e : Dynamic ) { }; + } + + function convertXml() { + var cwd = cli.cwd; + var xmlFile = cwd + "haxelib.xml"; + var jsonFile = cwd + "haxelib.json"; + + if (!FileSystem.exists(xmlFile)) + { + print('No `haxelib.xml` file was found in the current directory.'); + Sys.exit(0); + } + + var xmlString = File.getContent(xmlFile); + var json = ConvertXml.convert(xmlString); + var jsonString = ConvertXml.prettyPrint(json); + + File.saveContent(jsonFile, jsonString); + print('Saved to $jsonFile'); + } + + function newRepo() { + if( FileSystem.exists(REPODIR) ) { + if( !FileSystem.isDirectory(REPODIR) ) { + print('$REPODIR exists already but is not a directory, delete it first'); + Sys.exit(1); + } + try { + sys.io.File.saveContent(REPODIR+"/checkWrite.txt","CHECK WRITE"); + } catch( e : Dynamic ) { + print('$REPODIR exists but is not writeable, chmod it'); + Sys.exit(2); + } + FileSystem.deleteFile(REPODIR+"/checkWrite.txt"); + } else { + try { + FileSystem.createDirectory(REPODIR); + } catch( e : Dynamic ) { + print('Failed to create ./$REPODIR'); + Sys.exit(3); + } + } + } + + function deleteRepo() { + if( !FileSystem.exists(REPODIR) ) + return; + function deleteRec(path) { + if( FileSystem.isDirectory(path) ) { + for( f in FileSystem.readDirectory(path) ) + deleteRec(Path.join([path, f])); + FileSystem.deleteDirectory(path); + } else + FileSystem.deleteFile(path); + } + deleteRec(REPODIR); + } + + // ---------------------------------- + + inline function print(str) + cli.print(str); + + static function main() { + new Main().process(); + } + +} diff --git a/extra/haxelib_src/src/tools/haxelib/Paths.hx b/extra/haxelib_src/src/tools/haxelib/Paths.hx new file mode 100644 index 0000000000000000000000000000000000000000..1acf47df1ebfe6b9e9eb4e1dabb00037236eeff4 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Paths.hx @@ -0,0 +1,19 @@ +package tools.haxelib; + +class Paths { + static var RELATIVE_ROOT = + #if haxelib_api + '../../'; + #else + ''; + #end + //TODO: these should be inline or read-only or whatever + static public var CWD = neko.Web.getCwd() + RELATIVE_ROOT; + static public var DB_CONFIG = CWD + "dbconfig.json"; + static public var DB_FILE = CWD + "haxelib.db"; + + static public var TMP_DIR = CWD + "tmp"; + static public var TMPL_DIR = CWD + "tmpl/"; + static public var REP_DIR = CWD + Data.REPOSITORY; + +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Rebuild.hx b/extra/haxelib_src/src/tools/haxelib/Rebuild.hx new file mode 100644 index 0000000000000000000000000000000000000000..946fd5b4ea9819ce1b98cfa4fa2a25ede6e598c8 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Rebuild.hx @@ -0,0 +1,46 @@ +package tools.haxelib; + +import sys.FileSystem; +import sys.io.Process; + +class Rebuild { + static function run(cmd:String, ?msg:String = '', ?args:Array) { + if (args == null) args = []; + var p = new Process(cmd, args); + if (p.exitCode() != 0) + throw 'Error $msg:' + p.stderr.readAll().toString(); + } + static function main() + try { + Sys.sleep(.5);//wait for calling haxelib to exit + switch Sys.systemName() { + case 'Windows': + case os: throw 'Wrong OS. Expected Windows but detected $os'; + } + var haxepath = Sys.getEnv("HAXEPATH"); + var file = '$haxepath/haxelib.n'; + + run('haxe', 'rebuilding haxelib', [ + '-neko', file, + '-lib', 'haxelib_client', + '-main', 'tools.haxelib.Main', + ]); + run('nekotools', 'booting haxe', ['boot', file]); + FileSystem.deleteFile(file); + var oldMode = FileSystem.exists('update.hxml'); + if (oldMode) + FileSystem.deleteFile('update.hxml'); + + Sys.println('Update successful.'); + + if (!oldMode) { + Sys.println('Rebuild will exit in 5 seconds.'); + Sys.sleep(5.0); + } + } + catch (e:Dynamic) { + Sys.println(Std.string(e)); + Sys.println('Press any key to close'); + Sys.getChar(false); + } +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Repo.hx b/extra/haxelib_src/src/tools/haxelib/Repo.hx new file mode 100644 index 0000000000000000000000000000000000000000..4a31e389a627d39d7776354babace159ef839ca3 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Repo.hx @@ -0,0 +1,325 @@ +/* + * Copyright (C)2005-2012 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 tools.haxelib; +import haxe.io.Bytes; +import tools.haxelib.Data; +import tools.haxelib.Paths.*; +import tools.haxelib.SiteDb; +import neko.Web; +import tools.haxelib.SemVer; + +class Repo implements SiteApi { + + static function run() { + if( !sys.FileSystem.exists(TMP_DIR) ) + sys.FileSystem.createDirectory(TMP_DIR); + if( !sys.FileSystem.exists(REP_DIR) ) + sys.FileSystem.createDirectory(REP_DIR); + + var ctx = new haxe.remoting.Context(); + ctx.addObject("api", new Repo()); + + if( haxe.remoting.HttpConnection.handleRequest(ctx) ) + return; + else + throw "Invalid remoting call"; + } + + public function new() {} + + public function search( word : String ) : List<{ id : Int, name : String }> { + return Project.containing(word); + } + + public function infos( project : String ) : ProjectInfos { + var p = Project.manager.select($name == project); + if( p == null ) + throw "No such Project : "+project; + var vl = Version.manager.search($project == p.id); + + return { + name : p.name, + curversion : if( p.version == null ) null else p.version.toSemver(), + desc : p.description, + versions: + [for ( v in vl ) { + name : v.toSemver(), + comments : v.comments, + date : v.date + }], + owner : p.owner.name, + website : p.website, + license : p.license, + tags : Tag.manager.search($project == p.id).map(function(t) return t.tag), + }; + } + + public function user( name : String ) : UserInfos { + var u = User.manager.search($name == name).first(); + if( u == null ) + throw "No such user : "+name; + var pl = Project.manager.search($owner == u.id); + var projects = new Array(); + for( p in pl ) + projects.push(p.name); + return { + name : u.name, + fullname : u.fullname, + email : u.email, + projects : projects, + }; + } + + public function register( name : String, pass : String, mail : String, fullname : String ) : Bool { + if( !Data.alphanum.match(name) ) + throw "Invalid user name, please use alphanumeric characters"; + if( name.length < 3 ) + throw "User name must be at least 3 characters"; + var u = new User(); + u.name = name; + u.pass = pass; + u.email = mail; + u.fullname = fullname; + u.insert(); + return null; + } + + public function isNewUser( name : String ) : Bool { + return User.manager.select($name == name) == null; + } + + public function checkDeveloper( prj : String, user : String ) : Void { + var p = Project.manager.search({ name : prj }).first(); + if( p == null ) + return; + for( d in Developer.manager.search({ project : p.id }) ) + if( d.user.name == user ) + return; + throw "User '"+user+"' is not a developer of project '"+prj+"'"; + } + + public function checkPassword( user : String, pass : String ) : Bool { + var u = User.manager.search({ name : user }).first(); + return u != null && u.pass == pass; + } + + public function getSubmitId() : String { + return Std.string(Std.random(100000000)); + } + + public function processSubmit( id : String, user : String, pass : String ) : String { + var path = TMP_DIR+"/"+Std.parseInt(id)+".tmp"; + + var file = try sys.io.File.read(path,true) catch( e : Dynamic ) throw "Invalid file id #"+id; + var zip = try haxe.zip.Reader.readZip(file) catch( e : Dynamic ) { file.close(); neko.Lib.rethrow(e); }; + file.close(); + + var infos = Data.readInfos(zip,true); + var u = User.manager.search({ name : user }).first(); + if( u == null || u.pass != pass ) + throw "Invalid username or password"; + + var devs = infos.contributors.map(function(user) { + var u = User.manager.search({ name : user }).first(); + if( u == null ) + throw "Unknown user '"+user+"'"; + return u; + }); + + var tags = Lambda.array(infos.tags); + tags.sort(Reflect.compare); + + var p = Project.manager.search({ name : infos.name }).first(); + + // create project if needed + if( p == null ) { + p = new Project(); + p.name = infos.name; + p.description = infos.description; + p.website = infos.url; + p.license = infos.license; + p.owner = u; + p.insert(); + for( u in devs ) { + var d = new Developer(); + d.user = u; + d.project = p; + d.insert(); + } + for( tag in tags ) { + var t = new Tag(); + t.tag = tag; + t.project = p; + t.insert(); + } + } + + // check submit rights + var pdevs = Developer.manager.search({ project : p.id }); + var isdev = false; + for( d in pdevs ) + if( d.user.id == u.id ) { + isdev = true; + break; + } + if( !isdev ) + throw "You are not a developer of this project"; + + var otags = Tag.manager.search({ project : p.id }); + var curtags = otags.map(function(t) return t.tag).join(":"); + + // update public infos + if( infos.description != p.description || p.website != infos.url || p.license != infos.license || pdevs.length != devs.length || tags.join(":") != curtags ) { + if( u.id != p.owner.id ) + throw "Only project owner can modify project infos"; + p.description = infos.description; + p.website = infos.url; + p.license = infos.license; + p.update(); + if( pdevs.length != devs.length ) { + for( d in pdevs ) + d.delete(); + for( u in devs ) { + var d = new Developer(); + d.user = u; + d.project = p; + d.insert(); + } + } + if( tags.join(":") != curtags ) { + for( t in otags ) + t.delete(); + for( tag in tags ) { + var t = new Tag(); + t.tag = tag; + t.project = p; + t.insert(); + } + } + } + + // look for current version + var current = null; + for( v in Version.manager.search({ project : p.id }) ) + if( v.name == infos.version ) { + current = v; + break; + } + + // update documentation + var doc = null; + var docXML = Data.readDoc(zip); + if( docXML != null ) { + try { + var p = new haxe.rtti.XmlParser(); + p.process(Xml.parse(docXML).firstElement(),null); + p.sort(); + var roots = new Array(); + for( x in p.root ) + switch( x ) { + case TPackage(name,_,_): + switch( name ) { + case "flash","flash8","sys","cs","java","flash9","haxe","js","neko","cpp","php","tools": // don't include haXe core types + default: roots.push(x); + } + default: + // don't include haXe root types + } + var s = new haxe.Serializer(); + s.useEnumIndex = true; + s.useCache = true; + s.serialize(roots); + doc = s.toString(); + } catch ( e:Dynamic ) { + // If documentation can't be generated, ignore it. + } + } + + // update file + var target = REP_DIR + "/" + Data.fileName(p.name, infos.version); + sys.FileSystem.rename(path,target); + var semVer = SemVer.ofString(infos.version); + + // update existing version + if( current != null ) { + current.documentation = doc; + current.comments = infos.releasenote; + current.update(); + return "Version "+current.name+" (id#"+current.id+") updated"; + } + + // add new version + var v = new Version(); + v.project = p; + v.major = semVer.major; + v.minor = semVer.minor; + v.patch = semVer.patch; + v.preview = semVer.preview; + v.previewNum = semVer.previewNum; + + v.comments = infos.releasenote; + v.downloads = 0; + v.date = Date.now().toString(); + v.documentation = doc; + v.insert(); + + p.version = v; + p.update(); + return "Version " + v.toSemver() + " (id#" + v.id + ") added"; + } + + public function postInstall( project : String, version : String ) { + var p = Project.manager.select($name == project); + if( p == null ) + throw "No such Project : " + project; + + var version = SemVer.ofString(version); + var v = Version.manager.select( + $project == p.id && + $major == version.major && + $minor == version.minor && + $patch == version.patch && + $preview == version.preview && + $previewNum == version.previewNum + ); + if( v == null ) + throw "No such Version : " + version; + v.downloads++; + v.update(); + p.downloads++; + p.update(); + } + + static function main() { + var error = null; + SiteDb.init(); + try { + run(); + } catch( e : Dynamic ) { + error = { e : e }; + } + SiteDb.cleanup(); + if( error != null ) + neko.Lib.rethrow(error.e); + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/SemVer.hx b/extra/haxelib_src/src/tools/haxelib/SemVer.hx new file mode 100644 index 0000000000000000000000000000000000000000..80b76543a8de792f4c2d23c0ffaa377190a4f8d6 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/SemVer.hx @@ -0,0 +1,140 @@ +package tools.haxelib; + +import haxe.ds.Option; + +using Std; + +enum Preview { + ALPHA; + BETA; + RC; +} + +abstract SemVer(String) to String { + + public var major(get, never):Int; + public var minor(get, never):Int; + public var patch(get, never):Int; + public var preview(get, never):Null; + public var previewNum(get, never):Null; + public var data(get, never):SemVerData; + public var valid(get, never):Bool; + + inline function new(s) this = s; + + static public function compare(a:SemVer, b:SemVer) { + function toArray(data:SemVerData) + return [ + data.major, + data.minor, + data.patch, + if (data.preview == null) 100 else data.preview.getIndex(), + if (data.previewNum == null) -1 else data.previewNum + ]; + + var a = toArray(a.data), + b = toArray(b.data); + + for (i in 0...a.length) + switch Reflect.compare(a[i], b[i]) { + case 0: + case v: return v; + } + + return 0; + } + @:to public function toValidatable():Validator.Validatable + return { + validate: + function ():Option<{ error: String }> + return + try { + get_data(); + None; + } + catch (e:Dynamic) + Some({ + error: Std.string(e) + }) + } + + inline function get_major() + return data.major; + + inline function get_minor() + return data.minor; + + inline function get_patch() + return data.patch; + + inline function get_preview() + return data.preview; + + inline function get_previewNum() + return data.previewNum; + + inline function get_valid() + return isValid(this); + + static var FORMAT = ~/^([0-9]+)\.([0-9]+)\.([0-9]+)(-(alpha|beta|rc)(\.([0-9]+))?)?$/; + + static var cache = new Map(); + + @:to function get_data():SemVerData { + if (!cache.exists(this)) + cache[this] = getData(); + return cache[this]; + } + + @:from static function fromData(data:SemVerData) + return + new SemVer( + data.major + '.' + data.minor + '.' + data.patch + + if (data.preview == null) '' + else '-' + data.preview.getName().toLowerCase() + + if (data.previewNum == null) ''; + else '.' + data.previewNum + ); + + function getData():SemVerData + return + if (valid) {//RAPTORS: This query will already cause the matching. + major: FORMAT.matched(1).parseInt(), + minor: FORMAT.matched(2).parseInt(), + patch: FORMAT.matched(3).parseInt(), + preview: + switch FORMAT.matched(5) { + case 'alpha': ALPHA; + case 'beta': BETA; + case 'rc': RC; + case v if (v == null): null; + case v: throw 'unrecognized preview tag $v'; + }, + previewNum: + switch FORMAT.matched(7) { + case null: null; + case v: v.parseInt(); + } + } + else + throw '$this is not a valid version string';//TODO: include some URL for reference + + static public function isValid(s:String) + return Std.is(s, String) && FORMAT.match(s.toLowerCase()); + + static public function ofString(s:String) { + var ret = new SemVer(s); + ret.getData(); + return ret; + } + + static public var DEFAULT(default, null) = new SemVer('0.0.0'); +} + +typedef SemVerData = { + major:Int, + minor:Int, + patch:Int, + preview:Null, + previewNum:Null, +} diff --git a/extra/haxelib_src/src/tools/haxelib/Site.hx b/extra/haxelib_src/src/tools/haxelib/Site.hx new file mode 100644 index 0000000000000000000000000000000000000000..937823d57fc4f4c86fa9f7fe3071c5ff9264ea13 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Site.hx @@ -0,0 +1,313 @@ +/* + * Copyright (C)2005-2012 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 tools.haxelib; + +import haxe.web.Dispatch; +import neko.Lib; +import neko.Web; +import sys.db.*; +import sys.io.File; +import tools.haxelib.SiteDb; +import haxe.rtti.CType; +import haxe.Json; +import tools.haxelib.Paths.*; + +using sys.io.File; +using sys.FileSystem; +using Lambda; + +class Site { + static function setup() {}//obsolete + + static function run() { + + if( !sys.FileSystem.exists(TMP_DIR) ) + sys.FileSystem.createDirectory(TMP_DIR); + if( !sys.FileSystem.exists(REP_DIR) ) + sys.FileSystem.createDirectory(REP_DIR); + + if( Sys.args()[0] == "setup" ) { + setup(); + Sys.print("Setup done\n"); + return; + } + var file = null; + var sid = null; + var bytes = 0; + + //RAPTORS: the whole handling for nekotools is seriously evil + if (Sys.executablePath().indexOf('nekotools') == -1) + Web.parseMultipart(function(p,filename) { + if( p == "file" ) { + sid = Std.parseInt(filename); + file = sys.io.File.write(TMP_DIR + "/" + sid + ".tmp", true); + } else + throw p+" not accepted"; + },function(data,pos,len) { + bytes += len; + file.writeFullBytes(data,pos,len); + }); + else { + var post = Web.getPostData(); + if (post != null) { + var index = post.indexOf('PK'); + if (index == -1) + throw 'Invalid Zip - or so I claim'; + + var start = post.substr(0, index); + var data = post.substr(index); + + sid = Std.parseInt(start.split('filename="').pop()); + file = sys.io.File.write(TMP_DIR + "/" + sid + ".tmp", true); + bytes = data.length;//thank got neko does not use utf8 + file.writeString(data); + } + } + + if( file != null ) { + file.close(); + Sys.print("File #"+sid+" accepted : "+bytes+" bytes written"); + return; + } + display(); + } + + static function getTemplate(name:String) { + var data = File.getContent(TMPL_DIR + name + '.mtt'); + return new Template(data); + } + static var macros = { + download : function( res:String->Dynamic, p, v ) { + return "/" + Data.REPOSITORY + "/" + Data.fileName(res(p).name, res(v).toSemver().toString()); + }, + }; + + static function display() { + + // required by all templates + haxe.Template.globals.menuTags = Tag.topTags(10); + + var uri = Web.getURI(); + if (uri == "/index.n") uri = "/"; + + try { + Dispatch.run(uri,Web.getParams(), Site); + } + catch (e:DispatchError) { + // TODO: maybe we could give a nicer error message + error('Page not found:' + uri); + } + + } + static function error(msg:String) { + render('error', { + error: StringTools.htmlEscape(msg), + legacyurl: "/legacy"+Web.getURI() + }); + } + // render content into layout template + static function render(page:String, context:Dynamic) { + var layout = getTemplate('layout'); + var content = getTemplate(page); + Sys.print(layout.execute({ + content: content.execute(context, macros), + site: neko.Web.getHostName() + })); + } + // index page + static function doDefault() { + var vl = Version.latest(10); + for( v in vl ) { + var p = v.project; // fetch + } + return render('index', { + versions: vl + }); + } + + // project page + static function doP(name:String) { + var p = Project.manager.select({ name : name }); + if( p == null ) + return error("Unknown project '"+name+"'"); + return render('project', { + p: p, + owner: p.owner, + version: p.version, + versions: Version.byProject(p), + tags: Tag.manager.search({ project : p.id }) + }); + } + + // user page + static function doU(name:String) { + var u = User.manager.select({ name : name }); + if( u == null ) + return error("Unknown user '"+name+"'"); + return render('user', { + u: u, + uprojects: Developer.manager.search({ user : u.id }).map(function(d:Developer) { return d.project; }) + }); + } + + // tag page + static function doT(tagName: String) { + render('tag', { + tag: StringTools.htmlEscape(tagName), + tprojects: Tag.manager.search({ tag : tagName }).map(function(t) return t.project) + }); + } + + // list of all projects page + static function doAll() { + render('list', { + projects: Project.allByName() + }); + } + + // documenation + static function doD(name:String, version:Null) { + return error('Library documenation display is currently not implemented'); + /* + // TODO: the current project does not allow uploads with documenation, this ported, but not tested + var ctx:Dynamic = {}; + var p = Project.manager.select({ name : name }); + if( p == null ) + return error("Unknown project '"+name+"'"); + var v; + if( version == null ) { + v = p.version; + version = v.name; + } else { + v = Version.manager.select( { project : p.id, name : version } ); + if( v == null ) return error("Unknown version '"+version+"'"); + } + if( v.documentation == null ) + return error("Project "+p.name+" version "+version+" has no documentation"); + var root : TypeRoot = haxe.Unserializer.run(v.documentation); + var buf = new StringBuf(); + var html = new tools.haxedoc.HtmlPrinter("/d/"+p.name+"/"+version+"/","",""); + html.output = function(str) buf.add(str); + var path = uri.join(".").toLowerCase().split("."); + if( path.length == 1 && path[0] == "" ) + path = []; + if( path.length == 0 ) { + ctx.index = true; + html.process(TPackage("root","root",root)); + } else { + var cl = html.find(root,path,0); + if( cl == null ) { + // we most likely clicked on a class which is part of the haxe core documentation + Web.redirect("http://haxe.org/api/"+path.join("/")); + return false; + } + html.process(cl); + } + ctx.p = p; + ctx.v = v; + ctx.content = buf.toString(); + return render('documentation', {}); + */ + } + + // search + static function doSearch() { + var v = Web.getParams().get("v"); + var p = Project.manager.select({ name : v }); + if( p != null ) { + return Web.redirect("/p/"+p.name); + } + if( Tag.manager.count({ tag : v }) > 0 ) { + return Web.redirect("/t/"+v); + } + return render('list', { + search: StringTools.htmlEscape(v), + projects: Project.containing(v).map(function(p) return Project.manager.get(p.id)) + }); + } + + // RSS feed + static function doRss() { + Web.setHeader("Content-Type", "text/xml; charset=UTF-8"); + Sys.println(''); + Sys.print(buildRss().toString()); + } + + static function buildRss() : Xml { + var createChild = function(root:Xml, name:String){ + var c = Xml.createElement(name); + root.addChild(c); + return c; + } + var createChildWithContent = function(root:Xml, name:String, content:String){ + var e = Xml.createElement(name); + var c = Xml.createPCData(if (content != null) content else ""); + e.addChild(c); + root.addChild(e); + return e; + } + var createChildWithCdata = function(root:Xml, name:String, content:String){ + var e = Xml.createElement(name); + var c = Xml.createCData(if (content != null) content else ""); + e.addChild(c); + root.addChild(e); + return e; + } + Sys.setTimeLocale("en_US.UTF8"); + var url = "http://"+Web.getClientHeader("Host"); + var rss = Xml.createElement("rss"); + var num = 50; + rss.set("version","2.0"); + var channel = createChild(rss, "channel"); + createChildWithContent(channel, "title", 'Latest haxelib releases (${neko.Web.getHostName()})'); + createChildWithContent(channel, "link", url); + createChildWithContent(channel, "description", 'The $num latest haxelib releases on ${neko.Web.getHostName()}'); + createChildWithContent(channel, "generator", "haxe"); + createChildWithContent(channel, "language", "en"); + for (v in Version.latest(num)){ + var project = v.project; + var item = createChild(channel, "item"); + createChildWithContent(item, "title", StringTools.htmlEscape(project.name + " " + v.toSemver())); + createChildWithContent(item, "link", url+"/p/"+project.name); + createChildWithContent(item, "guid", url+"/p/"+project.name+"?v="+v.id); + var date = DateTools.format(Date.fromString(v.date), "%a, %e %b %Y %H:%M:%S %z"); + createChildWithContent(item, "pubDate", date); + createChildWithContent(item, "author", project.owner.name); + createChildWithContent(item, "description", StringTools.htmlEscape(v.comments)); + } + return rss; + } + + static function main() { + var error = null; + SiteDb.init(); + try { + run(); + } catch( e : Dynamic ) { + error = { e : e }; + } + SiteDb.cleanup(); + if( error != null ) + Lib.rethrow(error.e); + } + +} diff --git a/std/tools/haxelib/SiteApi.hx b/extra/haxelib_src/src/tools/haxelib/SiteApi.hx similarity index 100% rename from std/tools/haxelib/SiteApi.hx rename to extra/haxelib_src/src/tools/haxelib/SiteApi.hx diff --git a/extra/haxelib_src/src/tools/haxelib/SiteDb.hx b/extra/haxelib_src/src/tools/haxelib/SiteDb.hx new file mode 100644 index 0000000000000000000000000000000000000000..8123eeeddb98c5db8fc47b2e01dc38a43f2e484c --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/SiteDb.hx @@ -0,0 +1,154 @@ +/* + * Copyright (C)2005-2012 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 tools.haxelib; + +import sys.db.*; +import sys.db.Types; +import tools.haxelib.Paths.*; +using sys.io.File; +using sys.FileSystem; + +class User extends Object { + + public var id : SId; + public var name : String; + public var fullname : String; + public var email : String; + public var pass : String; + +} + +class Project extends Object { + + public var id : SId; + public var name : String; + public var description : String; + public var website : String; + public var license : String; + public var downloads : Int = 0; + @:relation(owner) public var owner : User; + @:relation(version) public var version : SNull; + + static public function containing( word:String ) : List<{ id: Int, name: String }> { + var ret = new List(); + word = '%$word%'; + for (project in manager.search($name.like(word) || $description.like(word))) + ret.push( { id: project.id, name: project.name } ); + return ret; + } + + static public function allByName() { + //TODO: Propose SPOD patch to support manager.search(true, { orderBy: name.toLowerCase() } ); + return manager.unsafeObjects('SELECT * FROM Project ORDER BY LOWER(name)', false); + } + +} + +class Tag extends Object { + + public var id : SId; + public var tag : String; + @:relation(project) public var project : Project; + + static public function topTags( n : Int ) : List<{ tag:String, count: Int }> { + return cast Manager.cnx.request("SELECT tag, COUNT(*) as count FROM Tag GROUP BY tag ORDER BY count DESC LIMIT " + n).results(); + } + +} + +class Version extends Object { + + public var id : SId; + @:relation(project) public var project : Project; + public var major : Int; + public var minor : Int; + public var patch : Int; + @:nullable public var preview : SEnum; + public var previewNum : SNull; + @:skip public var name(get, never):String; + function get_name():String return toSemver(); + + public function toSemver():SemVer { + return { + major: this.major, + minor: this.minor, + patch: this.patch, + preview: this.preview, + previewNum: this.previewNum, + } + } + public var date : String; // sqlite does not have a proper 'date' type + public var comments : String; + public var downloads : Int; + public var documentation : SNull; + + static public function latest( n : Int ) { + return manager.search(true, { orderBy: -date, limit: n } ); + } + + static public function byProject( p : Project ) { + return manager.search($project == p.id, { orderBy: -date } ); + } + +} + +@:id(user,project) +class Developer extends Object { + + @:relation(user) public var user : User; + @:relation(project) public var project : Project; + +} + +class SiteDb { + static var db : Connection; + //TODO: this whole configuration business is rather messy to say the least + + static public function init() { + db = + if (DB_CONFIG.exists()) + Mysql.connect(haxe.Json.parse(DB_CONFIG.getContent())); + else + Sqlite.open(DB_FILE); + + Manager.cnx = db; + Manager.initialize(); + + var managers:Array> = [ + User.manager, + Project.manager, + Tag.manager, + Version.manager, + Developer.manager + ]; + for (m in managers) + if (!TableCreate.exists(m)) + TableCreate.create(m); + } + static public function cleanup() { + db.close(); + Manager.cleanup(); + } + public static function create( db : sys.db.Connection ) { + //now based on TableCreate when establishing the connection + } +} diff --git a/extra/haxelib_src/src/tools/haxelib/Template.hx b/extra/haxelib_src/src/tools/haxelib/Template.hx new file mode 100644 index 0000000000000000000000000000000000000000..fd0f55a5e7c6360a694b2ac33825e572d26307fd --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Template.hx @@ -0,0 +1,72 @@ +package tools.haxelib; + +import haxe.ds.Option; +import haxe.ds.StringMap; + +class Template extends haxe.Template { + static var fieldCache = new StringMap(); + static function fieldMap(type:Class) { + var name = Type.getClassName(type); + if (!fieldCache.exists(name)) { + fieldCache.set(name, [for (field in Type.getInstanceFields(type)) field => true]); + } + return fieldCache.get(name); + } + function tryField(o:Dynamic, field:String):Option { + return + switch Type.typeof(o) { + case TClass(c): + var fields = fieldMap(c); + if (fields.exists(field) || fields.exists('get_$field')) + Some(Reflect.getProperty(o, field)); + else { + None; + } + default: + if (Reflect.hasField(o, field)) Some(Reflect.field(o, field)); + else None; + } + } + function getField(o, field) + return + switch tryField(o, field) { + case Some(v): v; + case None: null; + } + + override private function makePath(e:Void -> Dynamic, l):Dynamic { + if (false) super.makePath(e, l);//to infer l + + var p = l.first(); + if( p == null || p.p != "." ) + return e; + l.pop(); + var field = l.pop(); + if( field == null || !field.s ) + throw field.p; + var f = field.p; + haxe.Template.expr_trim.match(f); + f = haxe.Template.expr_trim.matched(1); + return makePath(function() { return getField(e(), f); }, l); + } + override function resolve(field:String):Dynamic { + switch tryField(context, field) { + case Some(v): return v; + case None: + } + for (ctx in stack) + switch tryField(ctx, field) { + case Some(v): return v; + case None: + } + + if (field == "__current__" ) + return context; + + return + switch tryField(haxe.Template.globals, field) { + case Some(v): v; + case None: null; + } + } +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Validator.hx b/extra/haxelib_src/src/tools/haxelib/Validator.hx new file mode 100644 index 0000000000000000000000000000000000000000..bec27b38400b8bfe8386709e1da518f52added37 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Validator.hx @@ -0,0 +1,156 @@ +package tools.haxelib; + +import haxe.ds.Option; + +#if macro +import haxe.macro.Expr; +import haxe.macro.Type; +import haxe.macro.Context; + +using haxe.macro.Tools; +#end + +typedef Validatable = { + function validate():Option<{ error: String }>; +} + +class Validator { + #if macro + static var ARG = 'v'; + var pos:Position; + var IARG:Expr; + function new(pos) { + this.pos = pos; + IARG = macro @:pos(pos) $i{ARG}; + } + + function doCheck(t:Type, e:Expr) { + var ct = t.toComplexType(); + return + macro @:pos (function ($ARG : $ct) ${makeCheck(t)})($e); + } + + function isAtom(s:String) + return switch s { + case 'String', 'Int', 'Bool', 'Float': true; + default: false; + } + + function enforce(type:String) + return + macro @:pos(pos) if (!Std.is($i{ARG}, $i{type})) throw '$type expected'; + + function rename(e:Expr) + return switch e { + case macro $i{name} if (name == '_'): IARG; + default: e.map(rename); + } + + function makeCheck(t:Type):Expr + return + switch Context.follow(t) { + case TAnonymous(_.get().fields => fields): + + var block:Array = [ + for (f in fields) + if (f.kind.match(FVar(AccNormal, _))) + { + var name = f.name; + var rec = doCheck(f.type, macro @:pos(pos) $IARG.$name); + + if (f.meta.has(':requires')) { + var body = []; + for (m in f.meta.get()) + if (m.name == ':requires') + for (p in m.params) + switch p { + case macro $msg => $p: + body.push(rename( + macro @:pos(pos) if (!$p) throw $msg + )); + default: + Context.error('Should be "" =>" ', p.pos); + } + //{ + //p = rename(p); + //cond = macro @:pos(pos) $p && $cond; + //} + + var t = f.type.toComplexType(); + rec = macro @:pos(pos) { + $rec; + (function($ARG : $t) $b{body})($IARG.$name); + } + } + + if (f.meta.has(':optional')) { + rec = macro @:pos(pos) if (Reflect.hasField($IARG, $v{name}) && $IARG.$name != null) $rec; + } + else + rec = macro @:pos(pos) + if (!Reflect.hasField($IARG, $v{name})) + throw ("missing field " + $v{name}); + else + $rec; + + rec; + } + ]; + + block.unshift( + macro @:pos(pos) if (!Reflect.isObject($IARG)) throw 'object expected' + ); + + macro @:pos(pos) $b{block}; + + case _.toString() => atom if (isAtom(atom)): + + enforce(atom); + + case TInst(_.get().module => 'Array', [p]): + + macro @:pos(pos) { + ${enforce('Array')}; + for ($IARG in $IARG) + ${doCheck(p, IARG)}; + } + + case TAbstract(_.get() => { from: [ { t: t, field: null } ] }, _): + + makeCheck(t); + + case TAbstract(_.get() => a, _) if (a.meta.has(':enum')): + var name = a.module + '.' + a.name; + var options:Array = [ + for (f in a.impl.get().statics.get()) + if (f.kind.match(FVar(_, _))) + macro @:pos(pos) $p{(name+'.'+f.name).split('.')} + ]; + + macro if (!Lambda.has($a { options }, $IARG)) throw 'Invalid value ' + $IARG + ' for ' + $v { a.name }; + + case TAbstract(_.get() => a, _): + + macro @:pos(pos) switch ($IARG : tools.haxelib.Validator.Validatable).validate() { + case Some( { error: e } ): throw e; + case None: + } + + case TDynamic(k): + var checker = makeCheck(k); + var ct = k.toComplexType(); + macro @:pos(pos) { + if (!Reflect.isObject($i{ARG})) throw 'object expected'; + for (f in Reflect.fields($i{ARG})) { + var $ARG:$ct = Reflect.field($i{ARG}, f); + $checker; + } + } + case v: + throw t.toString(); + } + #end + macro static public function validate(e:Expr) + return + new Validator(e.pos).doCheck(Context.typeof(e), e); +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/Vcs.hx b/extra/haxelib_src/src/tools/haxelib/Vcs.hx new file mode 100644 index 0000000000000000000000000000000000000000..a8709e9a640d625f9767eb61926d2b5678774ef2 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/Vcs.hx @@ -0,0 +1,399 @@ +package tools.haxelib; + +import tools.haxelib.Main; +import sys.FileSystem; + + + +interface IVcs +{ + public var name(default, null):String; + public var directory(default, null):String; + public var executable(default, null):String; + //TODO: public var internalDirectory(default, null):String; + + public var available(get_available, null):Bool; + + + + /** + Clone repo into CWD. + CWD must be like "...haxelib-repo/lib/git" for Git. + **/ + public function clone(libPath:String, vcsPath:String, ?branch:String, ?version:String, ?settings:Settings):Void; + + // check available updates for repo in CWD/{directory} + //TODO: public function updatable(libName:String):Void; + + /** + Update to HEAD repo contains in CWD or CWD/`Vcs.directory`. + CWD must be like "...haxelib-repo/lib/git" for Git. + Returns `true` if update successful. + **/ + public function update(libName:String, ?settings:Settings):Bool; + + // reset all changes in repo in CWD/{directory} + //TODO: public function reset(?cwd:String):Void; +} + + +@:enum abstract VcsID(String) to String +{ + var Hg = "hg"; + var Git = "git"; +} + +enum VcsError +{ + VcsUnavailable(vcs:Vcs); + CantCloneRepo(vcs:Vcs, repo:String, ?stderr:String); + CantCheckoutBranch(vcs:Vcs, branch:String, stderr:String); + CantCheckoutVersion(vcs:Vcs, version:String, stderr:String); +} + + +typedef Settings = +{ + var flat:Bool; + @:optional var quiet:Bool; + @:optional var debug:Bool; +}; + + +class Vcs implements IVcs +{ + private static var reg:Map; + + //----------- properties, fields ------------// + + public var name(default, null):String; + public var directory(default, null):String; + public var executable(default, null):String; + + public var available(get_available, null):Bool; + private var availabilityChecked:Bool = false; + private var executableSearched:Bool = false; + + private var cli(default, null):Cli; + + //--------------- constructor ---------------// + + public static function initialize() + { + if(reg == null) + reg = [VcsID.Git => new Git(), VcsID.Hg => new Mercurial()]; + else + { + if(reg.get(VcsID.Git) == null) + reg.set(VcsID.Git, new Git()); + if(reg.get(VcsID.Hg) == null) + reg.set(VcsID.Hg, new Mercurial()); + } + } + + + private function new(executable:String, directory:String, name:String) + { + this.name = name; + this.directory = directory; + this.executable = executable; + + cli = new Cli(); + } + + + //----------------- static ------------------// + + public static function get(id:VcsID):Null + { + initialize(); + return reg.get(id); + } + + private static function set(id:VcsID, vcs:Vcs, ?rewrite:Bool):Void + { + initialize(); + var existing = reg.get(id) != null; + if(!existing || (existing && rewrite)) + reg.set(id, vcs); + } + + public static function getVcsForDevLib(libPath:String):Null + { + initialize(); + for(k in reg.keys()) + { + if(FileSystem.exists(libPath + "/" + k) && FileSystem.isDirectory(libPath + "/" + k)) + return reg.get(k); + } + return null; + } + + + //--------------- initialize ----------------// + + private function searchExecutable():Void + { + executableSearched = true; + } + + private function checkExecutable():Bool + { + available = + executable != null && try + { + cli.command(executable, []).code == 0; + } + catch(e:Dynamic) false; + availabilityChecked = true; + + if(!available && !executableSearched) + searchExecutable(); + + return available; + } + + @:final function get_available():Bool + { + if(!availabilityChecked) + checkExecutable(); + return this.available; + } + + //----------------- ctrl -------------------// + + public function clone(libPath:String, vcsPath:String, ?branch:String, ?version:String, ?settings:Settings):Void + { + throw "This method must be overriden."; + } + + public function update(libName:String, ?settings:Settings):Bool + { + throw "This method must be overriden."; + return false; + } + + + public function toString():String + { + return Type.getClassName(Type.getClass(this)); + } +} + + +class Git extends Vcs +{ + public static function init() + { + Vcs.set(VcsID.Git, new Git()); + } + + public function new() + super("git", "git", "Git"); + + + override private function checkExecutable():Bool + { + available = + executable != null && try + { + // with `help` cmd because without any cmd `git` can return exit-code = 1. + cli.command(executable, ["help"]).code == 0; + } + catch(e:Dynamic) false; + availabilityChecked = true; + + if(!available && !executableSearched) + searchExecutable(); + + return available; + } + + override private function searchExecutable():Void + { + super.searchExecutable(); + + if(available) + return; + + // if we have already msys git/cmd in our PATH + var match = ~/(.*)git([\\|\/])cmd$/; + for(path in Sys.getEnv("PATH").split(";")) + { + if(match.match(path.toLowerCase())) + { + var newPath = match.matched(1) + executable + match.matched(2) + "bin"; + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + newPath); + } + } + if(checkExecutable()) + return; + // look at a few default paths + for(path in ["C:\\Program Files (x86)\\Git\\bin", "C:\\Progra~1\\Git\\bin"]) + if(FileSystem.exists(path)) + { + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + path); + if(checkExecutable()) + return; + } + } + + override public function update(libName:String, ?settings:Settings):Bool + { + var doPull = true; + + if(0 != Sys.command(executable, ["diff", "--exit-code"]) || 0 != Sys.command(executable, ["diff", "--cached", "--exit-code"])) + { + switch cli.ask("Reset changes to " + libName + " " + name + " repo so we can pull latest version?") + { + case Answer.Yes: + Sys.command(executable, ["reset", "--hard"]); + case Answer.No: + doPull = false; + cli.print(name + " repo left untouched"); + } + } + if(doPull) + { + var code = Sys.command(executable, ["pull"]); + // But if before we pulled specified branch/tag/rev => then possibly currently we haxe "HEAD detached at ..". + if(code != 0) + { + // get parent-branch: + var branch = cli.command(executable, ["show-branch"]).out; + var regx = ~/\[([^]]*)\]/; + if(regx.match(branch)) + branch = regx.matched(1); + + Sys.command(executable, ["checkout", branch, "--force"]); + Sys.command(executable, ["pull"]); + } + } + return doPull; + } + + override public function clone(libPath:String, url:String, ?branch:String, ?version:String, ?settings:Settings):Void + { + var vcsArgs = ["clone", url, libPath]; + + if(settings == null || !settings.flat) + vcsArgs.push('--recursive'); + + //TODO: move to Vcs.run(vcsArgs) + //TODO: use settings.quiet + if(Sys.command(executable, vcsArgs) != 0) + { + throw VcsError.CantCloneRepo(this, url/*, ret.out*/); + } + + + var cwd = cli.cwd; + cli.cwd = libPath; + + if(branch != null) + { + var ret = cli.command(executable, ["checkout", branch]); + if(ret.code != 0) + throw VcsError.CantCheckoutBranch(this, branch, ret.out); + } + + if(version != null) + { + var ret = cli.command(executable, ["checkout", "tags/" + version]); + if(ret.code != 0) + throw VcsError.CantCheckoutVersion(this, version, ret.out); + } + + // return prev. cwd: + cli.cwd = cwd; + } +} + + +class Mercurial extends Vcs +{ + public static function init() + { + Vcs.set(VcsID.Hg, new Mercurial()); + } + + public function new() + super("hg", "hg", "Mercurial"); + + override private function searchExecutable():Void + { + super.searchExecutable(); + + if(available) + return; + + // if we have already msys git/cmd in our PATH + var match = ~/(.*)hg([\\|\/])cmd$/; + for(path in Sys.getEnv("PATH").split(";")) + { + if(match.match(path.toLowerCase())) + { + var newPath = match.matched(1) + executable + match.matched(2) + "bin"; + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + newPath); + } + } + checkExecutable(); + } + + override public function update(libName:String, ?settings:Settings):Bool + { + var changed = false; + cli.command(executable, ["pull"]); + var summary = cli.command(executable, ["summary"]).out; + var diff = cli.command(executable, ["diff", "-U", "2", "--git", "--subrepos"]); + var status = cli.command(executable, ["status"]); + + // get new pulled changesets: + // (and search num of sets) + summary = summary.substr(0, summary.length - 1); + summary = summary.substr(summary.lastIndexOf("\n") + 1); + // we don't know any about locale then taking only Digit-exising:s + changed = ~/(\d)/.match(summary); + if(changed) + // print new pulled changesets: + cli.print(summary); + + + if(diff.code + status.code + diff.out.length + status.out.length != 0) + { + cli.print(diff.out); + switch cli.ask("Reset changes to " + libName + " " + name + " repo so we can update to latest version?") + { + case Answer.Yes: + Sys.command(executable, ["update", "--clean"]); + case Answer.No: + changed = false; + cli.print(name + " repo left untouched"); + } + } + else if(changed) + Sys.command(executable, ["update"]); + + return changed; + } + + override public function clone(libPath:String, url:String, ?branch:String, ?version:String, ?settings:Settings):Void + { + var vcsArgs = ["clone", url, libPath]; + + if(branch != null) + { + vcsArgs.push("--branch"); + vcsArgs.push(branch); + } + + if(version != null) + { + vcsArgs.push("--rev"); + vcsArgs.push(version); + } + + if(Sys.command(executable, vcsArgs) != 0) + throw VcsError.CantCloneRepo(this, url/*, ret.out*/); + } +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/dbconfig.json.example b/extra/haxelib_src/src/tools/haxelib/dbconfig.json.example new file mode 100644 index 0000000000000000000000000000000000000000..baf97456d68fd50d9fbc62cf16445740a7fa9828 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/dbconfig.json.example @@ -0,0 +1,6 @@ +{ + "user" : "dbUser", + "pass" : "dbPass", + "host" : "localhost", + "database" : "haxelib" +} \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/haxelib.css b/extra/haxelib_src/src/tools/haxelib/haxelib.css new file mode 100644 index 0000000000000000000000000000000000000000..9902c0934e28b0a1b14b76babab62e7563033e81 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/haxelib.css @@ -0,0 +1,216 @@ + +/* structure */ + +body { + margin : 0; + padding : 0; + text-align: center; + font-family : "trebuchet ms",sans-serif; + font-size : 10.5pt; + background : #FFFFFF url("http://haxe.org/img/haxe/bg_main.gif") repeat-x; +} +.legacy-notice { + border : 1px solid #AAA; + padding: 10px; + margin: 10px; +} +.page { + margin: 10px auto 10px auto; + padding : 5px; + width : 750px; + background-color : #FFFFFF; + border : 1px solid #AAA; + -moz-border-radius : 10px; +} + +.menu { + text-align : left; + float : left; + width : 150px; +} + +.content { + text-align : left; + float : left; + width : 600px; +} + +.clear { + clear : both; +} + +/* style */ + +a, a:visited { + color : #C35700; + text-decoration : none; +} + +a:hover { + text-decoration : underline; +} + +h1 { + text-align : center; + margin-top : 20px; +} + +h1 a, h1 a:hover, h1 a:visited { + color : #C35700; + text-decoration : none; +} + +.content p { + text-align : justify; + margin : 0px; + padding : 0px 10px 0px 10px; +} + +.menu ul { + list-style : none; + margin : 5px; + padding : 0px; +} + +.versions .date, .versions .project, .versions .name { + display : inline; +} + +.versions ul, .projects ul { + list-style : circle; + margin : 25px; + padding : 0px; +} + +.date { + color : #555; + font-size : 12px; +} + +.versions .name { + font-weight : bold; +} + +.versions .download { + float : right; + margin-top : -22px; + margin-right : 30px; +} + +.download { + padding : 2px 4px 2px 4px; + background-color : #eee; + display : inline; +} + +.download a { + color : #555; + font-size : 12px; + text-decoration : none; +} + +.download a:visited { + color : #555; +} + +.versions .comments { + margin-right : 40px; + margin-left : 10px; + margin-bottom : 5px; + text-align : justify; +} + +.pinfos .description { + padding : 10px; +} + +.pinfos .download { + margin : 200px; +} + +.label { + color : #555; + width : 80px; + float : left; +} + +.tags a { + margin-right : 5px; +} + +form { + margin-left : 5px; + margin-top : 5px; +} + +input { + width : 80px; +} + +/* documentation */ + +.api .title { + font-size: 35; + font-weight: bold; + text-align: center; + background-color : #FFD473; + color : white; +} + +.api ul.entry { + list-style-type: disc; + margin-left : 30px; + padding-left : 0px; +} + +.api .package_content { + display : none; +} + +.api a { + text-decoration : none; +} + +.api a:hover { + text-decoration : underline; +} + +.api a.package { + color : black; +} + +.api .index { +} + +.api .kwd { + color : #09598A; + font-weight : bold; +} + +.api .classname { + font-size : 30; + font-weight : bold; +} + +.api .classdoc { + border : 1px dashed #666; + margin-left : 20px; + margin-right : 20px; + padding : 5 5 5 5; +} + +.api .importmod, .api .extends, .api .implements, .api .typedef, .api .platforms { + color : #777; +} + +.api dd { + margin-top : 10px; + font-size : 12pt; + color : #444; +} + +.api dt { + margin-left : 20px; + margin-bottom : 5px; + text-align : left; +} diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/documentation.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/documentation.mtt new file mode 100644 index 0000000000000000000000000000000000000000..39f779842e67189fefb2919fae813a064c70425d --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/documentation.mtt @@ -0,0 +1,14 @@ +

::(p.name):: ::(v.name):: Documentation

+ + + +
+::content:: +
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/error.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/error.mtt new file mode 100644 index 0000000000000000000000000000000000000000..b5df2f36d064fa0394f6657ee05de8649e83a5c9 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/error.mtt @@ -0,0 +1,5 @@ +
+

::error::

+ +

Perhaps what you are looking for is still on the legacy haxelib site

+
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/index.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/index.mtt new file mode 100644 index 0000000000000000000000000000000000000000..c6232308114fad82f8bffdc0850a55ec3e4567f7 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/index.mtt @@ -0,0 +1,24 @@ +

Welcome

+ +

+ This website is listing all the libraries available through the haxelib Haxe package manager. + Please visit the haxelib page on Haxe website to learn more about haxelib. +

+ +

Latest releases

+ +
+ +
+ +

Browse Projects | RSS Feed

\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/layout.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/layout.mtt new file mode 100644 index 0000000000000000000000000000000000000000..f530edda3e106fc442b21cfdbf6c48c4662d78d9 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/layout.mtt @@ -0,0 +1,38 @@ + + + +haxelib (::site::) + + + + + + +

haxelib (::site::)

+ +
+ + + + +
+ ::content:: +
+ +
+ +
+ + + diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/list.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/list.mtt new file mode 100644 index 0000000000000000000000000000000000000000..bdc7188ff43bbb18ca30f03d0db522556e122163 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/list.mtt @@ -0,0 +1,12 @@ +

::if search::Search Results for '::search::'::else::All Projects::end:::

+ +
+
    +::foreach projects:: +
  • + ::name:: +
    ::description::
    +
  • +::end:: +
+
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/project.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/project.mtt new file mode 100644 index 0000000000000000000000000000000000000000..71a230c7c64c4f2631f55c19a47534970d054bd8 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/project.mtt @@ -0,0 +1,27 @@ +

::(p.name)::

+ +
+
::(p.description)::
+ ::if (tags.length != 0)::
Tags
::foreach tags::::tag::::end::
::end:: + +
Version
::(version.name)::
+ +
License
::(p.license)::
+ ::if (version.documentation)::::end:: + +
+ +

History

+ +
+
    + ::foreach versions:: +
  • +
    ::date::
    +
    ::name::
    + +
    ::comments::
    +
  • + ::end:: +
+
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/tag.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/tag.mtt new file mode 100644 index 0000000000000000000000000000000000000000..476c0bd270f8b6dd973b4cbd9b4ce13b616e534c --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/tag.mtt @@ -0,0 +1,16 @@ +

Tag ::tag::

+ +

+ Here's the list of projects using this tag : +

+ +
+
    +::foreach tprojects:: +
  • + ::name:: +
    ::description::
    +
  • +::end:: +
+
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/haxelib/tmpl/user.mtt b/extra/haxelib_src/src/tools/haxelib/tmpl/user.mtt new file mode 100644 index 0000000000000000000000000000000000000000..fe0cc64070b8411cac05d76e887e37ad983ebf30 --- /dev/null +++ b/extra/haxelib_src/src/tools/haxelib/tmpl/user.mtt @@ -0,0 +1,16 @@ +

::(u.name)::

+ +
+
Name
::(u.fullname)::
+ +
+ +

Projects

+ +
+
    +::foreach uprojects:: +
  • ::name::
  • +::end:: +
+
\ No newline at end of file diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/.htaccess b/extra/haxelib_src/src/tools/legacyhaxelib/.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..d92d589eafbeb2f910e88cc761d78a0e78231d70 --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/.htaccess @@ -0,0 +1,10 @@ +# Set index.n to come before index.php + +DirectoryIndex index.n + +# Enable rewrite + +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^(.*)$ index.n/$1 \ No newline at end of file diff --git a/std/tools/haxelib/Data.hx b/extra/haxelib_src/src/tools/legacyhaxelib/Data.hx similarity index 51% rename from std/tools/haxelib/Data.hx rename to extra/haxelib_src/src/tools/legacyhaxelib/Data.hx index bd41b930bf78e1e0abede9e799bc3f04af7178f4..093ef0cccb3bf69ddd2a3aed85ecf5bcebbab974 100644 --- a/std/tools/haxelib/Data.hx +++ b/extra/haxelib_src/src/tools/legacyhaxelib/Data.hx @@ -19,11 +19,11 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -package tools.haxelib; +package tools.legacyhaxelib; import haxe.zip.Reader; import haxe.zip.Entry; -import haxe.Json; -using StringTools; + +import haxe.xml.Check; typedef UserInfos = { var name : String; @@ -49,7 +49,7 @@ typedef ProjectInfos = { var tags : List; } -typedef Infos = { +typedef XmlInfos = { var project : String; var website : String; var desc : String; @@ -63,12 +63,32 @@ typedef Infos = { class Data { - public static var JSON = "haxelib.json"; + public static var XML = "haxelib.xml"; public static var DOCXML = "haxedoc.xml"; - public static var REPOSITORY = "files/3.0"; + public static var REPOSITORY = "files"; public static var alphanum = ~/^[A-Za-z0-9_.-]+$/; static var LICENSES = ["GPL","LGPL","BSD","Public","MIT"]; - static var RESERVED_NAMES = ["haxe","all"]; + + static function requiredAttribute( x : Xml, name ) { + var v = x.get(name); + if( v == null ) + throw "Missing required attribute '"+name+"' in node "+x.nodeName; + return v; + } + + static function requiredNode( x : Xml, name ) { + var v = x.elementsNamed(name).next(); + if( v == null ) + throw "Missing required node '"+name+"' in node "+x.nodeName; + return v; + } + + static function requiredText( x : Xml ) { + var v = x.firstChild(); + if( v == null || (v.nodeType != Xml.PCData && v.nodeType != Xml.CData) ) + throw "Missing required text in node "+x.nodeName; + return v.nodeValue; + } public static function safe( name : String ) { if( !alphanum.match(name) ) @@ -84,15 +104,6 @@ class Data { return safe(lib)+"-"+safe(ver)+".zip"; } - public static function locateBasePath( zip : List ) { - for( f in zip ) { - if( StringTools.endsWith(f.fileName,JSON) ) { - return f.fileName.substr(0,f.fileName.length - JSON.length); - } - } - throw "No "+JSON+" found"; - } - public static function readDoc( zip : List ) : String { for( f in zip ) if( StringTools.endsWith(f.fileName,DOCXML) ) @@ -100,91 +111,62 @@ class Data { return null; } - public static function readInfos( zip : List, check : Bool ) : Infos { - var infodata = null; + public static function readInfos( zip : List, check : Bool ) : XmlInfos { + var xmldata = null; for( f in zip ) - if( StringTools.endsWith(f.fileName,JSON) ) { - infodata = Reader.unzip(f).toString(); + if( StringTools.endsWith(f.fileName,XML) ) { + xmldata = Reader.unzip(f).toString(); break; } - if( infodata == null ) - throw JSON + " not found in package"; - - return readData(infodata,check); + if( xmldata == null ) + throw XML+" not found in package"; + return readData(xmldata,check); } - static function doCheck( doc : Dynamic ) { - var libName = doc.name.toLowerCase(); - if ( Lambda.indexOf(RESERVED_NAMES, libName) > -1 ) - throw 'Library name "${doc.name}" is reserved. Please choose another name'; - if ( libName.endsWith(".zip") ) - throw 'Library name cannot end in ".zip". Please choose another name'; - if ( libName.endsWith(".hxml") ) - throw 'Library name cannot end in ".hxml". Please choose another name'; - if( Lambda.indexOf(LICENSES, doc.license) == -1 ) - throw "License must be one of the following: " + LICENSES; - switch Type.typeof(doc.contributors) { - case TNull: throw "At least one contributor must be included"; - //case TClass(String): doc.contributors = [doc.contributors]; - case TClass(Array): - default: throw 'invalid type for contributors'; - } - switch Type.typeof(doc.version) { - case TClass(String): - SemVer.ofString(doc.version); - default: throw 'version must be defined as string'; - } - switch Type.typeof(doc.tags) { - case TClass(Array), TNull: - default: throw 'tags must be defined as array'; - } - switch Type.typeof(doc.dependencies) { - case TObject, TNull: - default: throw 'dependencies must be defined as object'; - } - switch Type.typeof(doc.releasenote) { - case TClass(String): - case TNull: throw 'no releasenote specified'; - default: throw 'releasenote should be string'; - } + static function doCheck( doc : Xml ) { + var sname = Att("name",FReg(alphanum)); + var schema = RNode( + "project", + [ sname, Att("url"), Att("license",FEnum(LICENSES)) ], + RList([ + RMulti( RNode("user",[sname]), true ), + RMulti( RNode("tag",[Att("v",FReg(alphanum))]) ), + RNode("description",[],RData()), + RNode("version",[sname],RData()), + RMulti( RNode("depends",[sname,Att("version",FReg(alphanum),"")]) ), + ]) + ); + haxe.xml.Check.checkDocument(doc,schema); } - public static function readData( jsondata: String, check : Bool ) : Infos { - var doc = try Json.parse(jsondata) catch( e : Dynamic ) throw "Error in JSON data : " + e; + public static function readData( xmldata : String, check : Bool ) : XmlInfos { + var doc = Xml.parse(xmldata); if( check ) doCheck(doc); - var project:String = doc.name; + var p = new haxe.xml.Fast(doc).node.project; + var project = p.att.name; if( project.length < 3 ) throw "Project name must contain at least 3 characters"; var tags = new List(); - if( doc.tags != null) { - var tagsArray:Array = doc.tags; - for( t in tagsArray ) - tags.add(t); - } + for( t in p.nodes.tag ) + tags.add(t.att.v.toLowerCase()); var devs = new List(); - var developers:Array = doc.contributors; - - for( d in developers ) - devs.add(d); + for( d in p.nodes.user ) + devs.add(d.att.name); var deps = new List(); - if( doc.dependencies != null ) { - for( d in Reflect.fields(doc.dependencies) ) { - deps.add({ project: d, version: Std.string(Reflect.field(doc.dependencies, d)) }); - } - } - + for( d in p.nodes.depends ) + deps.add({ project : d.att.name, version : if( d.has.version ) d.att.version else "" }); return { project : project, - website : doc.url, - desc : doc.description, - version : doc.version, - versionComments : doc.releasenote, - license : doc.license, + website : p.att.url, + desc : p.node.description.innerData, + version : p.node.version.att.name, + versionComments : p.node.version.innerData, + license : p.att.license, tags : tags, developers : devs, - dependencies : deps - }; + dependencies : deps, + } } -} \ No newline at end of file +} diff --git a/std/tools/haxelib/Main.hx b/extra/haxelib_src/src/tools/legacyhaxelib/Main.hx similarity index 60% rename from std/tools/haxelib/Main.hx rename to extra/haxelib_src/src/tools/legacyhaxelib/Main.hx index 1b54d46f46a1b7b7641ff700974a8760e8623d09..bdba8e1a4978a6cc2b35c52e742c705a31fda5db 100644 --- a/std/tools/haxelib/Main.hx +++ b/extra/haxelib_src/src/tools/legacyhaxelib/Main.hx @@ -19,18 +19,8 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -package tools.haxelib; - -import haxe.crypto.Md5; -import haxe.*; -import haxe.io.Path; +package tools.legacyhaxelib; import haxe.zip.Reader; -import tools.haxelib.Data; -import sys.FileSystem; -import sys.io.*; -import haxe.ds.Option; - -using StringTools; enum Answer { Yes; @@ -38,7 +28,7 @@ enum Answer { Always; } -class SiteProxy extends haxe.remoting.Proxy { +class SiteProxy extends haxe.remoting.Proxy { } class Progress extends haxe.io.Output { @@ -51,7 +41,7 @@ class Progress extends haxe.io.Output { public function new(o) { this.o = o; cur = 0; - start = Timer.stamp(); + start = haxe.Timer.stamp(); } function bytes(n) { @@ -76,7 +66,7 @@ class Progress extends haxe.io.Output { public override function close() { super.close(); o.close(); - var time = Timer.stamp() - start; + var time = haxe.Timer.stamp() - start; var speed = (cur / time) / 1024; time = Std.int(time * 10) / 10; speed = Std.int(speed * 10) / 10; @@ -122,14 +112,13 @@ class ProgressIn extends haxe.io.Input { class Main { - static var VERSION = SemVer.ofString('3.0.0'); + static var VERSION = 104; static var REPNAME = "lib"; static var SERVER = { host : "lib.haxe.org", port : 80, dir : "", - url : "index.n", - apiVersion : VERSION.major+"."+VERSION.minor, + url : "index.n" }; var argcur : Int; @@ -141,35 +130,31 @@ class Main { function new() { args = Sys.args(); commands = new List(); - addCommand("install", install, "install a given library, or all libraries from a hxml file"); - addCommand("list", list, "list all installed libraries", false); - addCommand("upgrade", upgrade, "upgrade all installed libraries"); - addCommand("update", update, "update a single library"); - addCommand("selfupdate", updateSelf, "update haxelib itself"); - addCommand("remove", remove, "remove a given library/version", false); - addCommand("set", set, "set the current version for a library", false); - addCommand("search", search, "list libraries matching a word"); - addCommand("info", info, "list informations on a given library"); - addCommand("user", user, "list informations on a given user"); - addCommand("register", register, "register a new user"); - addCommand("submit", submit, "submit or update a library package"); - addCommand("setup", setup, "set the haxelib repository path", false); - addCommand("convertxml", convertXml, "convert haxelib.xml file to haxelib.json"); - addCommand("config", config, "print the repository path", false); - addCommand("path", path, "give paths to libraries", false); - addCommand("run", run, "run the specified library with parameters", false); - addCommand("local", local, "install the specified package locally", false); - addCommand("dev", dev, "set the development directory for a given library", false); + addCommand("install",install,"install a given library"); + addCommand("list",list,"list all installed libraries",false); + addCommand("upgrade",upgrade,"upgrade all installed libraries"); + addCommand("update",update,"update a single library"); + addCommand("remove",remove,"remove a given library/version",false); + addCommand("set",set,"set the current version for a library",false); + addCommand("search",search,"list libraries matching a word"); + addCommand("info",info,"list informations on a given library"); + addCommand("user",user,"list informations on a given user"); + addCommand("register",register,"register a new user"); + addCommand("submit",submit,"submit or update a library package"); + addCommand("setup",setup,"set the haxelib repository path",false); + addCommand("config",config,"print the repository path",false); + addCommand("path",path,"give paths to libraries",false); + addCommand("run",run,"run the specified library with parameters",false); + addCommand("local",local,"install the specified package locally",false); + addCommand("dev",dev,"set the development directory for a given library",false); addCommand("git", git, "uses git repository as library"); addCommand("proxy", proxy, "setup the Http proxy"); initSite(); } - - function initSite() { - siteUrl = "http://" + SERVER.host + ":" + SERVER.port + "/" + SERVER.dir; - site = new SiteProxy(haxe.remoting.HttpConnection.urlConnect(siteUrl + "api/" + SERVER.apiVersion + "/" + SERVER.url).api); + siteUrl = "http://"+SERVER.host+":"+SERVER.port+"/"+SERVER.dir+'/'; + site = new SiteProxy(haxe.remoting.HttpConnection.urlConnect(siteUrl+SERVER.url).api); } function param( name, ?passwd ) { @@ -178,11 +163,9 @@ class Main { Sys.print(name+" : "); if( passwd ) { var s = new StringBuf(); - do switch Sys.getChar(false) { - case 10, 13: break; - case c: s.addChar(c); - } - while (true); + var c; + while( (c = Sys.getChar(false)) != 13 ) + s.addChar(c); print(""); return s.toString(); } @@ -212,7 +195,9 @@ class Main { } function usage() { - print("Haxe Library Manager " + VERSION + " - (c)2006-2013 Haxe Foundation"); + var vmin = Std.string(VERSION % 100); + var ver = Std.int(VERSION/100) + "." + if( vmin.length == 1 ) "0"+vmin else vmin; + print("Haxe Library Manager "+ver+" - (c)2006-2012 Haxe Foundation"); print(" Usage : haxelib [command] [options]"); print(" Commands :"); for( c in commands ) @@ -260,7 +245,7 @@ class Main { print("Host "+SERVER.host+" was not found"); print("Please ensure that your internet connection is on"); print("If you don't have an internet connection or if you are behing a proxy"); - print("please download manually the file from http://lib.haxe.org/files/3.0/"); + print("please download manually the file from http://lib.haxe.org/files"); print("and run 'haxelib local ' to install the Library."); print("You can also setup the proxy with 'haxelib proxy'."); Sys.exit(1); @@ -332,14 +317,14 @@ class Main { var pass2 = param("Confirm",true); if( pass != pass2 ) throw "Password does not match"; - pass = Md5.encode(pass); + pass = haxe.crypto.Md5.encode(pass); site.register(name,pass,email,fullname); return pass; } function submit() { var file = param("Package"); - var data = File.getBytes(file); + var data = sys.io.File.getBytes(file); var zip = Reader.readZip(new haxe.io.BytesInput(data)); var infos = Data.readInfos(zip,true); var user = infos.developers.first(); @@ -351,7 +336,7 @@ class Main { } else { if( infos.developers.length > 1 ) user = param("User"); - password = Md5.encode(param("Password",true)); + password = haxe.crypto.Md5.encode(param("Password",true)); if( !site.checkPassword(user,password) ) throw "Invalid password for "+user; } @@ -373,18 +358,17 @@ class Main { } // check if this version already exists - var sinfos = try site.infos(infos.project) catch( _ : Dynamic ) null; if( sinfos != null ) for( v in sinfos.versions ) - if( v.name == infos.version.toString() && ask("You're about to overwrite existing version '"+v.name+"', please confirm") == No ) + if( v.name == infos.version && ask("You're about to overwrite existing version '"+v.name+"', please confirm") == No ) throw "Aborted"; // query a submit id that will identify the file var id = site.getSubmitId(); // directly send the file data over Http - var h = new Http("http://"+SERVER.host+":"+SERVER.port+"/"+SERVER.url); + var h = new haxe.Http("http://"+SERVER.host+":"+SERVER.port+"/"+SERVER.url); h.onError = function(e) { throw e; }; h.onData = print; h.fileTransfert("file",id,new ProgressIn(new haxe.io.BytesInput(data),data.length),data.length); @@ -400,41 +384,17 @@ class Main { } function install() { - var prj = param("Library name or hxml file:"); - - // No library given, install libraries listed in *.hxml in given directory - if( prj == "all") - { - installFromAllHxml(); - return; - } - + var prj = param("Library name"); if( sys.FileSystem.exists(prj) && !sys.FileSystem.isDirectory(prj) ) { - // *.hxml provided, install all libraries/versions in this hxml file - if( prj.endsWith(".hxml") ) - { - installFromHxml(prj); - return; - } - // *.zip provided, install zip as haxe library - if( prj.endsWith(".zip") ) - { - doInstallFile(prj,true,true); - return; - } + if( !StringTools.endsWith(prj,".zip") ) + throw "Local file to install must be a zip"; + doInstallFile(prj,true,true); + return; } - - // Name provided that wasn't a local hxml or zip, so try to install it from server var inf = site.infos(prj); - var reqversion = paramOpt(); - var version = getVersion(inf, reqversion); - doInstall(inf.name,version,version == inf.curversion); - } - - function getVersion( inf:ProjectInfos, ?reqversion:String ) - { if( inf.curversion == null ) - throw "The library "+inf.name+" has not yet released a version"; + throw "This library has not yet released a version"; + var reqversion = paramOpt(); var version = if( reqversion != null ) reqversion else inf.curversion; var found = false; for( v in inf.versions ) @@ -443,92 +403,15 @@ class Main { break; } if( !found ) - throw "No such version "+version+" for library "+inf.name; - - return version; - } - - function installFromHxml( path ) - { - var hxml = sys.io.File.getContent(path); - var lines = hxml.split("\n"); - - var libsToInstall = new Map(); - for (l in lines) - { - l = l.trim(); - if (l.startsWith("-lib")) - { - var key = l.substr(5); - var parts = key.split(":"); - var libName = parts[0].trim(); - var libVersion = if (parts.length > 1) parts[1].trim() else null; - - if (libsToInstall.exists(key) == false) - { - libsToInstall.set(key, { name:libName, version:libVersion }); - } - } - } - installMany(libsToInstall); - } - - function installFromAllHxml() - { - var hxmlFiles = sys.FileSystem.readDirectory(Sys.getCwd()).filter(function (f) return f.endsWith(".hxml")); - if (hxmlFiles.length > 0) - { - for (file in hxmlFiles) - { - if (file.endsWith(".hxml")) - { - print('Installing all libraries from $file:'); - installFromHxml(Sys.getCwd()+file); - } - } - } - else - { - print ("No hxml files found in the current directory."); - } - } - - function installMany( libs:Iterable<{name:String,version:String}>, ?setCurrent=true ) - { - if (Lambda.count(libs) == 0) return; - - // Check the version numbers are all good - // TODO: can we collapse this into a single API call? It's getting too slow otherwise. - print("Loading info about the required libraries"); - for (l in libs) - { - var inf = site.infos(l.name); - l.version = getVersion(inf, l.version); - } - - // Print a list with all the info - print("Haxelib is going to install these libraries:"); - for (l in libs) - { - var vString = (l.version == null) ? "" : " - " + l.version; - print(" " + l.name + vString); - } - - // Install if they confirm - if (ask("Continue?") != No) - { - for (l in libs) - { - doInstall(l.name, l.version, setCurrent); - } - } + throw "No such version "+version; + doInstall(inf.name,version,version == inf.curversion); } function doInstall( project, version, setcurrent ) { var rep = getRepository(); // check if exists already - if( FileSystem.exists(rep+Data.safe(project)+"/"+Data.safe(version)) ) { + if( sys.FileSystem.exists(rep+Data.safe(project)+"/"+Data.safe(version)) ) { print("You already have "+project+" version "+version+" installed"); setCurrent(project,version,true); return; @@ -537,42 +420,52 @@ class Main { // download to temporary file var filename = Data.fileName(project,version); var filepath = rep+filename; - var out = File.write(filepath,true); + var out = sys.io.File.write(filepath,true); var progress = new Progress(out); - var h = new Http(siteUrl+Data.REPOSITORY+"/"+filename); + var h = new haxe.Http(siteUrl + Data.REPOSITORY + "/" + filename); h.onError = function(e) { progress.close(); - FileSystem.deleteFile(filepath); + sys.FileSystem.deleteFile(filepath); throw e; }; print("Downloading "+filename+"..."); h.customRequest(false,progress); - doInstallFile(filepath, setcurrent); - site.postInstall(project, version); + doInstallFile(filepath,setcurrent); + site.postInstall(project,version); } function doInstallFile(filepath,setcurrent,?nodelete) { + // read zip content - var f = File.read(filepath,true); + var f = sys.io.File.read(filepath,true); var zip = Reader.readZip(f); f.close(); var infos = Data.readInfos(zip,false); + // create directories var pdir = getRepository() + Data.safe(infos.project); safeDir(pdir); pdir += "/"; - var target = pdir + Data.safe(infos.version.toString()); + var target = pdir + Data.safe(infos.version); safeDir(target); target += "/"; - // locate haxelib.json base path - var basepath = Data.locateBasePath(zip); + // locate haxelib.xml base path + var basepath = null; + for( f in zip ) { + if( StringTools.endsWith(f.fileName,Data.XML) ) { + basepath = f.fileName.substr(0,f.fileName.length - Data.XML.length); + break; + } + } + if( basepath == null ) + throw "No "+Data.XML+" found"; // unzip content for( zipfile in zip ) { var n = zipfile.fileName; - if( n.startsWith(basepath) ) { + if( StringTools.startsWith(n,basepath) ) { // remove basepath n = n.substr(basepath.length,n.length-basepath.length); if( n.charAt(0) == "/" || n.charAt(0) == "\\" || n.split("..").length > 1 ) @@ -592,28 +485,23 @@ class Main { path += file; print(" Install "+path); var data = Reader.unzip(zipfile); - File.saveBytes(target+path,data); + sys.io.File.saveBytes(target+path,data); } } // set current version - if( setcurrent || !FileSystem.exists(pdir+".current") ) { - File.saveContent(pdir + ".current", infos.version.toString()); + if( setcurrent || !sys.FileSystem.exists(pdir+".current") ) { + sys.io.File.saveContent(pdir+".current",infos.version); print(" Current version is now "+infos.version); } // end if( !nodelete ) - FileSystem.deleteFile(filepath); + sys.FileSystem.deleteFile(filepath); print("Done"); // process dependencies - doInstallDependencies(infos.dependencies); - } - - function doInstallDependencies( dependencies:List<{ project: String, version : String }> ) - { - for( d in dependencies ) { + for( d in infos.dependencies ) { print("Installing dependency "+d.project+" "+d.version); if( d.version == "" ) d.version = site.infos(d.project).curversion; @@ -622,12 +510,13 @@ class Main { } function safeDir( dir ) { - if( FileSystem.exists(dir) ) { - if( !FileSystem.isDirectory(dir) ) + if( sys.FileSystem.exists(dir) ) { + if( !sys.FileSystem.isDirectory(dir) ) throw ("A file is preventing "+dir+" to be created"); + return false; } try { - FileSystem.createDirectory(dir); + sys.FileSystem.createDirectory(dir); } catch( e : Dynamic ) { throw "You don't have enough user rights to create the directory "+dir; } @@ -636,13 +525,13 @@ class Main { function safeDelete( file ) { try { - FileSystem.deleteFile(file); + sys.FileSystem.deleteFile(file); return true; } catch (e:Dynamic) { if( Sys.systemName() == "Windows") { try { Sys.command("attrib -R \"" +file+ "\""); - FileSystem.deleteFile(file); + sys.FileSystem.deleteFile(file); return true; } catch (e:Dynamic) { } @@ -666,9 +555,9 @@ class Main { config_file = Sys.getEnv("HOME"); config_file += "/.haxelib"; var rep = try - File.getContent(config_file) + sys.io.File.getContent(config_file) catch( e : Dynamic ) try - File.getContent("/etc/.haxelib") + sys.io.File.getContent("/etc/.haxelib") catch( e : Dynamic ) { if( setup ) { (win ? haxepath : "/usr/lib/haxe/")+REPNAME; @@ -679,14 +568,14 @@ class Main { var rep = haxepath+REPNAME; try { safeDir(rep); - } catch( e : String ) { - throw "Error accessing Haxelib repository: $e"; + } catch( e : Dynamic ) { + throw "The directory defined by HAXEPATH does not exist, please run haxesetup.exe again"; } return rep+"\\"; } else - throw "This is the first time you are runing haxelib. Please run `haxelib setup` first"; + throw "This is the first time you are runing haxelib. Please run haxelib setup first"; } - rep = rep.trim(); + rep = StringTools.trim(rep); if( setup ) { if( args.length <= argcur ) { print("Please enter haxelib repository path with write access"); @@ -695,22 +584,19 @@ class Main { var line = param("Path"); if( line != "" ) rep = line; - if( !FileSystem.exists(rep) ) { + if( !sys.FileSystem.exists(rep) ) { try { - FileSystem.createDirectory(rep); + sys.FileSystem.createDirectory(rep); } catch( e : Dynamic ) { print("Failed to create directory '"+rep+"' ("+Std.string(e)+"), maybe you need appropriate user rights"); print("Check also that the parent directory exists"); Sys.exit(1); } } - rep = try FileSystem.fullPath(rep) catch( e : Dynamic ) rep; - File.saveContent(config_file, rep); - } else if( !FileSystem.exists(rep) ) { - throw "haxelib Repository "+rep+" does not exists. Please run `haxelib setup` again"; - } else if ( !FileSystem.isDirectory(rep) ) { - throw "haxelib Repository "+rep+" exists, but was a file, not a directory. Please remove it and run `haxelib setup` again."; - } + rep = try sys.FileSystem.fullPath(rep) catch( e : Dynamic ) rep; + sys.io.File.saveContent(config_file, rep); + } else if( !sys.FileSystem.exists(rep) ) + throw "haxelib Repository "+rep+" does not exists. Please run haxelib setup again"; return rep+"/"; } @@ -724,26 +610,22 @@ class Main { } function getCurrent( dir ) { - return (FileSystem.exists(dir+"/.dev")) ? "dev" : File.getContent(dir + "/.current").trim(); + return StringTools.trim(sys.io.File.getContent(dir + "/.current")); } function getDev( dir ) { - return File.getContent(dir + "/.dev").trim(); + return StringTools.trim(sys.io.File.getContent(dir + "/.dev")); } function list() { var rep = getRepository(); - var folders = FileSystem.readDirectory(rep); - var filter = paramOpt(); - if ( filter != null ) - folders = folders.filter( function (f) return f.toLowerCase().indexOf(filter.toLowerCase()) > -1 ); - for( p in folders ) { + for( p in sys.FileSystem.readDirectory(rep) ) { if( p.charAt(0) == "." ) continue; var versions = new Array(); var current = getCurrent(rep + p); - var dev = try File.getContent(rep+p+"/.dev").trim() catch( e : Dynamic ) null; - for( v in FileSystem.readDirectory(rep+p) ) { + var dev = try StringTools.trim(sys.io.File.getContent(rep+p+"/.dev")) catch( e : Dynamic ) null; + for( v in sys.FileSystem.readDirectory(rep+p) ) { if( v.charAt(0) == "." ) continue; v = Data.unsafe(v); @@ -759,8 +641,8 @@ class Main { function upgrade() { var state = { rep : getRepository(), prompt : true, updated : false }; - for( p in FileSystem.readDirectory(state.rep) ) { - if( p.charAt(0) == "." || !FileSystem.isDirectory(state.rep+"/"+p) ) + for( p in sys.FileSystem.readDirectory(state.rep) ) { + if( p.charAt(0) == "." || !sys.FileSystem.isDirectory(state.rep+"/"+p) ) continue; var p = Data.unsafe(p); print("Checking " + p); @@ -774,16 +656,17 @@ class Main { function doUpdate( p : String, state ) { var rep = state.rep; - if( FileSystem.exists(rep + "/" + p + "/git") && FileSystem.isDirectory(rep + "/" + p + "/git") ) { + if( sys.FileSystem.exists(rep + "/" + p + "/git") && sys.FileSystem.isDirectory(rep + "/" + p + "/git") ) { checkGit(); var oldCwd = Sys.getCwd(); Sys.setCwd(rep + "/" + p + "/git"); Sys.command("git pull"); + // TODO: update haxelib.xml version? Sys.setCwd(oldCwd); state.updated = true; } else { var inf = try site.infos(p) catch( e : Dynamic ) { Sys.println(e); return; }; - if( !FileSystem.exists(rep+Data.safe(p)+"/"+Data.safe(inf.curversion)) ) { + if( !sys.FileSystem.exists(rep+Data.safe(p)+"/"+Data.safe(inf.curversion)) ) { if( state.prompt ) switch ask("Upgrade "+p+" to "+inf.curversion) { case Yes: @@ -797,82 +680,24 @@ class Main { setCurrent(p, inf.curversion, true); } } - function updateByName(prj:String) { + + function update() { + var prj = param("Library"); var state = { rep : getRepository(), prompt : false, updated : false }; doUpdate(prj,state); - return state.updated; - } - function update() { - var prj = param('Library'); - if (!updateByName(prj)) + if( !state.updated ) print(prj + " is up to date"); - } - - function updateSelf() { - function tryBuild() { - var p = new Process('haxe', ['-neko', 'test.n', '-lib', 'haxelib_client', '-main', 'tools.haxelib.Main', '--no-output']); - return - if (p.exitCode() == 0) None; - else Some(p.stderr.readAll().toString()); - } - if (!updateByName('haxelib_client')) - print("haxelib is up to date"); - switch tryBuild() { - case None: - var win = Sys.systemName() == "Windows"; - var haxepath = - if (win) Sys.getEnv("HAXEPATH"); - else new Path(new Process('which', ['haxelib']).stdout.readAll().toString()).dir + '/'; - - if (haxepath == null) - throw (win ? 'HAXEPATH environment variable not defined' : 'unable to locate haxelib through `which haxelib`'); - else - haxepath += - switch (haxepath.charAt(haxepath.length - 1)) { - case '/', '\\': ''; - default: '/'; - } - - if (win) { - File.saveContent('update.hxml', '-lib haxelib_client\n--run tools.haxelib.Rebuild'); - Sys.println('Please run haxe update.hxml'); - } - else { - var p = new Process('haxelib', ['path', 'haxelib_client']); - if (p.exitCode() == 0) { - var args = []; - for (arg in p.stdout.readAll().toString().split('\n')) { - arg = arg.trim(); - if (arg.charAt(0) == '-') - args.push(arg); - else if (arg.length > 0) - args.push('-cp "$arg"'); - }; - - var file = haxepath+'haxelib'; - try File.saveContent( - file, - '#!/bin/sh\nhaxe '+args.join(' ')+' --run tools.haxelib.Main $@' - ) - catch (e:Dynamic) - throw 'Error writing file $file. Please ensure you have write permissions. \n ' + Std.string(e); - } - else throw p.stdout.readAll(); - } - case Some(error): - throw 'Error compiling haxelib client: $error'; - } } function deleteRec(dir) { - for( p in FileSystem.readDirectory(dir) ) { + for( p in sys.FileSystem.readDirectory(dir) ) { var path = dir+"/"+p; - if( FileSystem.isDirectory(path) ) + if( sys.FileSystem.isDirectory(path) ) deleteRec(path); else safeDelete(path); } - FileSystem.deleteDirectory(dir); + sys.FileSystem.deleteDirectory(dir); } function remove() { @@ -881,7 +706,7 @@ class Main { var rep = getRepository(); var pdir = rep + Data.safe(prj); if( version == null ) { - if( !FileSystem.exists(pdir) ) + if( !sys.FileSystem.exists(pdir) ) throw "Library "+prj+" is not installed"; deleteRec(pdir); print("Library "+prj+" removed"); @@ -889,7 +714,7 @@ class Main { } var vdir = pdir + "/" + Data.safe(version); - if( !FileSystem.exists(vdir) ) + if( !sys.FileSystem.exists(vdir) ) throw "Library "+prj+" does not have version "+version+" installed"; var cur = getCurrent(pdir); @@ -908,25 +733,25 @@ class Main { function setCurrent( prj : String, version : String, doAsk : Bool ) { var pdir = getRepository() + Data.safe(prj); var vdir = pdir + "/" + Data.safe(version); - if( !FileSystem.exists(vdir) ) + if( !sys.FileSystem.exists(vdir) ) throw "Library "+prj+" version "+version+" is not installed"; if( getCurrent(pdir) == version ) return; if( doAsk && ask("Set "+prj+" to version "+version) == No ) return; - File.saveContent(pdir+"/.current",version); + sys.io.File.saveContent(pdir+"/.current",version); print("Library "+prj+" current version is now "+version); } function checkRec( prj : String, version : String, l : List<{ project : String, version : String }> ) { var pdir = getRepository() + Data.safe(prj); - if( !FileSystem.exists(pdir) ) + if( !sys.FileSystem.exists(pdir) ) throw "Library "+prj+" is not installed : run 'haxelib install "+prj+"'"; var version = if( version != null ) version else getCurrent(pdir); var vdir = pdir + "/" + Data.safe(version); - if( vdir.endsWith("dev") ) + if( StringTools.endsWith(vdir, "dev") ) vdir = getDev(pdir); - if( !FileSystem.exists(vdir) ) + if( !sys.FileSystem.exists(vdir) ) throw "Library "+prj+" version "+version+" is not installed"; for( p in l ) if( p.project == prj ) { @@ -935,10 +760,8 @@ class Main { throw "Library "+prj+" has two version included "+version+" and "+p.version; } l.add({ project : prj, version : version }); - var json = try File.getContent(vdir+"/"+Data.JSON) catch( e : Dynamic ) null; - if( json == null ) - return; // ignore missing haxelib.json, assume no dependencies - var inf = Data.readData(json,false); + var xml = sys.io.File.getContent(vdir+"/haxelib.xml"); + var inf = Data.readData(xml,false); for( d in inf.dependencies ) checkRec(d.project,if( d.version == "" ) null else d.version,l); } @@ -961,17 +784,17 @@ class Main { } catch( e : Dynamic ) { } var ndir = dir + "ndll"; - if( FileSystem.exists(ndir) ) { + if( sys.FileSystem.exists(ndir) ) { var sysdir = ndir+"/"+Sys.systemName(); var is64 = neko.Lib.load("std", "sys_is64", 0)(); if( is64 ) sysdir += "64"; - if( !FileSystem.exists(sysdir) ) + if( !sys.FileSystem.exists(sysdir) ) throw "Library "+d.project+" version "+d.version+" does not have a neko dll for your system"; Sys.println("-L "+pdir+"ndll/"); } try { - var f = File.getContent(dir + "extraParams.hxml"); - Sys.println(f.trim()); + var f = sys.io.File.getContent(dir + "extraParams.hxml"); + Sys.println(StringTools.trim(f)); } catch( e : Dynamic ) { } Sys.println(dir); @@ -984,39 +807,23 @@ class Main { var project = param("Library"); var dir = paramOpt(); var proj = rep + Data.safe(project); - if( !FileSystem.exists(proj) ) { - FileSystem.createDirectory(proj); - File.saveContent(proj + "/.current", "dev"); + if( !sys.FileSystem.exists(proj) ) { + sys.FileSystem.createDirectory(proj); + sys.io.File.saveContent(proj + "/.current", "dev"); } var devfile = proj+"/.dev"; if( dir == null ) { - if( FileSystem.exists(devfile) ) - FileSystem.deleteFile(devfile); + if( sys.FileSystem.exists(devfile) ) + sys.FileSystem.deleteFile(devfile); print("Development directory disabled"); } else { - dir = try FileSystem.fullPath(dir)+"/" catch( e : Dynamic ) rep; try { - File.saveContent(devfile, dir); + sys.io.File.saveContent(devfile, dir); print("Development directory set to "+dir); - - try { - // Check for haxelib.json, install dependencies - var haxelibJsonPath = dir + "haxelib.json"; - if (FileSystem.exists(haxelibJsonPath)) - { - var haxelibJson = File.getContent(haxelibJsonPath); - var infos = Data.readData(haxelibJson,true); - doInstallDependencies(infos.dependencies); - } - } - catch (e:Dynamic) { - print('Error installing dependencies for $project:\n $e'); - } } catch (e:Dynamic) { print("Could not write to " +proj + "/.dev"); } - } } @@ -1038,7 +845,7 @@ class Main { return; // look at a few default paths for( path in ["C:\\Program Files (x86)\\Git\\bin","C:\\Progra~1\\Git\\bin"] ) - if( FileSystem.exists(path) ) { + if( sys.FileSystem.exists(path) ) { Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" +path); if( gitExists() ) return; @@ -1051,7 +858,7 @@ class Main { var rep = getRepository(); var libPath = rep + Data.safe(libName) + "/git"; - if( FileSystem.exists(libPath) ) { + if( sys.FileSystem.exists(libPath) ) { var state = { rep : rep, prompt : false, updated : false }; doUpdate(libName,state); if( !state.updated ) @@ -1060,9 +867,17 @@ class Main { } var gitPath = param("Git path"); - var branch = paramOpt(); var subDir = paramOpt(); + var match = ~/@([0-9]+)/; + var rev = if (match.match(gitPath) && match.matchedRight() == "") + { + gitPath = match.matchedLeft(); + match.matched(1); + } + else + null; + print("Installing " +libName + " from " +gitPath); checkGit(); @@ -1071,11 +886,11 @@ class Main { return; } Sys.setCwd(libPath); - if (branch != null) { - var ret = command("git", ["checkout", branch]); + if (rev != null) { + var ret = command("git", ["checkout", rev]); if (ret.code != 0) { - print("Could not checkout branch, tag or path: " +ret.out); + print("Could not checkout revision: " +ret.out); // TODO: We might have to get rid of the cloned repository here return; } @@ -1083,34 +898,18 @@ class Main { var revision = command("git", ["rev-parse", "HEAD"]).out; var devPath = libPath + (subDir == null ? "" : "/" + subDir); - var haxelibJsonPath = devPath + "/haxelib.json"; - var haxelibJson:String; - if (FileSystem.exists(haxelibJsonPath)) - { - haxelibJson = File.getContent(haxelibJsonPath); - } - else + if (!sys.FileSystem.exists(devPath +"/haxelib.xml")) { - haxelibJson = '{ - "name": "$libName", - "url" : "$gitPath", - "license": "", - "tags": [], - "description": "", - "version": "0.0.0", - "releasenote": "Updated from git.", - "contributors": [], - "dependencies": {} -}'; - File.saveContent(haxelibJsonPath, haxelibJson); + var haxelib = "" + +"" + +"Updated from git." + +""; + sys.io.File.saveContent(devPath +"/haxelib.xml", haxelib); } - var infos = Data.readData(haxelibJson,true); - doInstallDependencies(infos.dependencies); - Sys.setCwd(libPath + "/../"); - File.saveContent(".current", "dev"); - File.saveContent(".dev", devPath); + sys.io.File.saveContent(".current", "dev"); + sys.io.File.saveContent(".dev", devPath); print("Done"); } @@ -1120,14 +919,14 @@ class Main { var temp = project.split(":"); project = temp[0]; var pdir = rep + Data.safe(project); - if( !FileSystem.exists(pdir) ) + if( !sys.FileSystem.exists(pdir) ) throw "Library "+project+" is not installed"; pdir += "/"; var version = temp[1] != null ? temp[1] : getCurrent(pdir); var dev = try getDev(pdir) catch ( e : Dynamic ) null; var vdir = dev!=null ? dev : pdir + Data.safe(version); var rdir = vdir + "/run.n"; - if( !FileSystem.exists(rdir) ) + if( !sys.FileSystem.exists(rdir) ) throw "Library "+project+" version "+version+" does not have a run script"; args.push(Sys.getCwd()); Sys.setCwd(vdir); @@ -1153,13 +952,13 @@ class Main { var code = p.exitCode(); return { code:code, out: code == 0 ? p.stdout.readAll().toString() : p.stderr.readAll().toString() }; } - + function proxy() { var rep = getRepository(); var host = param("Proxy host"); if( host == "" ) { - if( FileSystem.exists(rep + "/.proxy") ) { - FileSystem.deleteFile(rep + "/.proxy"); + if( sys.FileSystem.exists(rep + "/.proxy") ) { + sys.FileSystem.deleteFile(rep + "/.proxy"); print("Proxy disabled"); } else print("No proxy specified"); @@ -1173,113 +972,19 @@ class Main { port : port, auth : authName == "" ? null : { user : authName, pass : authPass }, }; - Http.PROXY = proxy; + haxe.Http.PROXY = proxy; print("Testing proxy..."); - try Http.requestUrl("http://www.google.com") catch( e : Dynamic ) { + try haxe.Http.requestUrl("http://www.google.com") catch( e : Dynamic ) { print("Proxy connection failed"); return; } - File.saveContent(rep + "/.proxy", haxe.Serializer.run(proxy)); + sys.io.File.saveContent(rep + "/.proxy", haxe.Serializer.run(proxy)); print("Proxy setup done"); } function loadProxy() { var rep = getRepository(); - try Http.PROXY = haxe.Unserializer.run(File.getContent(rep + "/.proxy")) catch( e : Dynamic ) { }; - } - - function convertXml() { - var cwd = Sys.getCwd(); - var xmlFile = cwd + "haxelib.xml"; - var jsonFile = cwd + "haxelib.json"; - - if (!FileSystem.exists(xmlFile)) - { - print('No `haxelib.xml` file was found in the current directory.'); - Sys.exit(0); - } - - var xmlString = File.getContent(xmlFile); - var json = convert(xmlString); - var jsonString = prettyPrint(json); - - File.saveContent(jsonFile, jsonString); - print('Saved to $jsonFile'); - } - - function convert(inXml:String) { - // Set up the default JSON structure - var json = { - "name": "", - "url" : "", - "license": "", - "tags": [], - "description": "", - "version": "0.0.1", - "releasenote": "", - "contributors": [], - "dependencies": {} - }; - - // Parse the XML and set the JSON - var xml = Xml.parse(inXml); - var project = xml.firstChild(); - json.name = project.get("name"); - json.license = project.get("license"); - json.url = project.get("url"); - for (node in project) - { - switch (node.nodeType) - { - case Xml.Element: - switch (node.nodeName) - { - case "tag": - json.tags.push(node.get("v")); - case "user": - json.contributors.push(node.get("name")); - case "version": - json.version = node.get("name"); - json.releasenote = node.firstChild().toString(); - case "description": - json.description = node.firstChild().toString(); - case "depends": - var name = node.get("name"); - var version = node.get("version"); - if (version == null) version = ""; - Reflect.setField(json.dependencies, name, version); - default: - } - default: - } - } - - return json; - } - - function prettyPrint(json:Dynamic, indent="") - { - var sb = new StringBuf(); - sb.add("{\n"); - - var firstRun = true; - for (f in Reflect.fields(json)) - { - if (!firstRun) sb.add(",\n"); - firstRun = false; - - var value = switch (f) { - case "dependencies": - var d = Reflect.field(json, f); - prettyPrint(d, indent + " "); - default: - Json.stringify(Reflect.field(json, f)); - } - sb.add(indent+' "$f": $value'); - } - - sb.add('\n$indent}'); - return sb.toString(); + try haxe.Http.PROXY = haxe.Unserializer.run(sys.io.File.getContent(rep + "/.proxy")) catch( e : Dynamic ) { }; } // ---------------------------------- diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/Site.hx b/extra/haxelib_src/src/tools/legacyhaxelib/Site.hx new file mode 100644 index 0000000000000000000000000000000000000000..b3f113a9d7f5265f489a58d8fa183cfa9a573f67 --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/Site.hx @@ -0,0 +1,266 @@ +/* + * Copyright (C)2005-2012 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 tools.legacyhaxelib; +#if haxelib_site +import tools.legacyhaxelib.SiteDb; +#end +import haxe.rtti.CType; + +class Site { + + static var db : sys.db.Connection; + + static var CWD = neko.Web.getCwd(); + static var DB_FILE = CWD+"haxelib.db"; + public static var TMP_DIR = CWD+"../tmp"; + public static var REP_DIR = CWD+"../"+Data.REPOSITORY; + + static function setup() { + SiteDb.create(db); + } + + static function initDatabase() { + db = neko.db.Sqlite.open(DB_FILE); + neko.db.Manager.cnx = db; + neko.db.Manager.initialize(); + } + + static function run() { + if( !sys.FileSystem.exists(TMP_DIR) ) + sys.FileSystem.createDirectory(TMP_DIR); + if( !sys.FileSystem.exists(REP_DIR) ) + sys.FileSystem.createDirectory(REP_DIR); + + var ctx = new haxe.remoting.Context(); + ctx.addObject("api",new SiteApi(db)); + if( haxe.remoting.HttpConnection.handleRequest(ctx) ) + return; + if( Sys.args()[0] == "setup" ) { + setup(); + neko.Lib.print("Setup done\n"); + return; + } + var file = null; + var sid = null; + var bytes = 0; + neko.Web.parseMultipart(function(p,filename) { + if( p == "file" ) { + sid = Std.parseInt(filename); + file = sys.io.File.write(TMP_DIR+"/"+sid+".tmp",true); + } else + throw p+" not accepted"; + },function(data,pos,len) { + bytes += len; + file.writeFullBytes(data,pos,len); + }); + if( file != null ) { + file.close(); + neko.Lib.print("File #"+sid+" accepted : "+bytes+" bytes written"); + return; + } + display(); + } + + static function display() { + var data = sys.io.File.getContent(CWD + "website.mtt"); + var page = new haxe.Template(data); + var ctx : Dynamic = {}; + var macros = { + download : function( res, p, v ) { + return "/"+Data.REPOSITORY+"/"+Data.fileName(res(p).name,res(v).name); + } + }; + if( fillContent(ctx) ) + neko.Lib.print( page.execute(ctx,macros) ); + } + + static function fillContent( ctx : Dynamic ) { + var uri = neko.Web.getURI().split("/"); + var error = function(msg) { ctx.error = StringTools.htmlEscape(msg); return true; } + if( uri[0] == "" ) + uri.shift(); + var domain = "http://" + neko.Web.getHostName(); + var act = uri.shift(); + if( act == "legacy" ) { + act = uri.shift(); + ctx.basehref = domain + "/legacy/"; + } + else + ctx.basehref = domain + "/"; + if( act == null || act == "" || act == "index.n" ) + act = "index"; + ctx.menuTags = Tag.manager.topTags(10); + switch( act ) { + case "p": + var name = uri.shift(); + var p = Project.manager.search({ name : name }).first(); + if( p == null ) + return error("Unknown project '"+name+"'"); + ctx.p = p; + ctx.owner = p.owner; + ctx.version = p.version; + ctx.versions = Version.manager.byProject(p); + var tags = Tag.manager.search({ project : p.id }); + if( !tags.isEmpty() ) ctx.tags = tags; + case "u": + var name = uri.shift(); + var u = User.manager.search({ name : name }).first(); + if( u == null ) + return error("Unknown user '"+name+"'"); + ctx.u = u; + ctx.uprojects = Developer.manager.search({ user : u.id }).map(function(d:Developer) { return d.project; }); + case "t": + var tag = uri.shift(); + ctx.tag = StringTools.htmlEscape(tag); + ctx.tprojects = Tag.manager.search({ tag : tag }).map(function(t) return t.project); + case "d": + var name = uri.shift(); + var p = Project.manager.search({ name : name }).first(); + if( p == null ) + return error("Unknown project '"+name+"'"); + var version = uri.shift(); + var v; + if( version == null ) { + v = p.version; + version = v.name; + } else { + v = Version.manager.search({ project : p.id, name : version }).first(); + if( v == null ) return error("Unknown version '"+version+"'"); + } + if( v.documentation == null ) + return error("Project "+p.name+" version "+version+" has no documentation"); + var root : TypeRoot = haxe.Unserializer.run(v.documentation); + var buf = new StringBuf(); + var html = new tools.haxedoc.HtmlPrinter("/d/"+p.name+"/"+version+"/","",""); + html.output = function(str) buf.add(str); + var path = uri.join(".").toLowerCase().split("."); + if( path.length == 1 && path[0] == "" ) + path = []; + if( path.length == 0 ) { + ctx.index = true; + html.process(TPackage("root","root",root)); + } else { + var cl = html.find(root,path,0); + if( cl == null ) { + // we most likely clicked on a class which is part of the haxe core documentation + neko.Web.redirect("http://haxe.org/api/"+path.join("/")); + return false; + } + html.process(cl); + } + ctx.p = p; + ctx.v = v; + ctx.content = buf.toString(); + case "index": + var vl = Version.manager.latest(10); + for( v in vl ) { + var p = v.project; // fetch + } + ctx.versions = vl; + case "all": + ctx.projects = Project.manager.allByName(); + case "search": + var v = neko.Web.getParams().get("v"); + var p = Project.manager.search({ name : v }).first(); + if( p != null ) { + neko.Web.redirect("/legacy/p/"+p.name); + return false; + } + if( Tag.manager.count({ tag : v }) > 0 ) { + neko.Web.redirect("/legacy/t/"+v); + return false; + } + ctx.projects = Project.manager.containing(v).map(function(p) return Project.manager.get(p.id)); + ctx.act_all = true; + ctx.search = StringTools.htmlEscape(v); + case "rss": + neko.Web.setHeader("Content-Type", "text/xml; charset=UTF-8"); + neko.Lib.println(''); + neko.Lib.print(buildRss().toString()); + return false; + default: + ctx.error = "Unknown action : "+act; + return true; + } + Reflect.setField(ctx,"act_"+act,true); + return true; + } + + static function buildRss() : Xml { + var createChild = function(root:Xml, name:String){ + var c = Xml.createElement(name); + root.addChild(c); + return c; + } + var createChildWithContent = function(root:Xml, name:String, content:String){ + var e = Xml.createElement(name); + var c = Xml.createPCData(if (content != null) content else ""); + e.addChild(c); + root.addChild(e); + return e; + } + var createChildWithCdata = function(root:Xml, name:String, content:String){ + var e = Xml.createElement(name); + var c = Xml.createCData(if (content != null) content else ""); + e.addChild(c); + root.addChild(e); + return e; + } + Sys.setTimeLocale("en_US.UTF8"); + var url = "http://"+neko.Web.getClientHeader("Host"); + var rss = Xml.createElement("rss"); + rss.set("version","2.0"); + var channel = createChild(rss, "channel"); + createChildWithContent(channel, "title", "haxe-libs"); + createChildWithContent(channel, "link", url); + createChildWithContent(channel, "description", "lib.haxe.org RSS"); + createChildWithContent(channel, "generator", "haxe"); + createChildWithContent(channel, "language", "en"); + for (v in Version.manager.latest(10)){ + var project = v.project; + var item = createChild(channel, "item"); + createChildWithContent(item, "title", StringTools.htmlEscape(project.name+" "+v.name)); + createChildWithContent(item, "link", url+"/p/"+project.name); + createChildWithContent(item, "guid", url+"/p/"+project.name+"?v="+v.id); + var date = DateTools.format(Date.fromString(v.date), "%a, %e %b %Y %H:%M:%S %z"); + createChildWithContent(item, "pubDate", date); + createChildWithContent(item, "author", project.owner.name); + createChildWithContent(item, "description", StringTools.htmlEscape(v.comments)); + } + return rss; + } + + static function main() { + var error = null; + initDatabase(); + try { + run(); + } catch( e : Dynamic ) { + error = { e : e }; + } + db.close(); + neko.db.Manager.cleanup(); + if( error != null ) + neko.Lib.rethrow(error.e); + } + +} diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/SiteApi.hx b/extra/haxelib_src/src/tools/legacyhaxelib/SiteApi.hx new file mode 100644 index 0000000000000000000000000000000000000000..a6db5d1cdaafdf4c6003f226c8a2dae06dc4f33e --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/SiteApi.hx @@ -0,0 +1,287 @@ +/* + * Copyright (C)2005-2012 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 tools.legacyhaxelib; +import tools.legacyhaxelib.Data; +#if haxelib_site +import tools.legacyhaxelib.SiteDb; +#end + +class SiteApi { + + var db : sys.db.Connection; + + public function new( db ) { + this.db = db; + } + + public function search( word : String ) : List<{ id : Int, name : String }> { + return Project.manager.containing(word); + } + + public function infos( project : String ) : ProjectInfos { + var p = Project.manager.search({ name : project }).first(); + if( p == null ) + throw "No such Project : "+project; + var vl = Version.manager.search({ project : p.id }); + var versions = new Array(); + for( v in vl ) + versions.push({ name : v.name, comments : v.comments, date : v.date }); + return { + name : p.name, + curversion : if( p.version == null ) null else p.version.name, + desc : p.description, + versions : versions, + owner : p.owner.name, + website : p.website, + license : p.license, + tags : Tag.manager.search({ project : p.id }).map(function(t) return t.tag), + }; + } + + public function user( name : String ) : UserInfos { + var u = User.manager.search({ name : name }).first(); + if( u == null ) + throw "No such user : "+name; + var pl = Project.manager.search({ owner : u.id }); + var projects = new Array(); + for( p in pl ) + projects.push(p.name); + return { + name : u.name, + fullname : u.fullname, + email : u.email, + projects : projects, + }; + } + + public function register( name : String, pass : String, mail : String, fullname : String ) : Bool { + if( !Data.alphanum.match(name) ) + throw "Invalid user name, please use alphanumeric characters"; + if( name.length < 3 ) + throw "User name must be at least 3 characters"; + var u = new User(); + u.name = name; + u.pass = pass; + u.email = mail; + u.fullname = fullname; + u.insert(); + return null; + } + + public function isNewUser( name : String ) : Bool { + return User.manager.search({ name : name }).first() == null; + } + + public function checkDeveloper( prj : String, user : String ) : Void { + var p = Project.manager.search({ name : prj }).first(); + if( p == null ) + return; + for( d in Developer.manager.search({ project : p.id }) ) + if( d.user.name == user ) + return; + throw "User '"+user+"' is not a developer of project '"+prj+"'"; + } + + public function checkPassword( user : String, pass : String ) : Bool { + var u = User.manager.search({ name : user }).first(); + return u != null && u.pass == pass; + } + + public function getSubmitId() : String { + return Std.string(Std.random(100000000)); + } + + public function processSubmit( id : String, user : String, pass : String ) : String { + var path = Site.TMP_DIR+"/"+Std.parseInt(id)+".tmp"; + + var file = try sys.io.File.read(path,true) catch( e : Dynamic ) throw "Invalid file id #"+id; + var zip = try haxe.zip.Reader.readZip(file) catch( e : Dynamic ) { file.close(); neko.Lib.rethrow(e); }; + file.close(); + + var infos = Data.readInfos(zip,true); + var u = User.manager.search({ name : user }).first(); + if( u == null || u.pass != pass ) + throw "Invalid username or password"; + + var devs = infos.developers.map(function(user) { + var u = User.manager.search({ name : user }).first(); + if( u == null ) + throw "Unknown user '"+user+"'"; + return u; + }); + + var tags = Lambda.array(infos.tags); + tags.sort(Reflect.compare); + + var p = Project.manager.search({ name : infos.project }).first(); + + // create project if needed + if( p == null ) { + p = new Project(); + p.name = infos.project; + p.description = infos.desc; + p.website = infos.website; + p.license = infos.license; + p.downloads = 0; + p.owner = u; + p.insert(); + for( u in devs ) { + var d = new Developer(); + d.user = u; + d.project = p; + d.insert(); + } + for( tag in tags ) { + var t = new Tag(); + t.tag = tag; + t.project = p; + t.insert(); + } + } + + // check submit rights + var pdevs = Developer.manager.search({ project : p.id }); + var isdev = false; + for( d in pdevs ) + if( d.user.id == u.id ) { + isdev = true; + break; + } + if( !isdev ) + throw "You are not a developer of this project"; + + var otags = Tag.manager.search({ project : p.id }); + var curtags = otags.map(function(t) return t.tag).join(":"); + + // update public infos + if( infos.desc != p.description || p.website != infos.website || p.license != infos.license || pdevs.length != devs.length || tags.join(":") != curtags ) { + if( u.id != p.owner.id ) + throw "Only project owner can modify project infos"; + p.description = infos.desc; + p.website = infos.website; + p.license = infos.license; + p.update(); + if( pdevs.length != devs.length ) { + for( d in pdevs ) + d.delete(); + for( u in devs ) { + var d = new Developer(); + d.user = u; + d.project = p; + d.insert(); + } + } + if( tags.join(":") != curtags ) { + for( t in otags ) + t.delete(); + for( tag in tags ) { + var t = new Tag(); + t.tag = tag; + t.project = p; + t.insert(); + } + } + } + + // look for current version + var current = null; + for( v in Version.manager.search({ project : p.id }) ) + if( v.name == infos.version ) { + current = v; + break; + } + + // update documentation + var doc = null; + var docXML = Data.readDoc(zip); + if( docXML != null ) { + try { + var p = new haxe.rtti.XmlParser(); + var firstElm = Xml.parse(docXML).firstElement(); + p.process(firstElm, null); + throw "get to here before doc"; + p.process(Xml.parse(docXML).firstElement(),null); + p.sort(); + var roots = new Array(); + for( x in p.root ) + switch( x ) { + case TPackage(name,_,_): + switch( name ) { + case "flash","flash8","sys","cs","java","flash9","haxe","js","neko","cpp","php","tools": // don't include haXe core types + default: roots.push(x); + } + default: + // don't include haXe root types + } + var s = new haxe.Serializer(); + s.useEnumIndex = true; + s.useCache = true; + s.serialize(roots); + doc = s.toString(); + } catch ( e:Dynamic ) { + // If documentation can't be generated, ignore it. + } + } + + // update file + var target = Site.REP_DIR+"/"+Data.fileName(p.name,infos.version); + if( current != null ) sys.FileSystem.deleteFile(target); + sys.FileSystem.rename(path,target); + + // update existing version + if( current != null ) { + current.documentation = doc; + current.comments = infos.versionComments; + current.update(); + return "Version "+current.name+" (id#"+current.id+") updated"; + } + + // add new version + var v = new Version(); + v.project = p; + v.name = infos.version; + v.comments = infos.versionComments; + v.downloads = 0; + v.date = Date.now().toString(); + v.documentation = doc; + v.insert(); + + p.version = v; + p.update(); + return "Version "+v.name+" (id#"+v.id+") added"; + } + + public function postInstall( project : String, version : String ) { + var p = Project.manager.search({ name : project }).first(); + if( p == null ) + throw "No such Project : "+project; + var v = Version.manager.search({ project : p.id, name : version }).first(); + if( v == null ) + throw "No such Version : "+version; + v.downloads++; + v.update(); + p.downloads++; + p.update(); + } + +} + diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/SiteDb.hx b/extra/haxelib_src/src/tools/legacyhaxelib/SiteDb.hx new file mode 100644 index 0000000000000000000000000000000000000000..fa77216301659b4cf67403a74ec8178c3e786e78 --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/SiteDb.hx @@ -0,0 +1,198 @@ +/* + * Copyright (C)2005-2012 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 tools.legacyhaxelib; + +class User extends neko.db.Object { + + public static var manager = new neko.db.Manager(User); + + public var id : Int; + public var name : String; + public var fullname : String; + public var email : String; + public var pass : String; + +} + +class Project extends neko.db.Object { + + static function RELATIONS() { + return [ + { key : "owner", prop : "owner", manager : User.manager }, + { key : "version", prop : "version", manager : Version.manager }, + ]; + } + + public static var manager = new ProjectManager(Project); + + public var id : Int; + public var name : String; + public var description : String; + public var website : String; + public var license : String; + public var downloads : Int; + public var owner(dynamic,dynamic) : User; + public var version(dynamic,dynamic) : Version; + +} + +class Tag extends neko.db.Object { + + static function RELATIONS() { + return [ + { key : "project", prop : "project", manager : Project.manager }, + ]; + } + + public static var manager = new TagManager(Tag); + + public var id : Int; + public var tag : String; + public var project(dynamic,dynamic) : Project; + +} + +class Version extends neko.db.Object { + + static function RELATIONS() { + return [{ key : "project", prop : "project", manager : Project.manager }]; + } + + public static var manager = new VersionManager(Version); + + public var id : Int; + public var project(dynamic,dynamic) : Project; + public var name : String; + public var date : String; // sqlite does not have a proper 'date' type + public var comments : String; + public var downloads : Int; + public var documentation : Null; + +} + +class Developer extends neko.db.Object { + + static var TABLE_IDS = ["user","project"]; + static function RELATIONS() { + return [ + { key : "user", prop : "user", manager : User.manager }, + { key : "project", prop : "project", manager : Project.manager }, + ]; + } + + public static var manager = new neko.db.Manager(Developer); + + public var user(dynamic,dynamic) : User; + public var project(dynamic,dynamic) : Project; + +} + +class ProjectManager extends neko.db.Manager { + + public function containing( word ) : List<{ id : Int, name : String }> { + word = quote("%"+word+"%"); + return results("SELECT id, name FROM Project WHERE name LIKE "+word+" OR description LIKE "+word); + } + + public function allByName() { + return objects("SELECT * FROM Project ORDER BY name COLLATE NOCASE",false); + } + +} + +class VersionManager extends neko.db.Manager { + + public function latest( n : Int ) { + return objects("SELECT * FROM Version ORDER BY date DESC LIMIT "+n,false); + } + + public function byProject( p : Project ) { + return objects("SELECT * FROM Version WHERE project = "+p.id+" ORDER BY date DESC",false); + } + +} + +class TagManager extends neko.db.Manager { + + public function topTags( n : Int ) { + return results("SELECT tag, COUNT(*) as count FROM Tag GROUP BY tag ORDER BY count DESC LIMIT "+n); + } + +} + +class SiteDb { + + public static function create( db : sys.db.Connection ) { + db.request("DROP TABLE IF EXISTS User"); + db.request(" + CREATE TABLE User ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name VARCHAR(16) NOT NULL UNIQUE, + fullname VARCHAR(50) NOT NULL, + pass VARCHAR(32) NOT NULL, + email VARCHAR(50) NOT NULL + ) + "); + db.request("DROP TABLE IF EXISTS Project"); + db.request(" + CREATE TABLE Project ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + owner INTEGER NOT NULL, + name VARCHAR(32) NOT NULL UNIQUE, + license VARCHAR(20) NOT NULL, + description TEXT NOT NULL, + website VARCHAR(100) NOT NULL, + version INT, + downloads INT NOT NULL + ) + "); + db.request("DROP TABLE IF EXISTS Version"); + db.request(" + CREATE TABLE Version ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + project INTEGER NOT NULL, + downloads INTEGER NOT NULL, + date VARCHAR(19) NOT NULL, + name VARCHAR(32) NOT NULL, + comments TEXT NOT NULL, + documentation TEXT NULL + ) + "); + db.request("DROP TABLE IF EXISTS Developer"); + db.request(" + CREATE TABLE Developer ( + user INTEGER NOT NULL, + project INTEGER NOT NULL + ) + "); + db.request("DROP TABLE IF EXISTS Tag"); + db.request(" + CREATE TABLE Tag ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + tag VARCHAR(32) NOT NULL, + project INTEGER NOT NULL + ) + "); + db.request("DROP INDEX IF EXISTS TagSearch"); + db.request("CREATE INDEX TagSearch ON Tag(tag)"); + } +} diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.css b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.css new file mode 100644 index 0000000000000000000000000000000000000000..6a708cdb8d8cdba2e0c90e96b3d85074967e77ef --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.css @@ -0,0 +1,212 @@ + +/* structure */ + +body { + margin : 0; + padding : 0; + text-align: center; + font-family : "trebuchet ms",sans-serif; + font-size : 10.5pt; + background : #FFFFFF url("http://haxe.org/img/haxe/bg_main.gif") repeat-x; +} + +.page { + margin: 10px auto 10px auto; + padding : 5px; + width : 750px; + background-color : #FFFFFF; + border : 1px solid #AAA; + -moz-border-radius : 10px; +} + +.menu { + text-align : left; + float : left; + width : 150px; +} + +.content { + text-align : left; + float : left; + width : 600px; +} + +.clear { + clear : both; +} + +/* style */ + +a, a:visited { + color : #C35700; + text-decoration : none; +} + +a:hover { + text-decoration : underline; +} + +h1 { + text-align : center; + margin-top : 20px; +} + +h1 a, h1 a:hover, h1 a:visited { + color : #C35700; + text-decoration : none; +} + +.content p { + text-align : justify; + margin : 0px; + padding : 0px 10px 0px 10px; +} + +.menu ul { + list-style : none; + margin : 5px; + padding : 0px; +} + +.versions .date, .versions .project, .versions .name { + display : inline; +} + +.versions ul, .projects ul { + list-style : circle; + margin : 25px; + padding : 0px; +} + +.date { + color : #555; + font-size : 12px; +} + +.versions .name { + font-weight : bold; +} + +.versions .download { + float : right; + margin-top : -22px; + margin-right : 30px; +} + +.download { + padding : 2px 4px 2px 4px; + background-color : #eee; + display : inline; +} + +.download a { + color : #555; + font-size : 12px; + text-decoration : none; +} + +.download a:visited { + color : #555; +} + +.versions .comments { + margin-right : 40px; + margin-left : 10px; + margin-bottom : 5px; + text-align : justify; +} + +.pinfos .description { + padding : 10px; +} + +.pinfos .download { + margin : 200px; +} + +.label { + color : #555; + width : 80px; + float : left; +} + +.tags a { + margin-right : 5px; +} + +form { + margin-left : 5px; + margin-top : 5px; +} + +input { + width : 80px; +} + +/* documentation */ + +.api .title { + font-size: 35; + font-weight: bold; + text-align: center; + background-color : #FFD473; + color : white; +} + +.api ul.entry { + list-style-type: disc; + margin-left : 30px; + padding-left : 0px; +} + +.api .package_content { + display : none; +} + +.api a { + text-decoration : none; +} + +.api a:hover { + text-decoration : underline; +} + +.api a.package { + color : black; +} + +.api .index { +} + +.api .kwd { + color : #09598A; + font-weight : bold; +} + +.api .classname { + font-size : 30; + font-weight : bold; +} + +.api .classdoc { + border : 1px dashed #666; + margin-left : 20px; + margin-right : 20px; + padding : 5 5 5 5; +} + +.api .importmod, .api .extends, .api .implements, .api .typedef, .api .platforms { + color : #777; +} + +.api dd { + margin-top : 10px; + font-size : 12pt; + color : #444; +} + +.api dt { + margin-left : 20px; + margin-bottom : 5px; + text-align : left; +} diff --git a/std/tools/haxelib/haxelib.hxml b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxml similarity index 58% rename from std/tools/haxelib/haxelib.hxml rename to extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxml index 10837827e690539a6eb8aa29f0ca96e19d9aae75..e98559c95540d3cffa6c236431cfe8bb1e8093a9 100644 --- a/std/tools/haxelib/haxelib.hxml +++ b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxml @@ -1,3 +1,3 @@ -neko haxelib.n --main tools.haxelib.Main +-main tools.legacyhaxelib.Main -cmd "nekotools boot haxelib.n" diff --git a/std/tools/haxelib/haxelib.hxproj b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxproj similarity index 85% rename from std/tools/haxelib/haxelib.hxproj rename to extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxproj index ff01f819f5484599e9fd3e5a27bf5338b15bdd4a..93e9bb6dccf15e4c5617b75ce95e4c36b03e8133 100644 --- a/std/tools/haxelib/haxelib.hxproj +++ b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.hxproj @@ -35,12 +35,7 @@ - - - - - - + haxe haxelib.hxml diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.sh b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.sh new file mode 100644 index 0000000000000000000000000000000000000000..4a0621d429d541c4a2d718f328682947e29f875f --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/haxelib.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec haxe --run tools.legacyhaxelib.Main "$@" diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/site.hxml b/extra/haxelib_src/src/tools/legacyhaxelib/site.hxml new file mode 100644 index 0000000000000000000000000000000000000000..e7b575f48035056624adbb9453b1a8957f11c436 --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/site.hxml @@ -0,0 +1,5 @@ +-neko index.n +-main tools.legacyhaxelib.Site +-dce no +-D haxelib-site +-lib hx2compat \ No newline at end of file diff --git a/extra/haxelib_src/src/tools/legacyhaxelib/website.mtt b/extra/haxelib_src/src/tools/legacyhaxelib/website.mtt new file mode 100644 index 0000000000000000000000000000000000000000..4894d12cfb6cfa1cf5263b5d17c51a576efcc6d0 --- /dev/null +++ b/extra/haxelib_src/src/tools/legacyhaxelib/website.mtt @@ -0,0 +1,180 @@ + + + +lib.haxe.org + + + + + + + +

(Legacy Haxelib) lib.haxe.org

+ +
+ + + + +
+ +::if error:: + +
+ ::error:: +
+ +::elseif act_index:: + +

Welcome

+ +

+ This website is listing all the libraries available through the haxelib haXe package manager. + Please visit the haxelib page on haXe website to learn more about haxelib. +

+ +

Latest releases

+ +
+ +
+ +Browse Projects + +::elseif act_p:: + +

::(p.name)::

+ +
+
::(p.description)::
+ ::if tags::
Tags
::foreach tags::::tag::::end::
::end:: + +
Version
::(version.name)::
+ +
License
::(p.license)::
+ ::if (version.documentation)::::end:: + +
+ +

History

+ +
+
    + ::foreach versions:: +
  • +
    ::date::
    +
    ::name::
    + +
    ::comments::
    +
  • + ::end:: +
+
+ +::elseif act_u:: + +

::(u.name)::

+ +
+
Name
::(u.fullname)::
+ +
+ +

Projects

+ +
+
    +::foreach uprojects:: +
  • ::name::
  • +::end:: +
+
+ +::elseif act_t:: + +

Tag ::tag::

+ +

+ Here's the list of projects using this tag : +

+ +
+
    +::foreach tprojects:: +
  • + ::name:: +
    ::description::
    +
  • +::end:: +
+
+ +::elseif act_all:: + +

::if search::Search Results for '::search::'::else::All Projects::end:::

+ +
+
    +::foreach projects:: +
  • + ::name:: +
    ::description::
    +
  • +::end:: +
+
+ +::elseif act_d:: + +

::(p.name):: ::(v.name):: Documentation

+ + + +
+::content:: +
+ +::else:: + +

+ No content for this action +

+ +::end:: + +
+ +
+ +
+ + + diff --git a/extra/haxelib_src/test.hxml b/extra/haxelib_src/test.hxml new file mode 100644 index 0000000000000000000000000000000000000000..902314beb914cf1584b9bb663032e649e946d43e --- /dev/null +++ b/extra/haxelib_src/test.hxml @@ -0,0 +1,10 @@ +-debug +--each + +haxelib.hxml +--next + +-cp src +-cp test +-neko bin/test.n +-main HaxelibTests diff --git a/extra/haxelib_src/test.sh b/extra/haxelib_src/test.sh new file mode 100755 index 0000000000000000000000000000000000000000..435329eb181b7b5f2da424962712ba21015b976d --- /dev/null +++ b/extra/haxelib_src/test.sh @@ -0,0 +1,3 @@ +#!/bin/sh +haxe test.hxml +exec neko bin/test.n "$@" \ No newline at end of file diff --git a/extra/haxelib_src/test/HaxelibTests.hx b/extra/haxelib_src/test/HaxelibTests.hx new file mode 100644 index 0000000000000000000000000000000000000000..a08efa7a573aa2a0edfbba7e8296c14a98f77e2e --- /dev/null +++ b/extra/haxelib_src/test/HaxelibTests.hx @@ -0,0 +1,74 @@ +import tools.haxelib.Vcs; +import haxe.unit.TestRunner; +import sys.*; +import sys.io.*; +import tests.*; +using StringTools; + +class HaxelibTests { + public static function runCommand(cmd:String, args:Array):Void + { + Sys.println('Command: $cmd $args'); + + var exitCode = Sys.command(cmd, args); + + Sys.println('Command exited with $exitCode: $cmd $args'); + + if(exitCode != 0) + Sys.exit(exitCode); + } + + static function prepare():Void { + runCommand("haxe", ["--run", "Package"]); + + /* + (re)package the dummy libraries + */ + for (item in FileSystem.readDirectory("test/libraries")) { + if ( + !item.startsWith("lib") || + item.endsWith(".zip") + ) + continue; + + var zipUri = 'test/libraries/${item}.zip'; + if (FileSystem.exists(zipUri)) { + FileSystem.deleteFile(zipUri); + } + Sys.setCwd('test/libraries/${item}'); + switch (Sys.systemName()) { + case "Linux", "Mac": + runCommand("zip", ["-r", '../${item}.zip', "."]); + case "Windows": + runCommand("7za", ["a", "-tzip", "-r", '../${item}.zip', "."]); + } + + Sys.setCwd('../../..'); + } + } + + static function main():Void { + prepare(); + + var r = new TestRunner(); + + r.add(new TestSemVer()); + r.add(new TestData()); + r.add(new TestRemoveSymlinks("symlinks")); + r.add(new TestRemoveSymlinks("symlinks-broken")); + + // Testing VCS on two identical repositories: + // Hg: https://bitbucket.org/fzzr/hx.signal + // Git: https://github.com/fzzr-/hx.signal.git + + // Hg impl. suports tags & revs. Here "78edb4b" is a first revision "initial import" at that repo: + r.add(new TestVcs(tools.haxelib.Vcs.VcsID.Hg, "Mercurial", "https://bitbucket.org/fzzr/hx.signal", "78edb4b")); + // Git impl. suports only tags. Here "0.9.2" is a first revision too ("initial import"): + r.add(new TestVcs(tools.haxelib.Vcs.VcsID.Git, "Git", "https://github.com/fzzr-/hx.signal.git", "0.9.2")); + r.add(new TestVcsNotFound()); + r.add(new TestCli()); + + var success = r.run(); + Sys.exit(success ? 0 : 1); + } +} \ No newline at end of file diff --git a/extra/haxelib_src/test/libraries/libDeep/libDeep/bar/Bar.hx b/extra/haxelib_src/test/libraries/libDeep/libDeep/bar/Bar.hx new file mode 100644 index 0000000000000000000000000000000000000000..2936374c09fd9ec3ac752b23c93de783ce5e94fc --- /dev/null +++ b/extra/haxelib_src/test/libraries/libDeep/libDeep/bar/Bar.hx @@ -0,0 +1,9 @@ +package bar; + +class Bar { + + static function new() { + trace("new Bar"); + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/test/libraries/libDeep/libDeep/haxelib.json b/extra/haxelib_src/test/libraries/libDeep/libDeep/haxelib.json new file mode 100644 index 0000000000000000000000000000000000000000..5364a28c643257bf9414665b4a25814be2164b5c --- /dev/null +++ b/extra/haxelib_src/test/libraries/libDeep/libDeep/haxelib.json @@ -0,0 +1,10 @@ +{ + "name": "Deep", + "url" : "http://example.org", + "license": "Public", + "tags": ["deep", "test"], + "description": "This project's zip contains a folder that holds the lib.", + "version": "1.0.0", + "releasenote": "N/A", + "contributors": ["DeepAuthor", "AnotherGuy"] +} \ No newline at end of file diff --git a/extra/haxelib_src/test/libraries/symlinks-broken.zip b/extra/haxelib_src/test/libraries/symlinks-broken.zip new file mode 100644 index 0000000000000000000000000000000000000000..02c12f2046e4ebca6dfb9a631970f57a3f92800d Binary files /dev/null and b/extra/haxelib_src/test/libraries/symlinks-broken.zip differ diff --git a/extra/haxelib_src/test/libraries/symlinks.zip b/extra/haxelib_src/test/libraries/symlinks.zip new file mode 100644 index 0000000000000000000000000000000000000000..0e8c8355434e7c3e50a26631476290dd1e1d54e5 Binary files /dev/null and b/extra/haxelib_src/test/libraries/symlinks.zip differ diff --git a/extra/haxelib_src/test/tests/TestCli.hx b/extra/haxelib_src/test/tests/TestCli.hx new file mode 100644 index 0000000000000000000000000000000000000000..124c2de09e3f054bc49b42a914bb8e45ba7b6d9d --- /dev/null +++ b/extra/haxelib_src/test/tests/TestCli.hx @@ -0,0 +1,46 @@ +package tests; + +import tools.haxelib.Main.Cli; +import tools.haxelib.Main.CliError; +import haxe.unit.TestCase; + +class TestCli extends TestCase +{ + //----------- properties, fields ------------// + + var cli:Cli; + + //--------------- constructor ---------------// + public function new() + { + super(); + } + + + //--------------- initialize ----------------// + + override public function setup():Void + { + cli = new Cli(); + } + + //----------------- tests -------------------// + + public function testSetWrongCwd():Void + { + var cwd = Sys.getCwd(); + + try + { + cli.cwd = "/this/path/dos/not/exists"; + assertTrue(false); + } + catch(error:CliError) + assertTrue(true); + + assertEquals(cwd, Sys.getCwd()); + } + + + //----------------- tools -------------------// +} diff --git a/extra/haxelib_src/test/tests/TestData.hx b/extra/haxelib_src/test/tests/TestData.hx new file mode 100644 index 0000000000000000000000000000000000000000..435e1af392d9d4eb04806a776c778c155836dd04 --- /dev/null +++ b/extra/haxelib_src/test/tests/TestData.hx @@ -0,0 +1,282 @@ +package tests; + +import haxe.ds.StringMap; +import haxe.Json; +import haxe.io.*; +import haxe.zip.*; +import sys.io.*; +import tools.haxelib.Data; +using StringTools; + +class TestData extends haxe.unit.TestCase { + + public function testSafe() { + assertEquals( "abc", checkSafe("abc") ); + assertEquals( "bean,hx", checkSafe("bean.hx") ); + assertEquals( "1,2,3", checkSafe("1.2.3") ); + assertEquals( "_-,123", checkSafe("_-.123") ); + assertEquals( "invalid", checkSafe("1,2") ); + assertEquals( "invalid", checkSafe("space ") ); + assertEquals( "invalid", checkSafe("\t") ); + assertEquals( "invalid", checkSafe("\n") ); + assertEquals( "invalid", checkSafe("") ); + } + + function checkSafe( str:String ) { + return try { + Data.safe( str ); + } catch (e:String) "invalid"; + } + + public function testUnsafe() { + assertEquals( "abc", Data.unsafe("abc") ); + assertEquals( "1.2.3", Data.unsafe("1,2,3") ); + assertEquals( "", Data.unsafe("") ); + } + + public function testFileName() { + assertEquals( "lib-1,2,3.zip", checkFileName("lib","1.2.3") ); + assertEquals( "lib-1,2,3-rc,3.zip", checkFileName("lib","1.2.3-rc.3") ); + assertEquals( "invalid", checkFileName("lib",",") ); + assertEquals( "invalid", checkFileName(",","version") ); + assertEquals( "invalid", checkFileName("","version") ); + } + + function checkFileName( lib, ver ) { + return try { + Data.fileName( lib, ver ); + } catch (e:String) "invalid"; + } + + public function testLocateBasePath() { + var zip = Reader.readZip(new BytesInput(File.getBytes("package/package.zip"))); + assertEquals( "", Data.locateBasePath(zip) ); + + var zip = Reader.readZip(new BytesInput(File.getBytes("test/libraries/libDeep.zip"))); + assertEquals( "libDeep/", Data.locateBasePath(zip) ); + } + + public function testReadDoc() { + var zip = Reader.readZip(new BytesInput(File.getBytes("package/package.zip"))); + assertEquals( null, Data.readDoc(zip) ); + + //TODO + } + + public function testReadInfos() { + var zip = Reader.readZip(new BytesInput(File.getBytes("package/package.zip"))); + var info = Data.readInfos(zip, true); + assertEquals( "haxelib_client", info.name ); + assertEquals( "GPL", info.license ); + + var zip = Reader.readZip(new BytesInput(File.getBytes("test/libraries/libDeep.zip"))); + var info = Data.readInfos(zip, true); + assertEquals( "Deep", info.name ); + assertEquals( "http://example.org", info.url ); + assertEquals( "Public", info.license ); + assertEquals( "deep, test", info.tags.join(", ") ); + assertEquals( "This project's zip contains a folder that holds the lib.", info.description ); + assertEquals( "1.0.0", info.version ); + assertEquals( "N/A", info.releasenote ); + assertEquals( "DeepAuthor, AnotherGuy", info.contributors.join(", ") ); + } + + public function testCheckClassPath() { + var zip = Reader.readZip(new BytesInput(File.getBytes("package/package.zip"))); + var info = Data.readInfos(zip, true); + var ok:Dynamic = try { + Data.checkClassPath(zip,info); + true; + } catch (e:Dynamic) { + e; + } + assertEquals( ok, true ); + + var zip = Reader.readZip(new BytesInput(File.getBytes("test/libraries/libDeep.zip"))); + var info = Data.readInfos(zip, true); + var ok:Dynamic = try { + Data.checkClassPath(zip,info); + true; + } catch (e:Dynamic) { + e; + } + assertEquals( ok, true ); + } + + public function testReadDataWithCheck() { + assertFalse( readDataOkay("bad json") ); + + assertTrue( readDataOkay(getJsonInfos()) ); + + // Names + assertFalse( readDataOkay("{}") ); + assertFalse( readDataOkay(getJsonInfos({ name: null })) ); + + assertFalse( readDataOkay(getJsonInfos({ name: '' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: 'haxe' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: 'haXe' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: 'all' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: 'something.zip' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: 'something.hxml' })) ); + assertFalse( readDataOkay(getJsonInfos({ name: '12' })) ); + assertTrue( readDataOkay(getJsonInfos({ name: 'mylib' })) ); + assertFalse( readDataOkay(getJsonInfos([ "name" ])) ); // remove the field altogether + + // Description (optional) + assertTrue( readDataOkay(getJsonInfos({ description: 'Some Description' })) ); + assertTrue( readDataOkay(getJsonInfos({ description: '' })) ); + assertTrue( readDataOkay(getJsonInfos({ description: null })) ); + + // Licence + assertTrue( readDataOkay(getJsonInfos({ license: 'BSD' })) ); + assertFalse( readDataOkay(getJsonInfos({ license: null })) ); + assertFalse( readDataOkay(getJsonInfos({ license: '' })) ); + assertFalse( readDataOkay(getJsonInfos({ license: 'CustomLicence' })) ); + assertFalse( readDataOkay(getJsonInfos([ "license" ])) ); // remove the field altogether + + // Contibutors + assertFalse( readDataOkay(getJsonInfos({ contributors: [] })) ); + assertFalse( readDataOkay(getJsonInfos({ contributors: null })) ); + assertFalse( readDataOkay(getJsonInfos({ contributors: "jason" })) ); + assertTrue( readDataOkay(getJsonInfos({ contributors: ["jason"] })) ); + assertTrue( readDataOkay(getJsonInfos({ contributors: ["jason","juraj"] })) ); + assertFalse( readDataOkay(getJsonInfos([ "contributors" ])) ); // remove the field altogether + + // Version + assertTrue( readDataOkay(getJsonInfos({ version: "0.1.2-rc.0" })) ); + assertFalse( readDataOkay(getJsonInfos({ version: "non-semver" })) ); + assertFalse( readDataOkay(getJsonInfos({ version: 0 })) ); + assertFalse( readDataOkay(getJsonInfos({ version: null })) ); + assertFalse( readDataOkay(getJsonInfos([ "version" ])) ); // remove the field altogether + + // Tags (optional) + assertTrue( readDataOkay(getJsonInfos({ tags: ["tag1","tag2"] })) ); + assertTrue( readDataOkay(getJsonInfos({ tags: null })) ); + assertFalse( readDataOkay(getJsonInfos({ tags: "mytag" })) ); + + // Dependencies (optional) + assertTrue( readDataOkay(getJsonInfos({ dependencies: null })) ); + assertTrue( readDataOkay(getJsonInfos({ dependencies: { somelib: "" } })) ); + + assertTrue( readDataOkay(getJsonInfos({ dependencies: { somelib:"1.3.0" } }) )); + assertFalse( readDataOkay(getJsonInfos({ dependencies: { somelib: "nonsemver" }})) ); + + assertFalse( readDataOkay(getJsonInfos({ dependencies: { somelib: 0 } })) ); + assertFalse( readDataOkay(getJsonInfos({ dependencies: "somelib" })) ); + + // ReleaseNote + assertTrue( readDataOkay(getJsonInfos({ releasenote: "release" })) ); + assertFalse( readDataOkay(getJsonInfos({ releasenote: ["some","note"] })) ); + assertFalse( readDataOkay(getJsonInfos({ releasenote: null })) ); + assertFalse( readDataOkay(getJsonInfos([ "releasenote" ])) ); // remove the field altogether + + // ClassPath + assertTrue( readDataOkay(getJsonInfos({ classPath: 'src/' })) ); + assertTrue( readDataOkay(getJsonInfos({ classPath: '' })) ); + assertTrue( readDataOkay(getJsonInfos({ classPath: null })) ); + assertFalse( readDataOkay(getJsonInfos({ classPath: ["src","othersrc"] })) ); + } + + public function testReadDataWithoutCheck() { + assertEquals( ProjectName.DEFAULT, Data.readData("bad json",false).name ); + assertEquals( "0.0.0", Data.readData("bad json",false).version ); + + assertEquals( "mylib", Data.readData(getJsonInfos(),false).name ); + assertEquals( "0.1.2", Data.readData(getJsonInfos(),false).version ); + + // Names + assertEquals( ProjectName.DEFAULT, Data.readData("{}",false).name ); + assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos({ name: null }),false).name ); + assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos({ name: '' }),false).name ); + assertEquals( "mylib", Data.readData(getJsonInfos({ name: 'mylib' }),false).name ); + assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos([ "name" ]), false).name ); // remove the field altogether + + /* + // Description (optional) + assertEquals( "Some Description", Data.readData(getJsonInfos({ description: 'Some Description' }),false).description ); + assertEquals( "", Data.readData(getJsonInfos({ description: '' }),false).description ); + assertEquals( "", Data.readData(getJsonInfos({ description: null }),false).description ); + assertEquals( "", Data.readData(getJsonInfos([ "description" ]),false).description ); // remove the field altogether + + // Licence + assertEquals( "BSD", Data.readData(getJsonInfos({ license: 'BSD' }),false).license ); + assertEquals( "Unknown", Data.readData(getJsonInfos({ license: null }),false).license ); + assertEquals( "Unknown", Data.readData(getJsonInfos({ license: '' }),false).license ); + assertEquals( "CustomLicence", Data.readData(getJsonInfos({ license: 'CustomLicence' }),false).license ); + assertEquals( "Unknown", Data.readData(getJsonInfos([ "license" ]),false).license ); // remove the field altogether + + // Contibutors + assertEquals( 0, Data.readData(getJsonInfos({ contributors: [] }),false).contributors.length ); + assertEquals( 0, Data.readData(getJsonInfos({ contributors: null }),false).contributors.length ); + assertEquals( 0, Data.readData(getJsonInfos({ contributors: "jason" }),false).contributors.length ); + assertEquals( 1, Data.readData(getJsonInfos({ contributors: ["jason"] }),false).contributors.length ); + assertEquals( 2, Data.readData(getJsonInfos({ contributors: ["jason","juraj"] }),false).contributors.length ); + assertEquals( 0, Data.readData(getJsonInfos([ "contributors" ]),false).contributors.length ); // remove the field altogether + */ + // Version + assertEquals( "0.1.2-rc.0", Data.readData(getJsonInfos({ version: "0.1.2-rc.0" }),false).version ); + assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: "non-semver" }),false).version ); + assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: 0 }),false).version ); + assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: null }),false).version ); + assertEquals( "0.0.0", Data.readData(getJsonInfos([ "version" ]),false).version ); // remove the field altogether + + /* + // Tags (optional) + assertEquals( 2, Data.readData(getJsonInfos({ tags: ["tag1","tag2"] }),false).tags.length ); + assertEquals( 0, Data.readData(getJsonInfos({ tags: null }),false).tags.length ); + assertEquals( 0, Data.readData(getJsonInfos({ tags: "mytag" }),false).tags.length ); + */ + + // Dependencies (optional) + assertEquals( 0, Data.readData(getJsonInfos({ dependencies: null }),false).dependencies.toArray().length ); + assertEquals( "somelib", Data.readData(getJsonInfos({ dependencies: { somelib:"" } }),false).dependencies.toArray()[0].name ); + assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:"" } }),false).dependencies.toArray()[0].version ); + assertEquals( "1.3.0", Data.readData(getJsonInfos({ dependencies: { somelib:"1.3.0" } }),false).dependencies.toArray()[0].version ); + assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:"nonsemver" } }),false).dependencies.toArray()[0].version ); + assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:null } }),false).dependencies.toArray()[0].version ); + assertEquals( "", Data.readData(getJsonInfos( { dependencies: { somelib:0 } } ), false).dependencies.toArray()[0].version ); + + /* + // ReleaseNote + assertEquals( "release", Data.readData(getJsonInfos({ releasenote: "release" }),false).releasenote ); + assertEquals( "", Data.readData(getJsonInfos({ releasenote: null }),false).releasenote ); + assertEquals( "", Data.readData(getJsonInfos([ "releasenote" ]),false).releasenote ); // remove the field altogether + */ + // ClassPath + assertEquals( "src", Data.readData(getJsonInfos({ classPath: 'src' }), false).classPath ); + assertEquals( "", Data.readData(getJsonInfos({ classPath: '' }), false).classPath ); + assertEquals( "", Data.readData(getJsonInfos({ classPath: null }), false).classPath ); + } + + function readDataOkay( json ) { + try { + Data.readData( json,true ); + return true; + } + catch (e:String) { + return false; + } + } + + function getJsonInfos( ?remove:Array, ?change:Dynamic ) { + var infos = { + name: "mylib", + license: "MIT", + contributors: ["jason"], + version: "0.1.2", + releasenote: "" + }; + if (change != null) { + for ( name in Reflect.fields(change) ) { + var value = Reflect.field( change, name ); + Reflect.setField( infos, name, value ); + } + } + if (remove != null) { + for ( f in remove ) + Reflect.deleteField( infos, f ); + } + return Json.stringify(infos); + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/test/tests/TestRemoveSymlinks.hx b/extra/haxelib_src/test/tests/TestRemoveSymlinks.hx new file mode 100644 index 0000000000000000000000000000000000000000..331c2c9cfa53c8e72749f5f193a8d40568113229 --- /dev/null +++ b/extra/haxelib_src/test/tests/TestRemoveSymlinks.hx @@ -0,0 +1,50 @@ +package tests; + +import sys.FileSystem; +import haxe.io.Path; +import haxe.unit.TestCase; + +class TestRemoveSymlinks extends TestCase +{ + //----------- properties, fields ------------// + + static var REPO = "haxelib-repo"; + var lib:String = null; + var repo:String = null; + + //--------------- constructor ---------------// + public function new(lib:String) + { + super(); + this.lib = lib; + this.repo = Path.join([Sys.getCwd(), "testing", REPO]); + } + + //--------------- initialize ----------------// + + override public function setup():Void + { + var libzip = Path.join([Sys.getCwd(), "test", "libraries", lib + ".zip"]); + Sys.command("neko", ["./bin/haxelib.n", "setup", repo]); + Sys.command("neko", ["./bin/haxelib.n", "local", libzip]); + } + + //----------------- tests -------------------// + + public function testRemoveLibWithSymlinks():Void + { + var code = Sys.command("neko", ["./bin/haxelib.n", "remove", lib]); + assertEquals(code, 0); + assertFalse(FileSystem.exists(Path.join([repo, lib]))); + } + + + //----------------- tools -------------------// + + function command(cmd:String, args:Array) + { + var p = new sys.io.Process(cmd, args); + var code = p.exitCode(); + return {code:code, out:code == 0 ? p.stdout.readAll().toString() : p.stderr.readAll().toString()}; + } +} diff --git a/extra/haxelib_src/test/tests/TestSemVer.hx b/extra/haxelib_src/test/tests/TestSemVer.hx new file mode 100644 index 0000000000000000000000000000000000000000..8f83772023937e9c042f680d05d38dae0a100a19 --- /dev/null +++ b/extra/haxelib_src/test/tests/TestSemVer.hx @@ -0,0 +1,70 @@ +package tests; + +import tools.haxelib.SemVer; + +class TestSemVer extends haxe.unit.TestCase { + static function make(major, minor, patch, ?preview, ?previewNum):SemVer { + return { + major : major, + minor : minor, + patch : patch, + preview : preview, + previewNum : previewNum + }; + } + public function testToString() { + assertEquals( "0.1.2", make(0,1,2) ); + + // Release Tags + assertEquals( "0.1.2-alpha", make(0,1,2,ALPHA) ); + assertEquals( "0.1.2-beta", make(0,1,2,BETA) ); + assertEquals( "0.1.2-rc", make(0,1,2,RC) ); + + // Release Tag Versions + assertEquals( "0.1.2-alpha.0", make(0,1,2,ALPHA,0) ); + assertEquals( "0.1.2-beta.0", make(0,1,2,BETA,0) ); + assertEquals( "0.1.2-rc.0", make(0,1,2,RC,0) ); + + // Weird input + assertEquals( "0.1.2", make(0,1,2,null,0) ); + + // Multiple characters + assertEquals( "100.200.300-rc.400", make(100,200,300,RC,400) ); + } + + public function testOfString() { + // Normal + assertEquals( "0.1.2", (SemVer.ofString("0.1.2").data : SemVer)); + assertEquals( "100.50.200", (SemVer.ofString("0100.050.0200").data : SemVer)); + + // Release tags + assertEquals( "0.1.2-alpha", (SemVer.ofString("0.1.2-ALPHA").data : SemVer)); + assertEquals( "0.1.2-alpha", (SemVer.ofString("0.1.2-alpha").data : SemVer)); + assertEquals( "0.1.2-beta", (SemVer.ofString("0.1.2-beta").data : SemVer)); + assertEquals( "0.1.2-rc", (SemVer.ofString("0.1.2-rc").data : SemVer)); + assertEquals( "0.1.2-rc.1", (SemVer.ofString("0.1.2-rc.01").data : SemVer)); + } + + public function testOfStringInvalid() { + assertEquals( "invalid", parseInvalid(null) ); + assertEquals( "invalid", parseInvalid("") ); + assertEquals( "invalid", parseInvalid("1") ); + assertEquals( "invalid", parseInvalid("1.1") ); + assertEquals( "invalid", parseInvalid("1.2.a") ); + assertEquals( "invalid", parseInvalid("a.b.c") ); + assertEquals( "invalid", parseInvalid("1.2.3-") ); + assertEquals( "invalid", parseInvalid("1.2.3-rc.") ); + assertEquals( "invalid", parseInvalid("1.2.3--rc.1") ); + assertEquals( "invalid", parseInvalid("1.2.3-othertag") ); + assertEquals( "invalid", parseInvalid("1.2.3-othertag.1") ); + } + + function parseInvalid( str:String ) { + return try { + (SemVer.ofString( str ) : String); + } catch (e:String) { + "invalid"; + } + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/test/tests/TestVcs.hx b/extra/haxelib_src/test/tests/TestVcs.hx new file mode 100644 index 0000000000000000000000000000000000000000..031370aa55b300a1a6a676905687b946de93a3a0 --- /dev/null +++ b/extra/haxelib_src/test/tests/TestVcs.hx @@ -0,0 +1,241 @@ +package tests; + +import sys.io.File; +import sys.FileSystem; +import tools.haxelib.Vcs; +import haxe.unit.TestCase; +import tools.haxelib.Main.Cli; +import tools.haxelib.Main.Answer; + +class TestVcs extends TestCase +{ + //----------- properties, fields ------------// + + static inline var REPO_ROOT = "testing/libraries"; + static inline var REPO_DIR = "vcs"; + static var CWD:String = null; + + var id:VcsID = null; + var vcsName:String = null; + var url:String = null; + var rev:String = null; + var counter:Int = 0; + + //--------------- constructor ---------------// + + public function new(id:VcsID, vcsName:String, url:String, ?rev:String) + { + super(); + this.id = id; + this.url = url; + this.rev = rev; + this.vcsName = vcsName; + + CWD = Sys.getCwd(); + counter = 0; + } + + + //--------------- initialize ----------------// + + override public function setup():Void + { + Sys.setCwd(CWD + "/" + REPO_ROOT); + + if(!FileSystem.exists(REPO_DIR)) + FileSystem.createDirectory(REPO_DIR); + + Sys.setCwd(REPO_DIR); + } + + override public function tearDown():Void + { + // restore original CWD: + Sys.setCwd(CWD); + } + + //----------------- tests -------------------// + + + public function testGetVcs():Void + { + assertTrue(Vcs.get(id) != null); + assertTrue(Vcs.get(id).name == vcsName); + } + + public function testAvailable():Void + { + assertTrue(getVcs().available); + } + + // --------------- clone --------------- // + + public function testGetVcsByDir():Void + { + var vcs = getVcs(); + testCloneSimple(); + + assertEquals(vcs, Vcs.get(id)); + } + + public function testCloneSimple():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter++; + vcs.clone(dir, url); + + assertTrue(FileSystem.exists(dir)); + assertTrue(FileSystem.isDirectory(dir)); + + assertTrue(FileSystem.exists('$dir/.${vcs.directory}')); + assertTrue(FileSystem.isDirectory('$dir/.${vcs.directory}')); + } + + public function testCloneBranch():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter++; + vcs.clone(dir, url, "develop"); + + assertTrue(FileSystem.exists(dir)); + assertTrue(FileSystem.isDirectory(dir)); + + assertTrue(FileSystem.exists('$dir/.${vcs.directory}')); + assertTrue(FileSystem.isDirectory('$dir/.${vcs.directory}')); + } + + public function testCloneBranchTag_0_9_2():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter++; + vcs.clone(dir, url, "develop", "0.9.2"); + Sys.sleep(3); + assertTrue(FileSystem.exists(dir)); + assertTrue(FileSystem.exists('$dir/.${vcs.directory}')); + + // if that repo "README.md" was added in tag/rev.: "0.9.3" + assertFalse(FileSystem.exists(dir + "/README.md")); + } + + public function testCloneBranchTag_0_9_3():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter++; + vcs.clone(dir, url, "develop", "0.9.3"); + + assertTrue(FileSystem.exists(dir)); + assertTrue(FileSystem.exists('$dir/.${vcs.directory}')); + + // if that repo "README.md" was added in tag/rev.: "0.9.3" + assertTrue(FileSystem.exists(dir + "/README.md")); + } + + public function testCloneBranchRev():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter++; + vcs.clone(dir, url, "develop", rev); + + assertTrue(FileSystem.exists(dir)); + assertTrue(FileSystem.exists('$dir/.${vcs.directory}')); + + // if that repo "README.md" was added in tag/rev.: "0.9.3" + assertFalse(FileSystem.exists(dir + "/README.md")); + } + + + // --------------- update --------------- // + + public function testUpdateBranchTag_0_9_2__toLatest():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter;// increment will do in `testCloneBranchTag_0_9_2` + + testCloneBranchTag_0_9_2(); + assertFalse(FileSystem.exists("README.md")); + + // save CWD: + var cwd = Sys.getCwd(); + Sys.setCwd(cwd + dir); + assertTrue(FileSystem.exists("." + vcs.directory)); + + // in this case `libName` can get any value: + vcs.update("LIBNAME"); + + // Now we get actual version (0.9.3 or newer) with README.md. + assertTrue(FileSystem.exists("README.md")); + + // restore CWD: + Sys.setCwd(cwd); + } + + + public function testUpdateBranchTag_0_9_2__toLatest__afterUserChanges_withReset():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter;// increment will do in `testCloneBranchTag_0_9_2` + + testCloneBranchTag_0_9_2(); + assertFalse(FileSystem.exists("README.md")); + + // save CWD: + var cwd = Sys.getCwd(); + Sys.setCwd(cwd + dir); + + // creating user-changes: + FileSystem.deleteFile("build.hxml"); + File.saveContent("file", "new file \"file\" with content"); + + //Hack: set the default answer: + new Cli().defaultAnswer = Answer.Yes; + + // update to HEAD: + // in this case `libName` can get any value: + vcs.update("LIBNAME"); + + // Now we get actual version (0.9.3 or newer) with README.md. + assertTrue(FileSystem.exists("README.md")); + + // restore CWD: + Sys.setCwd(cwd); + } + + public function testUpdateBranchTag_0_9_2__toLatest__afterUserChanges_withoutReset():Void + { + var vcs = getVcs(); + var dir = vcs.directory + counter;// increment will do in `testCloneBranchTag_0_9_2` + + testCloneBranchTag_0_9_2(); + assertFalse(FileSystem.exists("README.md")); + + // save CWD: + var cwd = Sys.getCwd(); + Sys.setCwd(cwd + dir); + + // creating user-changes: + FileSystem.deleteFile("build.hxml"); + File.saveContent("file", "new file \"file\" with content"); + + //Hack: set the default answer: + new Cli().defaultAnswer = Answer.No; + + // update to HEAD: + // in this case `libName` can get any value: + vcs.update("LIBNAME"); + + // We get no reset and update: + assertTrue(FileSystem.exists("file")); + assertFalse(FileSystem.exists("build.hxml")); + assertFalse(FileSystem.exists("README.md")); + + // restore CWD: + Sys.setCwd(cwd); + } + + //----------------- tools -------------------// + + inline function getVcs():Vcs + { + return Vcs.get(id); + } +} diff --git a/extra/haxelib_src/test/tests/TestVcsNotFound.hx b/extra/haxelib_src/test/tests/TestVcsNotFound.hx new file mode 100644 index 0000000000000000000000000000000000000000..0a259b414c442c8e6ac4c69f685173182d67bc8f --- /dev/null +++ b/extra/haxelib_src/test/tests/TestVcsNotFound.hx @@ -0,0 +1,181 @@ +package tests; + +import sys.FileSystem; +import tools.haxelib.Vcs; +import haxe.unit.TestCase; + + +class TestVcsNotFound extends TestCase +{ + //----------- properties, fields ------------// + + static inline var REPO_ROOT = "testing/libraries"; + static inline var REPO_DIR = "vcs-no"; + static var CWD:String = null; + + //--------------- constructor ---------------// + public function new() + { + super(); + CWD = Sys.getCwd(); + } + + + //--------------- initialize ----------------// + + override public function setup():Void + { + Sys.setCwd(CWD + "/" + REPO_ROOT); + + if(!FileSystem.exists(REPO_DIR)) + FileSystem.createDirectory(REPO_DIR); + + Sys.setCwd(REPO_DIR); + } + + override public function tearDown():Void + { + // restore original CWD & PATH: + Sys.setCwd(CWD); + } + + //----------------- tests -------------------// + + + public function testAvailableHg():Void + { + assertFalse(getHg().available); + } + + public function testAvailableGit():Void + { + assertFalse(getGit().available); + } + + + public function testCloneHg():Void + { + var vcs = getHg(); + try + { + vcs.clone(vcs.directory, "https://bitbucket.org/fzzr/hx.signal"); + assertFalse(true); + } + catch(error:Dynamic) + { + assertTrue(Reflect.isEnumValue(error)); + switch(error) + { + case VcsError.CantCloneRepo(_, repo, stderr): assertTrue(true); + default: assertFalse(true); + } + } + } + + public function testCloneGit():Void + { + var vcs = getGit(); + try + { + vcs.clone(vcs.directory, "https://github.com/fzzr-/hx.signal.git"); + assertFalse(true); + } + catch(error:Dynamic) + { + assertTrue(Reflect.isEnumValue(error)); + switch(error) + { + case VcsError.CantCloneRepo(_, repo, stderr): assertTrue(true); + default: assertFalse(true); + } + } + } + + + //----------------- tools -------------------// + + inline function getHg():Vcs + { + return new WrongHg(); + } + + inline function getGit():Vcs + { + return new WrongGit(); + } +} + + + +class WrongHg extends Mercurial +{ + public function new() + { + super(); + this.directory = "no-hg"; + this.executable = "no-hg"; + this.name = "Mercurial-not-found"; + } + + // copy of Mercurial.searchExecutablebut have a one change - regexp. + override private function searchExecutable():Void + { + super.searchExecutable(); + + if(available) + return; + + // if we have already msys git/cmd in our PATH + var match = ~/(.*)no-hg-no([\\|\/])cmd$/; + for(path in Sys.getEnv("PATH").split(";")) + { + if(match.match(path.toLowerCase())) + { + var newPath = match.matched(1) + executable + match.matched(2) + "bin"; + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + newPath); + } + } + checkExecutable(); + } +} + +class WrongGit extends Git +{ + public function new() + { + super(); + this.directory = "no-git"; + this.executable = "no-git"; + this.name = "Git-not-found"; + } + + // copy of Mercurial.searchExecutablebut have a one change - regexp. + override private function searchExecutable():Void + { + super.searchExecutable(); + + if(available) + return; + + // if we have already msys git/cmd in our PATH + var match = ~/(.*)no-git-no([\\|\/])cmd$/; + for(path in Sys.getEnv("PATH").split(";")) + { + if(match.match(path.toLowerCase())) + { + var newPath = match.matched(1) + executable + match.matched(2) + "bin"; + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + newPath); + } + } + if(checkExecutable()) + return; + // look at a few default paths + for(path in ["C:\\Program Files (x86)\\Git\\bin", "C:\\Progra~1\\Git\\bin"]) + if(FileSystem.exists(path)) + { + Sys.putEnv("PATH", Sys.getEnv("PATH") + ";" + path); + if(checkExecutable()) + return; + } + } +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/PrepareServer.hx b/extra/haxelib_src/testing/PrepareServer.hx new file mode 100644 index 0000000000000000000000000000000000000000..9163b6a3a667779002cb061c00793aac05125d22 --- /dev/null +++ b/extra/haxelib_src/testing/PrepareServer.hx @@ -0,0 +1,131 @@ +package; + +import haxe.crypto.Crc32; +import haxe.io.BytesInput; +import haxe.remoting.HttpConnection; +import haxe.zip.Entry; +import haxe.zip.Writer; +import sys.db.Sqlite; +import sys.FileSystem; +import sys.io.File; +import tools.haxelib.SiteDb; + +using StringTools; + +class SiteProxy extends haxe.remoting.Proxy { +} + +class PrepareServer { + + + static function deleteFolderContent(path:String) { + for (file in FileSystem.readDirectory(path)) { + var fullPath = path + '/' + file; + if (FileSystem.isDirectory(fullPath)) { + deleteFolderContent(fullPath); + FileSystem.deleteDirectory(fullPath); + } + else { + FileSystem.deleteFile(fullPath); + } + } + } + + static function getFileList(path:String):List { + var list = new List(); + for (file in FileSystem.readDirectory(path)) { + if (FileSystem.isDirectory(path + '/' + file)) { + for (sFile in getFileList(path + '/' + file)) { + list.add(file + '/' + sFile); + } + } + else { + list.add(file); + } + } + return list; + } + + static function packageLibrary(path:String) { + var files = getFileList(path); + var fileName = path + '.zip'; + if (FileSystem.exists(fileName)) + FileSystem.deleteFile(fileName); + var output = File.write(path + '.zip', true); + var writer = new Writer(output); + var entries = new List(); + for (file in files) { + var data = File.getBytes(path + '/' + file); + entries.add({ + fileTime: Date.now(), + compressed: false, + data: data, + crc32: Crc32.make(data), + dataSize: data.length, + fileName: file, + fileSize: 0 + }); + } + writer.write(entries); + output.flush(); + output.close(); + + } + + static function main() { + Sys.println("Cleaning up folders"); + var serverPath = Sys.getCwd() + 'server/'; + if (FileSystem.exists(serverPath + 'files') && FileSystem.isDirectory(serverPath + 'files')) + deleteFolderContent(serverPath + 'files'); + if (FileSystem.exists(serverPath + 'tmp') && FileSystem.isDirectory(serverPath + 'tmp')) + deleteFolderContent(serverPath + 'tmp'); + + Sys.println("Cleaning legacy DB"); + var sqlFile = serverPath + 'legacy/haxelib.db'; + var con = Sqlite.open(sqlFile); + tools.legacyhaxelib.SiteDb.create(con); + + Sys.println("Package testing libraries"); + var libraries = new List(); + var testFolder = Sys.getCwd() + 'testing/'; + for (file in FileSystem.readDirectory(testFolder + 'libraries')) { + if (FileSystem.isDirectory(testFolder + 'libraries/' + file) && file.startsWith('lib')) { + packageLibrary(testFolder + 'libraries/' + file); + Sys.println("Packaged libray: " + file.substr(3)); + libraries.push(file.substr(3)); + } + } + + Sys.println("Submitting test libraries"); + try { + var sites = [ + 'legacy' => 'http://localhost:2000/', + '2.0.0-rc' => 'http://localhost:2000/api/2.0.0-rc/', + ]; + for (siteName in sites.keys()) { + trace('Test $siteName on ' + sites.get(siteName)); + var site = new SiteProxy(HttpConnection.urlConnect(sites.get(siteName)).api); + for (library in libraries) { + Sys.println("Submitting library: " + library); + site.register(library, library, library+'@example.org', library + ' Developer'); + // TODO: This is not how haxelib usually behave, do we need dependencies checks and all the other stuff? + site.checkDeveloper(library, library); + var libraryFile = testFolder + 'libraries/lib' + library + '.zip'; + var data = File.getBytes(libraryFile); + var id = site.getSubmitId(); + var h = new haxe.Http('http://localhost:2000/'); + h.fileTransfert("file", id, new BytesInput(data), data.length); + h.request(true); + site.processSubmit(id, library, library); + //FileSystem.deleteFile(libraryFile); + } + } + } + catch (e:Dynamic) { + Sys.println("There was a problem submitting test libraries to the local haxelib server. Make sure it is running."); + Sys.println(e); + Sys.exit(1); + } + + } +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/installSeveral.hxml b/extra/haxelib_src/testing/installSeveral.hxml new file mode 100644 index 0000000000000000000000000000000000000000..f3768e5da78bc42c3e8a0edd73c06f8a6a6e1f37 --- /dev/null +++ b/extra/haxelib_src/testing/installSeveral.hxml @@ -0,0 +1,3 @@ +-lib hxcpp +-lib hxcs +-lib hxjava diff --git a/extra/haxelib_src/testing/libraries/libBar/bar/Bar.hx b/extra/haxelib_src/testing/libraries/libBar/bar/Bar.hx new file mode 100644 index 0000000000000000000000000000000000000000..2936374c09fd9ec3ac752b23c93de783ce5e94fc --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libBar/bar/Bar.hx @@ -0,0 +1,9 @@ +package bar; + +class Bar { + + static function new() { + trace("new Bar"); + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/libraries/libBar/haxelib.json b/extra/haxelib_src/testing/libraries/libBar/haxelib.json new file mode 100644 index 0000000000000000000000000000000000000000..a591758094b75f9ceb5705727da887b0ffa5602e --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libBar/haxelib.json @@ -0,0 +1,10 @@ +{ + "name": "Bar", + "url" : "http://example.org", + "license": "GPL", + "tags": ["bar", "test"], + "description": "This project is an example of an haxelib project", + "version": "1.0.0", + "releasenote": "Initial release, everything is working correctly", + "contributors": ["Bar"] +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/libraries/libBar/haxelib.xml b/extra/haxelib_src/testing/libraries/libBar/haxelib.xml new file mode 100644 index 0000000000000000000000000000000000000000..476a4920c7efc04f3b616b3a8d0759e73c4fcfc0 --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libBar/haxelib.xml @@ -0,0 +1,7 @@ + + + + + This project is an example of an haxelib project + Initial release, everything is working correctly + \ No newline at end of file diff --git a/extra/haxelib_src/testing/libraries/libFoo/foo/Foo.hx b/extra/haxelib_src/testing/libraries/libFoo/foo/Foo.hx new file mode 100644 index 0000000000000000000000000000000000000000..1ecc074b8a1c982050e959ac06ee3ee4203acdbb --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libFoo/foo/Foo.hx @@ -0,0 +1,9 @@ +package foo; + +class Foo { + + public function new() { + trace("new Foo"); + } + +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/libraries/libFoo/haxelib.json b/extra/haxelib_src/testing/libraries/libFoo/haxelib.json new file mode 100644 index 0000000000000000000000000000000000000000..38f9bb072ed7c7dca1160bc8368e0ab5747fe01d --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libFoo/haxelib.json @@ -0,0 +1,13 @@ +{ + "name": "Foo", + "url" : "http://example.org", + "license": "GPL", + "tags": ["foo", "test"], + "description": "This project is an example of an haxelib project", + "version": "0.1.0-alpha.0", + "releasenote": "Initial release, everything is working correctly", + "dependencies": { + "bar": "" + }, + "contributors": ["Foo"] +} \ No newline at end of file diff --git a/extra/haxelib_src/testing/libraries/libFoo/haxelib.xml b/extra/haxelib_src/testing/libraries/libFoo/haxelib.xml new file mode 100644 index 0000000000000000000000000000000000000000..53ff84c9089fc21f51a2c8d15ee3be848b6efb6f --- /dev/null +++ b/extra/haxelib_src/testing/libraries/libFoo/haxelib.xml @@ -0,0 +1,7 @@ + + + + + This project is an example of an haxelib project + Initial release, everything is working correctly + \ No newline at end of file diff --git a/extra/haxeserver.bat b/extra/haxeserver.bat new file mode 100644 index 0000000000000000000000000000000000000000..7df09401aeccc1b7f9db9ecac646b15f402669c8 --- /dev/null +++ b/extra/haxeserver.bat @@ -0,0 +1,3 @@ +@echo off +nekotools server -p 2000 -h localhost -d .\ +pause \ No newline at end of file diff --git a/doc/images/Banner.bmp b/extra/images/Banner.bmp similarity index 100% rename from doc/images/Banner.bmp rename to extra/images/Banner.bmp diff --git a/doc/images/Wizard.bmp b/extra/images/Wizard.bmp similarity index 100% rename from doc/images/Wizard.bmp rename to extra/images/Wizard.bmp diff --git a/doc/installer.nsi b/extra/installer.nsi similarity index 87% rename from doc/installer.nsi rename to extra/installer.nsi index c8d1481974edff744a8848306d3ed24aae24dbd6..36f843b94cdd339770699db61c265d7b4a737c50 100644 --- a/doc/installer.nsi +++ b/extra/installer.nsi @@ -1,183 +1,190 @@ -; Haxe/Neko Install script - -;-------------------------------- - -!include "MUI.nsh" -!include "LogicLib.nsh" -!include "WordFunc.nsh" -!include "winmessages.nsh" -!include "EnvVarUpdate.nsh" - -;-------------------------------- - -; Define version info -!define VERSION "3.0.0" - -; Define Neko info -!define NEKO_VERSION "2.0.0" - -; Installer details -VIAddVersionKey "CompanyName" "Haxe Foundation" -VIAddVersionKey "ProductName" "Haxe Installer" -VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2013" -VIAddVersionKey "FileDescription" "Haxe Installer" -VIAddVersionKey "ProductVersion" "${VERSION}.0" -VIAddVersionKey "FileVersion" "${VERSION}.0" -VIProductVersion "${VERSION}.0" - -; The name of the installer -Name "Haxe ${VERSION}" - -; The captions of the installer -Caption "Haxe ${VERSION} Setup" -UninstallCaption "Haxe ${VERSION} Uninstall" - -; The file to write -OutFile "haxe-${VERSION}-win.exe" - -; Default installation folder -InstallDir "C:\HaxeToolkit\" - -; Define executable files -!define EXECUTABLE "$INSTDIR\haxe\haxe.exe" -!define HaxeLIB "$INSTDIR\Haxe\haxelib.exe" -!define NEKOEXE "$INSTDIR\neko\neko.exe" - -; Vista redirects $SMPROGRAMS to all users without this -RequestExecutionLevel admin - -; Use replace and version compare -!insertmacro WordReplace -!insertmacro VersionCompare - -; Required props -SetFont /LANG=${LANG_ENGLISH} "Tahoma" 8 -SetCompressor /SOLID lzma -CRCCheck on -XPStyle on - -;-------------------------------- - -; Interface Configuration - -!define MUI_HEADERIMAGE -!define MUI_ABORTWARNING -!define MUI_HEADERIMAGE_BITMAP "images\Banner.bmp" -!define MUI_WELCOMEFINISHPAGE_BITMAP "images\Wizard.bmp" -!define MUI_UNWELCOMEFINISHPAGE_BITMAP "images\Wizard.bmp" -!define MUI_PAGE_HEADER_SUBTEXT "Please view the license before installing Haxe ${VERSION}." -!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of $(^NameDA).\r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without having to reboot your computer.\r\n\r\n$_CLICK" - -;-------------------------------- - -; Pages - -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_WELCOME -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_COMPONENTS -!insertmacro MUI_UNPAGE_INSTFILES -!insertmacro MUI_UNPAGE_FINISH -!insertmacro MUI_LANGUAGE "English" - -;-------------------------------- - -; InstallTypes - -InstType "Default" -InstType "un.Default" -InstType "un.Full" - -;-------------------------------- - -; Functions - - - -Function .onInit - - - -FunctionEnd - -;-------------------------------- - -; Install Sections - -!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' -!define env_hkcu 'HKCU "Environment"' - -Section "Haxe ${VERSION}" Main - - SectionIn 1 2 RO - SetOverwrite on - - SetOutPath "$INSTDIR\haxe" - - File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\haxe\*.*" - - ExecWait "$INSTDIR\haxe\haxesetup.exe -silent" - - WriteUninstaller "$INSTDIR\Uninstall.exe" - -SectionEnd - -Section "Neko ${NEKO_VERSION}" Neko - - SectionIn 1 2 - SetOverwrite on - - SetOutPath "$INSTDIR\neko" - - File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\neko\*.*" - -SectionEnd - - - - -;-------------------------------- - -; Install section strings - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN -!insertmacro MUI_DESCRIPTION_TEXT ${Main} "Installs Haxe and other core files." -!insertmacro MUI_DESCRIPTION_TEXT ${Neko} "Installs Neko, which is required by various Haxe tools." -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -;-------------------------------- - -; Uninstall Sections - -Section "un.Haxe" UninstMain - - RMDir /r "$INSTDIR\haxe" - ${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "%HAXEPATH%" - DeleteRegValue ${env_hkcu} HAXEPATH - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - -SectionEnd - -Section "un.Neko" UninstNeko - - RMDir /r "$INSTDIR\neko" - ${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "%NEKO_INSTPATH%" - DeleteRegValue ${env_hkcu} NEKO_INSTPATH - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - -SectionEnd - -;-------------------------------- - -; Uninstall section strings - -!insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN -!insertmacro MUI_DESCRIPTION_TEXT ${UninstMain} "Uninstalls Haxe and other core files." -!insertmacro MUI_DESCRIPTION_TEXT ${UninstNeko} "Uninstalls Neko." -!insertmacro MUI_UNFUNCTION_DESCRIPTION_END - -;-------------------------------- +; Haxe/Neko Install script +; Instructions: +; - put haxe files in resources/haxe +; - put neko files in resources/neko +; - run + +;-------------------------------- + +!include "MUI.nsh" +!include "LogicLib.nsh" +!include "WordFunc.nsh" +!include "winmessages.nsh" +!include "EnvVarUpdate.nsh" + +;-------------------------------- + +; Define version info +!define VERSION "%%VERSION%%" +!define VERSTRING "%%VERSTRING%%" +!define VERLONG "%%VERLONG%%" + +; Define Neko info +!define NEKO_VERSION "2.0.0" + +; Installer details +VIAddVersionKey "CompanyName" "Haxe Foundation" +VIAddVersionKey "ProductName" "Haxe Installer" +VIAddVersionKey "LegalCopyright" "Haxe Foundation 2005-2013" +VIAddVersionKey "FileDescription" "Haxe Installer" +VIAddVersionKey "ProductVersion" "${VERSION}.0" +VIAddVersionKey "FileVersion" "${VERSION}.0" +VIProductVersion "${VERSION}.0" + +; The name of the installer +Name "Haxe ${VERSTRING}" + +; The captions of the installer +Caption "Haxe ${VERLONG} Setup" +UninstallCaption "Haxe ${VERLONG} Uninstall" + +; The file to write +OutFile "haxe-${VERSTRING}-win.exe" + +; Default installation folder +InstallDir "C:\HaxeToolkit\" + +; Define executable files +!define EXECUTABLE "$INSTDIR\haxe\haxe.exe" +!define HaxeLIB "$INSTDIR\Haxe\haxelib.exe" +!define NEKOEXE "$INSTDIR\neko\neko.exe" + +; Vista redirects $SMPROGRAMS to all users without this +RequestExecutionLevel admin + +; Use replace and version compare +!insertmacro WordReplace +!insertmacro VersionCompare + +; Required props +SetFont /LANG=${LANG_ENGLISH} "Tahoma" 8 +SetCompressor /SOLID lzma +CRCCheck on +XPStyle on + +;-------------------------------- + +; Interface Configuration + +!define MUI_HEADERIMAGE +!define MUI_ABORTWARNING +!define MUI_HEADERIMAGE_BITMAP "images\Banner.bmp" +!define MUI_WELCOMEFINISHPAGE_BITMAP "images\Wizard.bmp" +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "images\Wizard.bmp" +!define MUI_PAGE_HEADER_SUBTEXT "Please view the license before installing Haxe ${VERLONG}." +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of $(^NameDA).\r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without having to reboot your computer.\r\n\r\n$_CLICK" + +;-------------------------------- + +; Pages + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_COMPONENTS +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH +!insertmacro MUI_LANGUAGE "English" + +;-------------------------------- + +; InstallTypes + +InstType "Default" +InstType "un.Default" +InstType "un.Full" + +;-------------------------------- + +; Functions + + + +Function .onInit + + + +FunctionEnd + +;-------------------------------- + +; Install Sections + +!define env_hklm 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' +!define env_hkcu 'HKCU "Environment"' + +Section "Haxe ${VERSION}" Main + + SectionIn 1 2 RO + SetOverwrite on + + RMDir /r /REBOOTOK "$INSTDIR\haxe\std" + SetOutPath "$INSTDIR\haxe" + + File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\haxe\*.*" + + ExecWait "$INSTDIR\haxe\haxesetup.exe -silent" + + WriteUninstaller "$INSTDIR\Uninstall.exe" + +SectionEnd + +Section "Neko ${NEKO_VERSION}" Neko + + SectionIn 1 2 + SetOverwrite on + + SetOutPath "$INSTDIR\neko" + + File /r /x .svn /x *.db /x Exceptions.log /x .local /x .multi /x *.pdb /x *.vshost.exe /x *.vshost.exe.config /x *.vshost.exe.manifest "resources\neko\*.*" + +SectionEnd + + + + +;-------------------------------- + +; Install section strings + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN +!insertmacro MUI_DESCRIPTION_TEXT ${Main} "Installs Haxe and other core files." +!insertmacro MUI_DESCRIPTION_TEXT ${Neko} "Installs Neko, which is required by various Haxe tools." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- + +; Uninstall Sections + +Section "un.Haxe" UninstMain + + RMDir /r "$INSTDIR\haxe" + ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "%HAXEPATH%" + DeleteRegValue ${env_hklm} HAXEPATH + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + +SectionEnd + +Section "un.Neko" UninstNeko + + RMDir /r "$INSTDIR\neko" + ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "%NEKO_INSTPATH%" + DeleteRegValue ${env_hklm} NEKO_INSTPATH + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + +SectionEnd + +;-------------------------------- + +; Uninstall section strings + +!insertmacro MUI_UNFUNCTION_DESCRIPTION_BEGIN +!insertmacro MUI_DESCRIPTION_TEXT ${UninstMain} "Uninstalls Haxe and other core files." +!insertmacro MUI_DESCRIPTION_TEXT ${UninstNeko} "Uninstalls Neko." +!insertmacro MUI_UNFUNCTION_DESCRIPTION_END + +;-------------------------------- diff --git a/extra/osx_installer_template.zip b/extra/osx_installer_template.zip new file mode 100644 index 0000000000000000000000000000000000000000..1b136f1e903c7d10911d75c129fe1c61f7ca0a2f Binary files /dev/null and b/extra/osx_installer_template.zip differ diff --git a/extra/release-checklist.txt b/extra/release-checklist.txt new file mode 100644 index 0000000000000000000000000000000000000000..32b00d641011d1f72a1f8580dffecfc1f2f69336 --- /dev/null +++ b/extra/release-checklist.txt @@ -0,0 +1,31 @@ +# Preparing related projects + +- 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 + +# Building the binaries and installers + +- Make sure CHANGES.txt has a proper date set! +- Make sure `version` in main.ml has the correct value. +- Merge development branch into master. +- Wait for Travis to greenlight master. +- Tag master as MAJOR.MINOR.PATCH. +- Wait for builds.haxe.org to build master. +- Get https://github.com/waneck/hxbuilds/tree/master/release-helper +- Run it with the fileName corresponding to the latest master file name on builds.haxe.org. + +# Making the release + +- Push the generated binaries and installers to haxe.org. +- Copy relevant changelog part to CHANGES.md. +- Write announcement post. +- Copy announcement post to RELEASE.md. +- Update versions.json + +# Announcing the release + +- Update Github README page. +- Regenerate and upload API documentation. +- Update http://haxe.org/file/CHANGES.txt +- Post announcement post to haxelang. diff --git a/doc/release.neko b/extra/release.neko similarity index 90% rename from doc/release.neko rename to extra/release.neko index ac37abc218dc23c05e174e3d843b507e0143f6fa..d1d2083914da9a02753adf4d2d378e0acf0ecfe1 100644 --- a/doc/release.neko +++ b/extra/release.neko @@ -54,7 +54,7 @@ chdir(dir+"/std/tools"); chdir("haxedoc"); cmd("haxe haxedoc.hxml"); -cmd(curdir+"haxedoc -v \"../../../../flash8.xml;flash8;flash\" \"../../../../neko.xml;neko\" \"../../../../js.xml;js\" \"../../../../flash9.xml;flash\" \"../../../../php.xml;php\" \"../../../../cpp.xml;cpp\""); +cmd(curdir+"haxedoc -v \"../../../../neko.xml;neko\" \"../../../../js.xml;js\" \"../../../../flash9.xml;flash\" \"../../../../php.xml;php\" \"../../../../cpp.xml;cpp\""); cmd("mv index.html content ../../../doc"); cmd("mv haxedoc"+binext+" ../../.."); chdir(".."); diff --git a/doc/setup.cpp b/extra/setup.cpp similarity index 86% rename from doc/setup.cpp rename to extra/setup.cpp index 97e1ee4fa7966787f0e591cbbab873fc526c8572..0bdeeb9e2fcb23db78509bc7285e1e244ff6b910 100644 --- a/doc/setup.cpp +++ b/extra/setup.cpp @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -// this is a small program that do basic haXe setup on Windows +// this is a small program that do basic Haxe setup on Windows #include static void Set( HKEY k, const char *name, DWORD t, const char *data ) { @@ -42,7 +42,7 @@ int WINAPI WinMain( HINSTANCE inst, HINSTANCE prev, LPSTR lpCmdLine, int nCmdSho DWORD ksize = 16000; char *kdata = new char[16000]; memset(kdata,0,ksize); - RegOpenKey(HKEY_CURRENT_USER,"Environment",&k); + RegOpenKey(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",&k); RegQueryValueEx(k,"PATH",NULL,&ktype,(LPBYTE)kdata,&ksize); if( strstr(kdata,"%HAXEPATH%") == NULL ) { char *s = kdata + strlen(kdata); @@ -64,9 +64,9 @@ int WINAPI WinMain( HINSTANCE inst, HINSTANCE prev, LPSTR lpCmdLine, int nCmdSho DWORD unused; SendMessageTimeout(HWND_BROADCAST,WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 5000, &unused ); - delete kdata; - // register - if( strcmp(lpCmdLine,"-silent") != 0 ) - MessageBox(NULL,"Setup completed, you can start using haXe now","haxesetup",MB_OK | MB_ICONINFORMATION); + // delete kdata; + // // register + // if( strcmp(lpCmdLine,"-silent") != 0 ) + // MessageBox(NULL,"Setup completed, you can start using Haxe now","haxesetup",MB_OK | MB_ICONINFORMATION); return 0; } diff --git a/extra/setup.sln b/extra/setup.sln new file mode 100644 index 0000000000000000000000000000000000000000..99eeadeb9ca617f6df892fed7bdf1cc4da833e87 --- /dev/null +++ b/extra/setup.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setup", "setup.vcproj", "{6E869222-35FF-4BC0-B5AA-E63BCB8803A6}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Debug.ActiveCfg = Debug|Win32 + {6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Debug.Build.0 = Debug|Win32 + {6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Release.ActiveCfg = Release|Win32 + {6E869222-35FF-4BC0-B5AA-E63BCB8803A6}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/extra/setup.vcproj b/extra/setup.vcproj new file mode 100644 index 0000000000000000000000000000000000000000..11deff2037d5db9e80067a0b8965d9ac4c552aa9 --- /dev/null +++ b/extra/setup.vcproj @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filters.ml b/filters.ml new file mode 100644 index 0000000000000000000000000000000000000000..a8d557e4f7a406bcabcbe0793889024294d25aa5 --- /dev/null +++ b/filters.ml @@ -0,0 +1,1207 @@ +open Ast +open Common +open Type +open Typecore + +(* PASS 1 begin *) + +let rec verify_ast e = match e.eexpr with + | TField(_) -> + () + | TTypeExpr(TClassDecl {cl_kind = KAbstractImpl a}) when not (Meta.has Meta.RuntimeValue a.a_meta) -> + error "Cannot use abstract as value" e.epos + | _ -> + Type.iter verify_ast e + +(* + Wraps implicit blocks in TIf, TFor, TWhile, TFunction and TTry with real ones +*) +let rec blockify_ast e = + match e.eexpr with + | TIf(e1,e2,eo) -> + {e with eexpr = TIf(blockify_ast e1,mk_block (blockify_ast e2),match eo with None -> None | Some e -> Some (mk_block (blockify_ast e)))} + | TFor(v,e1,e2) -> + {e with eexpr = TFor(v,blockify_ast e1,mk_block (blockify_ast e2))} + | TWhile(e1,e2,flag) -> + {e with eexpr = TWhile(blockify_ast e1,mk_block (blockify_ast e2),flag)} + | TFunction tf -> + {e with eexpr = TFunction {tf with tf_expr = mk_block (blockify_ast tf.tf_expr)}} + | TTry(e1,cl) -> + {e with eexpr = TTry(mk_block (blockify_ast e1),List.map (fun (v,e) -> v,mk_block (blockify_ast e)) cl)} + | TSwitch(e1,cases,def) -> + let e1 = blockify_ast e1 in + let cases = List.map (fun (el,e) -> + el,mk_block (blockify_ast e) + ) cases in + let def = match def with None -> None | Some e -> Some (mk_block (blockify_ast e)) in + {e with eexpr = TSwitch(e1,cases,def)} + | _ -> + Type.map_expr blockify_ast e + +(* + Pushes complex right-hand side expression inwards. + + return { exprs; value; } -> { exprs; return value; } + x = { exprs; value; } -> { exprs; x = value; } + var x = { exprs; value; } -> { var x; exprs; x = value; } +*) +let promote_complex_rhs com e = + let rec is_complex e = match e.eexpr with + | TBlock _ | TSwitch _ | TIf _ | TTry _ | TCast(_,Some _) -> true + | TBinop(_,e1,e2) -> is_complex e1 || is_complex e2 + | TParenthesis e | TMeta(_,e) | TCast(e, None) | TField(e,_) -> is_complex e + | _ -> false + in + let rec loop f e = match e.eexpr with + | TBlock(el) -> + begin match List.rev el with + | elast :: el -> {e with eexpr = TBlock(block (List.rev ((loop f elast) :: el)))} + | [] -> e + end + | TSwitch(es,cases,edef) -> + {e with eexpr = TSwitch(es,List.map (fun (el,e) -> List.map find el,loop f e) cases,match edef with None -> None | Some e -> Some (loop f e)); } + | TIf(eif,ethen,eelse) -> + {e with eexpr = TIf(find eif, loop f ethen, match eelse with None -> None | Some e -> Some (loop f e)); } + | TTry(e1,el) -> + {e with eexpr = TTry(loop f e1, List.map (fun (el,e) -> el,loop f e) el); } + | TParenthesis e1 when not (Common.defined com Define.As3) -> + {e with eexpr = TParenthesis(loop f e1)} + | TMeta(m,e1) -> + { e with eexpr = TMeta(m,loop f e1)} + | TReturn _ | TThrow _ -> + find e + | TContinue | TBreak -> + e + | _ -> + f (find e) + and block el = + let r = ref [] in + List.iter (fun e -> + match e.eexpr with + | TVar(v,eo) -> + begin match eo with + | Some e when is_complex e -> + let e = find e in + r := (loop (fun e -> mk (TBinop(OpAssign,mk (TLocal v) v.v_type e.epos,e)) v.v_type e.epos) e) + :: ((mk (TVar (v,None)) com.basic.tvoid e.epos)) + :: !r + | Some e -> + r := (mk (TVar (v,Some (find e))) com.basic.tvoid e.epos) :: !r + | None -> r := (mk (TVar (v,None)) com.basic.tvoid e.epos) :: !r + end + | TReturn (Some e1) when (match follow e1.etype with TAbstract({a_path=[],"Void"},_) -> true | _ -> false) -> + r := ({e with eexpr = TReturn None}) :: e1 :: !r + | _ -> r := (find e) :: !r + ) el; + List.rev !r + and find e = match e.eexpr with + | TReturn (Some e1) -> loop (fun er -> {e with eexpr = TReturn (Some er)}) e1 + | TBinop(OpAssign | OpAssignOp _ as op, ({eexpr = TLocal _ | TField _ | TArray _} as e1), e2) -> loop (fun er -> {e with eexpr = TBinop(op, e1, er)}) e2 + | TBlock(el) -> {e with eexpr = TBlock (block el)} + | _ -> Type.map_expr find e + in + find e + +(* Adds final returns to functions as required by some platforms *) +let rec add_final_return e = + let rec loop e t = + let def_return p = + let c = (match follow t with + | TAbstract ({ a_path = [],"Int" },_) -> TInt 0l + | TAbstract ({ a_path = [],"Float" },_) -> TFloat "0." + | TAbstract ({ a_path = [],"Bool" },_) -> TBool false + | _ -> TNull + ) in + { eexpr = TReturn (Some { eexpr = TConst c; epos = p; etype = t }); etype = t; epos = p } + in + match e.eexpr with + | TBlock el -> + (match List.rev el with + | [] -> e + | elast :: el -> + match loop elast t with + | { eexpr = TBlock el2 } -> { e with eexpr = TBlock ((List.rev el) @ el2) } + | elast -> { e with eexpr = TBlock (List.rev (elast :: el)) }) + | TReturn _ -> + e + | _ -> + { e with eexpr = TBlock [e;def_return e.epos] } + in + + let e = Type.map_expr add_final_return e in + + match e.eexpr with + | TFunction f -> + let f = (match follow f.tf_type with + | TAbstract ({ a_path = [],"Void" },[]) -> f + | t -> { f with tf_expr = loop f.tf_expr t } + ) in + { e with eexpr = TFunction f } + | _ -> e + +let rec wrap_js_exceptions com e = + let rec is_error t = + match follow t with + | TInst ({cl_path = (["js"],"Error")},_) -> true + | TInst ({cl_super = Some (csup,tl)}, _) -> is_error (TInst (csup,tl)) + | _ -> false + in + let rec loop e = + match e.eexpr with + | TThrow eerr when not (is_error eerr.etype) -> + let terr = List.find (fun mt -> match mt with TClassDecl {cl_path = ["js";"_Boot"],"HaxeError"} -> true | _ -> false) com.types in + let cerr = match terr with TClassDecl c -> c | _ -> assert false in + let ewrap = { eerr with eexpr = TNew (cerr,[],[eerr]) } in + { e with eexpr = TThrow ewrap } + | _ -> + Type.map_expr loop e + in + + loop e + +(* -------------------------------------------------------------------------- *) +(* CHECK LOCAL VARS INIT *) + +let check_local_vars_init e = + let intersect vl1 vl2 = + PMap.mapi (fun v t -> t && PMap.find v vl2) vl1 + in + let join vars cvars = + List.iter (fun v -> vars := intersect !vars v) cvars + in + let restore vars old_vars declared = + (* restore variables declared in this block to their previous state *) + vars := List.fold_left (fun acc v -> + try PMap.add v (PMap.find v old_vars) acc with Not_found -> PMap.remove v acc + ) !vars declared; + in + let declared = ref [] in + let rec loop vars e = + match e.eexpr with + | TLocal v -> + let init = (try PMap.find v.v_id !vars with Not_found -> true) in + if not init 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 + end + | TVar (v,eo) -> + begin + match eo with + | None -> + declared := v.v_id :: !declared; + vars := PMap.add v.v_id false !vars + | Some e -> + loop vars e + end + | TBlock el -> + let old = !declared in + let old_vars = !vars in + declared := []; + List.iter (loop vars) el; + restore vars old_vars (List.rev !declared); + declared := old; + | TBinop (OpAssign,{ eexpr = TLocal v },e) when PMap.mem v.v_id !vars -> + loop vars e; + vars := PMap.add v.v_id true !vars + | TIf (e1,e2,eo) -> + loop vars e1; + let vbase = !vars in + loop vars e2; + (match eo with + | None -> vars := vbase + (* ignore else false cases (they are added by the side-effect handler) *) + | Some {eexpr = TConst (TBool(false))} -> () + | Some e -> + let v1 = !vars in + vars := vbase; + loop vars e; + vars := intersect !vars v1) + | TWhile (cond,e,flag) -> + (match flag with + | NormalWhile when (match cond.eexpr with TParenthesis {eexpr = TConst (TBool true)} -> false | _ -> true) -> + loop vars cond; + let old = !vars in + loop vars e; + vars := old; + | _ -> + loop vars e; + loop vars cond) + | TTry (e,catches) -> + let cvars = List.map (fun (v,e) -> + let old = !vars in + loop vars e; + let v = !vars in + vars := old; + v + ) catches in + loop vars e; + join vars cvars; + | TSwitch (e,cases,def) -> + loop vars e; + let cvars = List.map (fun (ec,e) -> + let old = !vars in + List.iter (loop vars) ec; + vars := old; + loop vars e; + let v = !vars in + vars := old; + v + ) cases in + (match def with + | None when (match e.eexpr with TMeta((Meta.Exhaustive,_,_),_) | TParenthesis({eexpr = TMeta((Meta.Exhaustive,_,_),_)}) -> true | _ -> false) -> + (match cvars with + | cv :: cvars -> + PMap.iter (fun i b -> if b then vars := PMap.add i b !vars) cv; + join vars cvars + | [] -> ()) + | None -> () + | Some e -> + loop vars e; + join vars cvars) + (* mark all reachable vars as initialized, since we don't exit the block *) + | TBreak | TContinue | TReturn None -> + vars := PMap.map (fun _ -> true) !vars + | TThrow e | TReturn (Some e) -> + loop vars e; + vars := PMap.map (fun _ -> true) !vars + | _ -> + Type.iter (loop vars) e + in + loop (ref PMap.empty) e; + e + +(* -------------------------------------------------------------------------- *) +(* BLOCK VARIABLES CAPTURE *) + +(* + For some platforms, it will simply mark the variables which are used in closures + using the v_capture flag so it can be processed in a more optimized + + For Flash/JS platforms, it will ensure that variables used in loop sub-functions + have an unique scope. It transforms the following expression : + + for( x in array ) + funs.push(function() return x++); + + Into the following : + + for( _x in array ) { + var x = [_x]; + funs.push(function(x) { function() return x[0]++; }(x)); + } +*) + +type usage = + | Block of ((usage -> unit) -> unit) + | Loop of ((usage -> unit) -> unit) + | Function of ((usage -> unit) -> unit) + | Declare of tvar + | Use of tvar + | Assign of tvar + +let rec local_usage f e = + match e.eexpr with + | TBinop ((OpAssign | OpAssignOp _), { eexpr = TLocal v }, e2) -> + local_usage f e2; + f (Assign v) + | TUnop ((Increment | Decrement), _, { eexpr = TLocal v }) -> + f (Assign v) + | TLocal v -> + f (Use v) + | TVar (v,eo) -> + (match eo with None -> () | Some e -> local_usage f e); + f (Declare v); + | TFunction tf -> + let cc f = + List.iter (fun (v,_) -> f (Declare v)) tf.tf_args; + local_usage f tf.tf_expr; + in + f (Function cc) + | TBlock l -> + f (Block (fun f -> List.iter (local_usage f) l)) + | TFor (v,it,e) -> + local_usage f it; + f (Loop (fun f -> + f (Declare v); + local_usage f e; + )) + | TWhile _ -> + f (Loop (fun f -> + iter (local_usage f) e + )) + | TTry (e,catchs) -> + local_usage f e; + List.iter (fun (v,e) -> + f (Block (fun f -> + f (Declare v); + local_usage f e; + )) + ) catchs; + | _ -> + iter (local_usage f) e + +let captured_vars com e = + + let t = com.basic in + + let impl = match com.platform with + (* optimized version for C#/Java - use native arrays *) + | Cs | Java -> + let cnativearray = + match (List.find (fun md -> match md with + | TClassDecl ({ cl_path = ["cs"|"java"],"NativeArray" }) -> true + | _ -> false + ) com.types) + with TClassDecl cl -> cl | _ -> assert false + in + + object + method captured_type t = TInst (cnativearray,[t]) + + method mk_ref v ve p = + 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 + mk (TNew (cnativearray,[t],[eone])) v.v_type p + | Some e -> + { (Optimizer.mk_untyped_call "__array__" p [e]) with etype = v.v_type } + + method mk_ref_access e v = + mk (TArray ({ e with etype = v.v_type }, mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos + + method mk_init av v pos = + let elocal = mk (TLocal v) v.v_type pos in + let earray = { (Optimizer.mk_untyped_call "__array__" pos [elocal]) with etype = av.v_type } in + mk (TVar (av,Some earray)) t.tvoid pos + end + (* default implementation - use haxe array *) + | _ -> + object + method captured_type = t.tarray + method mk_ref v ve p = + mk (TArrayDecl (match ve with None -> [] | Some e -> [e])) v.v_type p + method mk_ref_access e v = + mk (TArray ({ e with etype = v.v_type }, mk (TConst (TInt 0l)) t.tint e.epos)) e.etype e.epos + method mk_init av v pos = + mk (TVar (av,Some (mk (TArrayDecl [mk (TLocal v) v.v_type pos]) av.v_type pos))) t.tvoid pos + end + in + + let mk_var v used = + let v2 = alloc_var v.v_name (PMap.find v.v_id used) in + v2.v_meta <- v.v_meta; + v2 + in + + let rec wrap used e = + match e.eexpr with + | TVar (v,ve) -> + let v,ve = + if PMap.mem v.v_id used then + v, Some (impl#mk_ref v (Option.map (wrap used) ve) e.epos) + else + v, (match ve with None -> None | Some e -> Some (wrap used e)) + in + { e with eexpr = TVar (v,ve) } + | TLocal v when PMap.mem v.v_id used -> + impl#mk_ref_access e v + | TFor (v,it,expr) when PMap.mem v.v_id used -> + let vtmp = mk_var v used in + let it = wrap used it in + let expr = wrap used expr in + mk (TFor (vtmp,it,Type.concat (impl#mk_init v vtmp e.epos) expr)) e.etype e.epos + | TTry (expr,catchs) -> + let catchs = List.map (fun (v,e) -> + let e = wrap used e in + try + let vtmp = mk_var v used in + vtmp, Type.concat (impl#mk_init v vtmp e.epos) e + with Not_found -> + v, e + ) catchs in + mk (TTry (wrap used expr,catchs)) e.etype e.epos + | TFunction f -> + (* + list variables that are marked as used, but also used in that + function and which are not declared inside it ! + *) + let fused = ref PMap.empty in + let tmp_used = ref used in + let rec browse = function + | Block f | Loop f | Function f -> f browse + | Use v | Assign v -> + if PMap.mem v.v_id !tmp_used then fused := PMap.add v.v_id v !fused; + | Declare v -> + tmp_used := PMap.remove v.v_id !tmp_used + in + local_usage browse e; + let vars = PMap.fold (fun v acc -> v :: acc) !fused [] in + + (* in case the variable has been marked as used in a parallel scope... *) + let fexpr = ref (wrap used f.tf_expr) in + let fargs = List.map (fun (v,o) -> + if PMap.mem v.v_id used then + let vtmp = mk_var v used in + fexpr := Type.concat (impl#mk_init v vtmp e.epos) !fexpr; + vtmp, o + else + v, o + ) f.tf_args in + let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in + (* + Create a new function scope to make sure that the captured loop variable + will not be overwritten in next loop iteration + *) + if com.config.pf_capture_policy = CPLoopVars then + mk (TCall ( + Codegen.mk_parent (mk (TFunction { + tf_args = List.map (fun v -> v, None) vars; + tf_type = e.etype; + tf_expr = mk_block (mk (TReturn (Some e)) e.etype e.epos); + }) (TFun (List.map (fun v -> v.v_name,false,v.v_type) vars,e.etype)) e.epos), + List.map (fun v -> mk (TLocal v) v.v_type e.epos) vars) + ) e.etype e.epos + else + e + | _ -> + map_expr (wrap used) e + + and do_wrap used e = + if PMap.is_empty used then + e + else + let used = PMap.map (fun v -> + let vt = v.v_type in + v.v_type <- impl#captured_type vt; + v.v_capture <- true; + vt + ) used in + wrap used e + + and out_loop e = + match e.eexpr with + | TFor _ | TWhile _ -> + (* + collect variables that are declared in loop but used in subfunctions + *) + let vars = ref PMap.empty in + let used = ref PMap.empty in + let depth = ref 0 in + let rec collect_vars in_loop = function + | Block f -> + let old = !vars in + f (collect_vars in_loop); + vars := old; + | Loop f -> + let old = !vars in + f (collect_vars true); + vars := old; + | Function f -> + incr depth; + f (collect_vars false); + decr depth; + | Declare v -> + if in_loop then vars := PMap.add v.v_id !depth !vars; + | Use v | Assign v -> + try + let d = PMap.find v.v_id !vars in + if d <> !depth then used := PMap.add v.v_id v !used; + with Not_found -> + () + in + local_usage (collect_vars false) e; + do_wrap !used e + | _ -> + map_expr out_loop e + and all_vars e = + let vars = ref PMap.empty in + let used = ref PMap.empty in + let assigned = ref PMap.empty in + let depth = ref 0 in + let rec collect_vars = function + | Block f -> + let old = !vars in + f collect_vars; + vars := old; + | Loop f -> + let old = !vars in + f collect_vars; + vars := old; + | Function f -> + incr depth; + f collect_vars; + decr depth; + | Declare v -> + vars := PMap.add v.v_id !depth !vars; + | Use v -> + (try + let d = PMap.find v.v_id !vars in + if d <> !depth then used := PMap.add v.v_id v !used; + with Not_found -> ()) + | Assign v -> + (try + let d = PMap.find v.v_id !vars in + (* different depth - needs wrap *) + if d <> !depth then begin + used := PMap.add v.v_id v !used; + assigned := PMap.add v.v_id v !assigned; + end + (* same depth but assigned after being used on a different depth - needs wrap *) + else if PMap.mem v.v_id !used then + assigned := PMap.add v.v_id v !assigned; + with Not_found -> ()) + in + local_usage collect_vars e; + + (* mark all capture variables - also used in rename_local_vars at later stage *) + PMap.iter (fun _ v -> v.v_capture <- true) !used; + + !assigned + in + let captured = all_vars e in + match com.config.pf_capture_policy with + | CPNone -> e + | CPWrapRef -> do_wrap captured e + | CPLoopVars -> out_loop e + +(* -------------------------------------------------------------------------- *) +(* RENAME LOCAL VARS *) + +let rename_local_vars ctx e = + let cfg = ctx.com.config in + let all_scope = (not cfg.pf_captured_scope) || (not cfg.pf_locals_scope) in + let vars = ref PMap.empty in + let all_vars = ref PMap.empty in + let vtemp = alloc_var "~" t_dynamic in + let rebuild_vars = ref false in + let rebuild m = + PMap.fold (fun v acc -> PMap.add v.v_name v acc) m PMap.empty + in + let save() = + let old = !vars in + if cfg.pf_unique_locals || not cfg.pf_locals_scope then (fun() -> ()) else (fun() -> vars := if !rebuild_vars then rebuild old else old) + in + let rename vars v = + let count = ref 1 in + while PMap.mem (v.v_name ^ string_of_int !count) vars do + incr count; + done; + v.v_name <- v.v_name ^ string_of_int !count; + in + let declare v p = + (match follow v.v_type with + | TAbstract ({a_path = [],"Void"},_) -> error "Arguments and variables of type Void are not allowed" p + | _ -> ()); + (* 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 look_vars = (if not cfg.pf_captured_scope && v.v_capture then !all_vars else !vars) in + (try + let v2 = PMap.find v.v_name look_vars in + (* + block_vars will create some wrapper-functions that are declaring + the same variable twice. In that case do not perform a rename since + we are sure it's actually the same variable + *) + if v == v2 then raise Not_found; + rename look_vars v; + with Not_found -> + ()); + vars := PMap.add v.v_name v !vars; + if all_scope then all_vars := PMap.add v.v_name v !all_vars; + in + (* + This is quite a rare case, when a local variable would otherwise prevent + accessing a type because it masks the type value or the package name. + *) + let check t = + match (t_infos t).mt_path with + | [], name | name :: _, _ -> + let vars = if cfg.pf_locals_scope then vars else all_vars in + (try + let v = PMap.find name !vars in + if v == vtemp then raise Not_found; (* ignore *) + rename (!vars) v; + rebuild_vars := true; + vars := PMap.add v.v_name v !vars + with Not_found -> + ()); + vars := PMap.add name vtemp !vars + 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 loop e = + match e.eexpr with + | TVar (v,eo) -> + if not cfg.pf_locals_scope then declare v e.epos; + (match eo with None -> () | Some e -> loop e); + if cfg.pf_locals_scope then declare v e.epos; + | TFunction tf -> + let old = save() in + List.iter (fun (v,_) -> declare v e.epos) tf.tf_args; + loop tf.tf_expr; + old() + | TBlock el -> + let old = save() in + (* we have to look ahead for vars on these targets (issue #3344) *) + begin match ctx.com.platform with + | Js -> + let rec check_var e = match e.eexpr with + | TVar (v,eo) -> + (match eo with None -> () | Some e -> loop e); + declare v e.epos + | TBlock _ -> + () + | _ -> + Type.iter check_var e + in + List.iter check_var el + | _ -> + () + end; + List.iter loop el; + old() + | TFor (v,it,e1) -> + loop it; + let old = save() in + declare v e.epos; + loop e1; + old() + | TTry (e,catchs) -> + loop e; + List.iter (fun (v,e) -> + let old = save() in + declare v e.epos; + check_type v.v_type; + loop e; + old() + ) catchs; + | TTypeExpr t -> + check t + | TNew (c,_,_) -> + Type.iter loop e; + check (TClassDecl c); + | TCast (e,Some t) -> + loop e; + check t; + | TConst TSuper -> + check_type e.etype + | _ -> + Type.iter loop e + in + declare (alloc_var "this" t_dynamic) Ast.null_pos; (* force renaming of 'this' vars in abstract *) + begin match ctx.curclass.cl_path with + | s :: _,_ | [],s -> declare (alloc_var s t_dynamic) Ast.null_pos + end; + loop e; + e + +let check_unification ctx e t = + begin match e.eexpr,t with + | TLocal v,TType({t_path = ["cs"],("Ref" | "Out")},_) -> + (* TODO: this smells of hack, but we have to deal with it somehow *) + v.v_capture <- true + | _ -> + () + end; + e + +(* PASS 1 end *) + +(* Saves a class state so it can be restored later, e.g. after DCE or native path rewrite *) +let save_class_state ctx t = match t with + | TClassDecl c -> + let mk_field_restore f = + let rec mk_overload_restore f = + f.cf_name,f.cf_kind,f.cf_expr,f.cf_type,f.cf_meta,f.cf_params + in + ( f,mk_overload_restore f, List.map (fun f -> f,mk_overload_restore f) f.cf_overloads ) + in + let restore_field (f,res,overloads) = + let restore_field (f,(name,kind,expr,t,meta,params)) = + f.cf_name <- name; f.cf_kind <- kind; f.cf_expr <- expr; f.cf_type <- t; f.cf_meta <- meta; f.cf_params <- params; + f + in + let f = restore_field (f,res) in + f.cf_overloads <- List.map restore_field overloads; + f + in + let mk_pmap lst = + List.fold_left (fun pmap f -> PMap.add f.cf_name f pmap) PMap.empty lst + in + + let meta = c.cl_meta and path = c.cl_path and ext = c.cl_extern and over = c.cl_overrides in + let sup = c.cl_super and impl = c.cl_implements in + let csr = Option.map (mk_field_restore) c.cl_constructor in + let ofr = List.map (mk_field_restore) c.cl_ordered_fields in + let osr = List.map (mk_field_restore) c.cl_ordered_statics in + let init = c.cl_init in + c.cl_restore <- (fun() -> + c.cl_super <- sup; + c.cl_implements <- impl; + c.cl_meta <- meta; + c.cl_extern <- ext; + c.cl_path <- path; + c.cl_init <- init; + c.cl_ordered_fields <- List.map restore_field ofr; + c.cl_ordered_statics <- List.map restore_field osr; + c.cl_fields <- mk_pmap c.cl_ordered_fields; + c.cl_statics <- mk_pmap c.cl_ordered_statics; + c.cl_constructor <- Option.map restore_field csr; + c.cl_overrides <- over; + ) + | _ -> + () + +(* PASS 2 begin *) + +let rec is_removable_class c = + match c.cl_kind with + | KGeneric -> + (Meta.has Meta.Remove c.cl_meta || + (match c.cl_super with + | Some (c,_) -> is_removable_class c + | _ -> false) || + List.exists (fun (_,t) -> match follow t with + | TInst(c,_) -> + Codegen.has_ctor_constraint c + | _ -> + false + ) c.cl_params) + | KTypeParameter _ -> + (* this shouldn't happen, have to investigate (see #4092) *) + true + | _ -> + false + +let remove_generic_base ctx t = match t with + | TClassDecl c when is_removable_class c -> + c.cl_extern <- true + | _ -> + () + +(* Removes extern and macro fields, also checks for Void fields *) + +let remove_extern_fields ctx t = match t with + | TClassDecl c -> + if not (Common.defined ctx.com Define.DocGen) then begin + c.cl_ordered_fields <- List.filter (fun f -> + let b = Codegen.is_removable_field ctx f in + if b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields; + not b + ) c.cl_ordered_fields; + c.cl_ordered_statics <- List.filter (fun f -> + let b = Codegen.is_removable_field ctx f in + if b then c.cl_statics <- PMap.remove f.cf_name c.cl_statics; + not b + ) c.cl_ordered_statics; + end + | _ -> + () + +(* PASS 2 end *) + +(* PASS 3 begin *) + +(* Checks if a private class' path clashes with another path *) +let check_private_path ctx t = match t with + | TClassDecl c when c.cl_private -> + let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in + if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos; + | _ -> + () + +(* Rewrites class or enum paths if @:native metadata is set *) +let apply_native_paths ctx t = + let get_native_name meta = + let rec get_native meta = match meta with + | [] -> raise Not_found + | (Meta.Native,[v],p as meta) :: _ -> + meta + | _ :: meta -> + get_native meta + in + let (_,e,mp) = get_native meta in + match e with + | [Ast.EConst (Ast.String name),p] -> + name,p + | [] -> + raise Not_found + | _ -> + error "String expected" mp + in + let get_real_name meta name = + let name',p = get_native_name meta in + (Meta.RealPath,[Ast.EConst (Ast.String (name)), p], p), name' + in + let get_real_path meta path = + let name,p = get_native_name meta in + (Meta.RealPath,[Ast.EConst (Ast.String (s_type_path path)), p], p), parse_path name + in + try + (match t with + | TClassDecl c -> + let did_change = ref false in + let field cf = try + let meta,name = get_real_name cf.cf_meta cf.cf_name in + cf.cf_name <- name; + cf.cf_meta <- meta :: cf.cf_meta; + List.iter (fun cf -> cf.cf_name <- name) cf.cf_overloads; + did_change := true + with Not_found -> + () + in + let fields cfs old_map = + did_change := false; + List.iter field cfs; + if !did_change then + List.fold_left (fun map f -> PMap.add f.cf_name f map) PMap.empty cfs + else + old_map + in + c.cl_fields <- fields c.cl_ordered_fields c.cl_fields; + c.cl_statics <- fields c.cl_ordered_statics c.cl_statics; + let meta,path = get_real_path c.cl_meta c.cl_path in + c.cl_meta <- meta :: c.cl_meta; + c.cl_path <- path; + | TEnumDecl e -> + let meta,path = get_real_path e.e_meta e.e_path in + e.e_meta <- meta :: e.e_meta; + e.e_path <- path; + | TAbstractDecl a -> + let meta,path = get_real_path a.a_meta a.a_path in + a.a_meta <- meta :: a.a_meta; + a.a_path <- path; + | _ -> + ()) + with Not_found -> + () + +(* Adds the __rtti field if required *) +let add_rtti ctx t = + let rec has_rtti c = + Meta.has Meta.Rtti c.cl_meta || match c.cl_super with None -> false | Some (csup,_) -> has_rtti csup + in + match t with + | TClassDecl c when has_rtti c && not (PMap.mem "__rtti" c.cl_statics) -> + let f = mk_field "__rtti" ctx.t.tstring c.cl_pos in + let str = Genxml.gen_type_string ctx.com t in + f.cf_expr <- Some (mk (TConst (TString str)) f.cf_type c.cl_pos); + c.cl_ordered_statics <- f :: c.cl_ordered_statics; + c.cl_statics <- PMap.add f.cf_name f c.cl_statics; + | _ -> + () + +(* Adds member field initializations as assignments to the constructor *) +let add_field_inits ctx t = + let is_as3 = Common.defined ctx.com Define.As3 && not ctx.in_macro in + 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 *) + let v = alloc_var "_g" ethis.etype in + 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) + | _ -> (inits, cf :: fields) + ) ([],[]) c.cl_ordered_fields in + c.cl_ordered_fields <- (List.rev fields); + match inits with + | [] -> () + | _ -> + let el = List.map (fun cf -> + match cf.cf_expr with + | None -> assert false + | Some e -> + let lhs = mk (TField(ethis,FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type e.epos in + cf.cf_expr <- None; + let eassign = mk (TBinop(OpAssign,lhs,e)) e.etype 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; + ) inits in + let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in + match c.cl_constructor with + | None -> + let ct = TFun([],ctx.com.basic.tvoid) in + let ce = mk (TFunction { + tf_args = []; + tf_type = ctx.com.basic.tvoid; + tf_expr = mk (TBlock el) ctx.com.basic.tvoid c.cl_pos; + }) ct c.cl_pos in + let ctor = mk_field "new" ct c.cl_pos in + ctor.cf_kind <- Method MethNormal; + c.cl_constructor <- Some { ctor with cf_expr = Some ce }; + | Some cf -> + match cf.cf_expr with + | Some { eexpr = TFunction f } -> + let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in + 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 + c.cl_constructor <- Some {cf with cf_expr = Some ce } + | _ -> + assert false + in + match t with + | TClassDecl c -> + apply c + | _ -> + () + +(* Adds the __meta__ field if required *) +let add_meta_field ctx t = match t with + | TClassDecl c -> + (match Codegen.build_metadata ctx.com t with + | None -> () + | Some e -> + let f = mk_field "__meta__" t_dynamic c.cl_pos in + f.cf_expr <- Some e; + c.cl_ordered_statics <- f :: c.cl_ordered_statics; + c.cl_statics <- PMap.add f.cf_name f c.cl_statics) + | _ -> + () + +(* Removes interfaces tagged with @:remove metadata *) +let check_remove_metadata ctx t = match t with + | TClassDecl c -> + c.cl_implements <- List.filter (fun (c,_) -> not (Meta.has Meta.Remove c.cl_meta)) c.cl_implements; + | _ -> + () + +(* Checks for Void class fields *) +let check_void_field ctx t = match t with + | TClassDecl c -> + let check f = + match follow f.cf_type with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed" f.cf_pos | _ -> (); + in + List.iter check c.cl_ordered_fields; + List.iter check c.cl_ordered_statics; + | _ -> + () + +(* Interfaces have no 'super', but can extend many other interfaces. + This makes the first extended (implemented) interface the super for efficiency reasons (you can get one for 'free') + and leaves the remaining ones as 'implemented' *) +let promote_first_interface_to_super ctx t = match t with + | TClassDecl c when c.cl_interface -> + begin match c.cl_implements with + | ({ cl_path = ["cpp";"rtti"],_ },_ ) :: _ -> () + | first_interface :: remaining -> + c.cl_super <- Some first_interface; + c.cl_implements <- remaining + | _ -> () + end + | _ -> + () + +let commit_features ctx t = + let m = (t_infos t).mt_module in + Hashtbl.iter (fun k v -> + Common.add_feature ctx.com k; + ) m.m_extra.m_features + +let check_reserved_type_paths ctx t = + let check path pos = + if List.mem path ctx.com.config.pf_reserved_type_paths then + ctx.com.warning ("Type path " ^ (s_type_path path) ^ " is reserved on this target") pos + in + match t with + | TClassDecl c when not c.cl_extern -> check c.cl_path c.cl_pos + | TEnumDecl e when not e.e_extern -> check e.e_path e.e_pos + | _ -> () + +(* PASS 3 end *) + +let run_expression_filters ctx filters t = + let run e = + List.fold_left (fun e f -> f e) e filters + in + match t with + | TClassDecl c when is_removable_class c -> () + | TClassDecl c -> + ctx.curclass <- c; + let rec process_field f = + (match f.cf_expr with + | Some e when not (Codegen.is_removable_field ctx f) -> + Codegen.AbstractCast.cast_stack := f :: !Codegen.AbstractCast.cast_stack; + f.cf_expr <- Some (run e); + Codegen.AbstractCast.cast_stack := List.tl !Codegen.AbstractCast.cast_stack; + | _ -> ()); + List.iter process_field f.cf_overloads + in + List.iter process_field c.cl_ordered_fields; + List.iter process_field c.cl_ordered_statics; + (match c.cl_constructor with + | None -> () + | Some f -> process_field f); + (match c.cl_init with + | None -> () + | Some e -> + c.cl_init <- Some (run e)); + | TEnumDecl _ -> () + | TTypeDecl _ -> () + | TAbstractDecl _ -> () + +let pp_counter = ref 1 + +let is_cached t = + let m = (t_infos t).mt_module.m_extra in + if m.m_processed = 0 then m.m_processed <- !pp_counter; + m.m_processed <> !pp_counter + +let apply_filters_once ctx filters t = + if not (is_cached t) then run_expression_filters ctx filters t + +let next_compilation() = + incr pp_counter + +let iter_expressions fl mt = + match mt with + | TClassDecl c -> + let field cf = match cf.cf_expr with + | None -> () + | Some e -> List.iter (fun f -> f e) fl + in + List.iter field c.cl_ordered_statics; + List.iter field c.cl_ordered_fields; + (match c.cl_constructor with None -> () | Some cf -> field cf) + | _ -> + () + +let run com tctx main = + begin match com.display with + | DMUsage | DMPosition -> + Codegen.detect_usage com; + | _ -> + () + end; + if not (Common.defined com Define.NoDeprecationWarnings) then + Codegen.DeprecationCheck.run com; + let use_static_analyzer = Common.defined com Define.Analyzer in + (* this part will be a bit messy until we make the analyzer the default *) + let new_types = List.filter (fun t -> not (is_cached t)) com.types in + if use_static_analyzer then begin + (* PASS 1: general expression filters *) + let filters = [ + Codegen.UnificationCallback.run (check_unification tctx); + Codegen.AbstractCast.handle_abstract_casts tctx; + Optimizer.inline_constructors tctx; + Optimizer.reduce_expression tctx; + blockify_ast; + captured_vars com; + ] in + List.iter (run_expression_filters tctx filters) new_types; + Analyzer.Run.run_on_types tctx new_types; + List.iter (iter_expressions [verify_ast]) new_types; + let filters = [ + Optimizer.sanitize com; + if com.config.pf_add_final_return then add_final_return else (fun e -> e); + if com.platform = Js then wrap_js_exceptions com else (fun e -> e); + rename_local_vars tctx; + ] in + List.iter (run_expression_filters tctx filters) new_types; + end else begin + (* PASS 1: general expression filters *) + let filters = [ + Codegen.UnificationCallback.run (check_unification tctx); + Codegen.AbstractCast.handle_abstract_casts tctx; + blockify_ast; + check_local_vars_init; + ( if (Common.defined com Define.NoSimplify) || (Common.defined com Define.Cppia) || + ( match com.platform with Cpp -> false | _ -> true ) then + fun e -> e + else + fun e -> + let save = save_locals tctx in + let timer = timer "analyzer-simplify-apply" in + let e = try snd (Analyzer.Simplifier.apply com e) with Exit -> e in + timer(); + save(); + e ); + if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize com; + captured_vars com; + promote_complex_rhs com; + if com.config.pf_add_final_return then add_final_return else (fun e -> e); + if com.platform = Js then wrap_js_exceptions com else (fun e -> e); + rename_local_vars tctx; + ] in + List.iter (run_expression_filters tctx filters) new_types; + List.iter (iter_expressions [verify_ast]) new_types; + end; + next_compilation(); + List.iter (fun f -> f()) (List.rev com.filters); (* macros onGenerate etc. *) + List.iter (save_class_state tctx) new_types; + List.iter (fun t -> + remove_generic_base tctx t; + remove_extern_fields tctx t; + ) com.types; + (* update cache dependencies before DCE is run *) + Codegen.update_cache_dependencies com; + (* check @:remove metadata before DCE so it is ignored there (issue #2923) *) + List.iter (check_remove_metadata tctx) com.types; + (* DCE *) + let dce_mode = if Common.defined com Define.As3 then + "no" + else + (try Common.defined_value com Define.Dce with _ -> "no") + in + begin match dce_mode with + | "full" -> Dce.run com main (not (Common.defined com Define.Interp)) + | "std" -> Dce.run com main false + | "no" -> Dce.fix_accessors com + | _ -> failwith ("Unknown DCE mode " ^ dce_mode) + end; + (* always filter empty abstract implementation classes (issue #1885) *) + List.iter (fun mt -> match mt with + | TClassDecl({cl_kind = KAbstractImpl _} as c) when c.cl_ordered_statics = [] && c.cl_ordered_fields = [] && not (Meta.has Meta.Used c.cl_meta) -> + c.cl_extern <- true + | TClassDecl({cl_kind = KAbstractImpl a} as c) when Meta.has Meta.Enum a.a_meta -> + let is_runtime_field cf = + not (Meta.has Meta.Enum cf.cf_meta) + in + (* also filter abstract implementation classes that have only @:enum fields (issue #2858) *) + if not (List.exists is_runtime_field c.cl_ordered_statics) then + c.cl_extern <- true + | _ -> () + ) com.types; + (* PASS 3: type filters *) + let type_filters = [ + check_private_path; + apply_native_paths; + add_rtti; + (match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits); + add_meta_field; + check_void_field; + (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ _ -> ()) ); + commit_features; + (if com.config.pf_reserved_type_paths <> [] then check_reserved_type_paths else (fun _ _ -> ())); + ] in + List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types diff --git a/genas3.ml b/genas3.ml index e017b2ce28b9511cc5d5ed0aedcb415e70934d92..5f999bd540c5b72f12af175370b9fed795b853bb 100644 --- a/genas3.ml +++ b/genas3.ml @@ -45,10 +45,12 @@ type context = { 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 _ -> true | _ -> false) + | FStatic (_,f) | FInstance (_,_,f) -> + (match f.cf_kind with Var _ | Method MethDynamic -> true | _ -> false) | _ -> false @@ -57,7 +59,7 @@ let is_special_compare e1 e2 = | TConst TNull, _ | _ , TConst TNull -> None | _ -> match follow e1.etype, follow e2.etype with - | TInst ({ cl_path = [],"Xml" } as c,_) , _ | _ , TInst ({ cl_path = [],"Xml" } as c,_) -> Some c + | TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c | _ -> None let protect name = @@ -119,6 +121,22 @@ let reserved = 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 "\"" ^ s ^ "\"" else s + let rec create_dir acc = function | [] -> () | d :: l -> @@ -151,6 +169,12 @@ let init infos path = } 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 -> @@ -212,8 +236,8 @@ let rec type_str ctx t p = match t with | TEnum _ | TInst _ when List.memq t ctx.local_types -> "*" - | TAbstract ({ a_impl = Some _ } as a,pl) -> - type_str ctx (apply_params a.a_types pl a.a_this) p + | TAbstract (a,pl) when not (Ast.Meta.has Ast.Meta.CoreType a.a_meta) -> + type_str ctx (Abstract.get_underlying_type a pl) p | TAbstract (a,_) -> (match a.a_path with | [], "Void" -> "void" @@ -246,7 +270,7 @@ let rec type_str ctx t p = | TInst (c,_) -> (match c.cl_kind with | KNormal | KGeneric | KGenericInstance _ | KAbstractImpl _ -> s_path ctx false c.cl_path p - | KTypeParameter _ | KExtension _ | KExpr _ | KMacroType -> "*") + | KTypeParameter _ | KExtension _ | KExpr _ | KMacroType | KGenericBuild _ -> "*") | TFun _ -> "Function" | TMono r -> @@ -269,14 +293,14 @@ let rec type_str ctx t p = | TEnum ({ e_path = [],"Bool" },_) -> "*" | _ -> type_str ctx t p) | _ -> assert false); - | _ -> type_str ctx (apply_params t.t_types args t.t_type) p) + | _ -> type_str ctx (apply_params t.t_params args t.t_type) p) | TLazy f -> type_str ctx ((!f)()) p let rec iter_switch_break in_switch e = match e.eexpr with | TFunction _ | TWhile _ | TFor _ -> () - | TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e + | TSwitch _ when not in_switch -> iter_switch_break true e | TBreak when in_switch -> raise Exit | _ -> iter (iter_switch_break in_switch) e @@ -301,20 +325,12 @@ let handle_break ctx e = let this ctx = if ctx.in_value <> None then "$this" else "this" -let escape_bin s = - let b = Buffer.create 0 in - for i = 0 to String.length s - 1 do - match Char.code (String.unsafe_get s i) with - | c when c < 32 -> Buffer.add_string b (Printf.sprintf "\\x%.2X" c) - | c -> Buffer.add_char b (Char.chr c) - done; - Buffer.contents b - 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 = Base64.str_encode name in let ch = open_out_bin (String.concat "/" (dir @ [name])) in output_string ch data; close_out ch @@ -329,9 +345,9 @@ let generate_resources infos = 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" name; + print ctx "\t\t[Embed(source = \"__res/%s\", mimeType = \"application/octet-stream\")]\n" (Base64.str_encode name); print ctx "\t\tpublic static var %s:Class;\n" varname; - inits := ("list[\"" ^name^ "\"] = " ^ varname ^ ";") :: !inits; + inits := ("list[\"" ^ Ast.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"; @@ -347,7 +363,7 @@ let generate_resources infos = let gen_constant ctx p = function | TInt i -> print ctx "%ld" i | TFloat s -> spr ctx s - | TString s -> print ctx "\"%s\"" (escape_bin (Ast.s_escape s)) + | TString s -> print ctx "\"%s\"" (Ast.s_escape s) | TBool b -> spr ctx (if b then "true" else "false") | TNull -> spr ctx "null" | TThis -> spr ctx (this ctx) @@ -380,14 +396,18 @@ let gen_function_header ctx name f params p = " " ^ loop meta ); concat ctx "," (fun (v,c) -> - 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 c -> - spr ctx " = "; - gen_constant ctx p 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 c -> + spr ctx " = "; + gen_constant ctx p c ) f.tf_args; print ctx ") : %s " (type_str ctx f.tf_type p); (fun () -> @@ -409,6 +429,12 @@ let rec gen_call ctx e el r = gen_value ctx e1; spr ctx " is "; gen_value ctx e2; + | TLocal { v_name = "__in__" } , [e1;e2] -> + spr ctx "("; + gen_value ctx e1; + spr ctx " in "; + gen_value ctx e2; + spr ctx ")" | TLocal { v_name = "__as__" }, [e1;e2] -> gen_value ctx e1; spr ctx " as "; @@ -482,6 +508,12 @@ let rec gen_call ctx e el r = 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; @@ -564,15 +596,20 @@ and gen_expr ctx e = 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 on interfaces are generated as (class["field"] as class) *) - | TField ({etype = TInst({cl_interface = true} as c,_)} as e,FInstance (_,{ cf_name = s })) - when (try (match (PMap.find s c.cl_fields).cf_kind with Var _ -> true | _ -> false) with Not_found -> false) -> + (* 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 e; + 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) -> @@ -580,8 +617,11 @@ and gen_expr ctx e = gen_expr ctx e1; spr ctx ")"; gen_field_access ctx e1.etype (field_name s) + | TEnumParameter (e,_,i) -> + gen_value ctx e; + print ctx ".params[%i]" i; | TField (e,s) -> - gen_value ctx e; + 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) @@ -589,6 +629,8 @@ and gen_expr ctx 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 @@ -624,10 +666,10 @@ and gen_expr ctx e = end else begin ctx.constructor_block <- false; print ctx " if( !%s.skip_constructor ) {" (s_path ctx true (["flash"],"Boot") e.epos); - (fun() -> print ctx "}") + (fun() -> print ctx "}") end) in (match ctx.block_inits with None -> () | Some i -> i()); - List.iter (fun e -> block_newline ctx; gen_expr ctx e) el; + List.iter (fun e -> gen_block_element ctx e) el; bend(); newline ctx; cb(); @@ -648,18 +690,15 @@ and gen_expr ctx e = | TThrow e -> spr ctx "throw "; gen_value ctx e; - | TVars [] -> - () - | TVars vl -> + | TVar (v,eo) -> spr ctx "var "; - concat ctx ", " (fun (v,eo) -> - print ctx "%s : %s" (s_ident v.v_name) (type_str ctx v.v_type e.epos); - match eo with - | None -> () - | Some e -> - spr ctx " = "; - gen_value ctx e - ) vl; + 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) @@ -699,7 +738,7 @@ and gen_expr ctx e = handle_break(); | TObjectDecl fields -> spr ctx "{ "; - concat ctx ", " (fun (f,e) -> print ctx "%s : " (s_ident f); gen_value ctx e) fields; + 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 @@ -721,49 +760,6 @@ and gen_expr ctx e = print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos); gen_expr ctx e; ) catchs; - | TMatch (e,_,cases,def) -> - print ctx "{"; - let bend = open_block ctx in - newline ctx; - let tmp = gen_local ctx "$e" in - print ctx "var %s : enum = " tmp; - gen_value ctx e; - newline ctx; - print ctx "switch( %s.index ) {" tmp; - List.iter (fun (cl,params,e) -> - List.iter (fun c -> - newline ctx; - print ctx "case %d:" c; - ) cl; - (match params with - | None | Some [] -> () - | Some l -> - let n = ref (-1) in - let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v,!n) :: acc) [] l in - match l with - | [] -> () - | l -> - newline ctx; - spr ctx "var "; - concat ctx ", " (fun (v,n) -> - print ctx "%s : %s = %s.params[%d]" (s_ident v.v_name) (type_str ctx v.v_type e.epos) tmp n; - ) l); - gen_block ctx e; - print ctx "break"; - ) cases; - (match def with - | None -> () - | Some e -> - newline ctx; - spr ctx "default:"; - gen_block ctx e; - print ctx "break"; - ); - newline ctx; - spr ctx "}"; - bend(); - newline ctx; - spr ctx "}"; | TSwitch (e,cases,def) -> spr ctx "switch"; gen_value ctx (parent e); @@ -789,12 +785,24 @@ and gen_expr ctx e = ); spr ctx "}" | TCast (e1,None) -> - spr ctx "(("; - gen_expr ctx e1; - print ctx ") as %s)" (type_str ctx e.etype e.epos); + 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) +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 @@ -857,6 +865,7 @@ and gen_value ctx e = | TArray _ | TBinop _ | TField _ + | TEnumParameter _ | TTypeExpr _ | TParenthesis _ | TObjectDecl _ @@ -866,11 +875,18 @@ and gen_value ctx e = | TUnop _ | TFunction _ -> gen_expr ctx e + | TMeta (_,e1) -> + gen_value ctx e1 | TCast (e1,None) -> let s = type_str ctx e.etype e1.epos in - if s = "*" then + begin match s with + | "*" -> gen_value ctx e1 - else begin + | "Function" | "Array" | "String" -> + spr ctx "(("; + gen_value ctx e1; + print ctx ") as %s)" s; + | _ -> print ctx "%s(" s; gen_value ctx e1; spr ctx ")"; @@ -881,7 +897,7 @@ and gen_value ctx e = | TBreak | TContinue -> unsupported e.epos - | TVars _ + | TVar _ | TFor _ | TWhile _ | TThrow _ -> @@ -924,13 +940,6 @@ and gen_value ctx e = match def with None -> None | Some e -> Some (assign e) )) e.etype e.epos); v() - | TMatch (cond,enum,cases,def) -> - let v = value true in - gen_expr ctx (mk (TMatch (cond,enum, - List.map (fun (constr,params,e) -> (constr,params,assign e)) 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), @@ -968,7 +977,11 @@ let generate_field ctx static f = print ctx "]"; | _ -> () ) f.cf_meta; - let public = f.cf_public || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static) || f.cf_name = "resolve" || Ast.Meta.has Ast.Meta.Public f.cf_meta in + let public = f.cf_public || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static) + || f.cf_name = "resolve" || Ast.Meta.has Ast.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) + 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 @@ -992,7 +1005,7 @@ let generate_field ctx static f = 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) -> + | TFun (args,r) when (match f.cf_kind with Method MethDynamic | Var _ -> false | _ -> true) -> let rec loop = function | [] -> f.cf_name | (Ast.Meta.Getter,[Ast.EConst (Ast.String name),_],_) :: _ -> "get " ^ name @@ -1006,20 +1019,6 @@ let generate_field ctx static f = if o then print ctx " = %s" (default_value tstr); ) args; print ctx ") : %s " (type_str ctx r p); - | _ when is_getset -> - let t = type_str ctx f.cf_type p in - let id = s_ident f.cf_name in - (match f.cf_kind with - | Var v -> - (match v.v_read with - | AccNormal -> print ctx "function get %s() : %s;" id t; - | AccCall -> print ctx "function %s() : %s;" ("get_" ^ f.cf_name) t; - | _ -> ()); - (match v.v_write with - | AccNormal -> print ctx "function set %s( __v : %s ) : void;" id t; - | AccCall -> print ctx "function %s( __v : %s ) : %s;" ("set_" ^ f.cf_name) t t; - | _ -> ()); - | _ -> assert false) | _ -> () else let gen_init () = match f.cf_expr with @@ -1075,7 +1074,7 @@ 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_types; + ctx.local_types <- List.map snd c.cl_params; let pack = open_block ctx in print ctx "\tpublic %s%s%s %s " (final c.cl_meta) (match c.cl_dynamic with None -> "" | Some _ -> if c.cl_interface then "" else "dynamic ") (if c.cl_interface then "interface" else "class") (snd c.cl_path); (match c.cl_super with @@ -1136,7 +1135,7 @@ let generate_main ctx inits = newline ctx let generate_enum ctx e = - ctx.local_types <- List.map snd e.e_types; + 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; diff --git a/gencommon.ml b/gencommon.ml index ea5f74f43bba3d3d31a6893215a598bbf7bdd594..cd039e59d8a4d824e2933630deb4a2931a786bfa 100644 --- a/gencommon.ml +++ b/gencommon.ml @@ -21,66 +21,80 @@ *) (* - Gen Common API + Gen Common API - This module intends to be a common set of utilities common to all targets. + This module intends to be a common set of utilities common to all targets. - It's intended to provide a set of tools to be able to make targets in haXe more easily, and to - allow the programmer to have more control of how the target language will handle the program. + It's intended to provide a set of tools to be able to make targets in Haxe more easily, and to + allow the programmer to have more control of how the target language will handle the program. - For example, as of now, the hxcpp target, while greatly done, relies heavily on cpp's own operator - overloading, and implicit conversions, which make it very hard to deliver a similar solution for languages - that lack these features. + For example, as of now, the hxcpp target, while greatly done, relies heavily on cpp's own operator + overloading, and implicit conversions, which make it very hard to deliver a similar solution for languages + that lack these features. - So this little framework is here so you can manipulate the HaXe AST and start bringing the AST closer - to how it's intenteded to be in your host language. + So this little framework is here so you can manipulate the Haxe AST and start bringing the AST closer + to how it's intenteded to be in your host language. - Rules + Rules - Design goals + Design goals - Naming convention + Naming convention - Weaknesses and TODO's + Weaknesses and TODO's *) - +open Unix open Ast open Type open Common open Option open Printf +open ExtString let debug_type_ctor = function - | TMono _ -> "TMono" - | TEnum _ -> "TEnum" - | TInst _ -> "TInst" - | TType _ -> "TType" - | TFun _ -> "TFun" - | TAnon _ -> "TAnon" - | TDynamic _ -> "TDynamic" - | TLazy _ -> "TLazy" - | TAbstract _ -> "TAbstract" + | TMono _ -> "TMono" + | TEnum _ -> "TEnum" + | TInst _ -> "TInst" + | TType _ -> "TType" + | TFun _ -> "TFun" + | TAnon _ -> "TAnon" + | TDynamic _ -> "TDynamic" + | TLazy _ -> "TLazy" + | TAbstract _ -> "TAbstract" let debug_type = (s_type (print_context())) let debug_expr = s_expr debug_type let rec like_float t = - match follow t with - | TAbstract({ a_path = ([], "Float") },[]) - | TAbstract({ a_path = ([], "Int") },[]) -> true - | TAbstract(a, _) -> List.exists (fun (t,_) -> like_float t) a.a_from || List.exists (fun (t,_) -> like_float t) a.a_to - | _ -> false + match follow t with + | TAbstract({ a_path = ([], "Float") },[]) + | TAbstract({ a_path = ([], "Int") },[]) -> true + | TAbstract({ a_path = (["cs"], "Pointer") },_) -> false + | TAbstract(a, _) -> List.exists (fun t -> like_float t) a.a_from || List.exists (fun t -> like_float t) a.a_to + | _ -> false let rec like_int t = - match follow t with - | TAbstract({ a_path = ([], "Int") },[]) -> true - | TAbstract(a, _) -> List.exists (fun (t,_) -> like_int t) a.a_from || List.exists (fun (t,_) -> like_float t) a.a_to - | _ -> false - + match follow t with + | TAbstract({ a_path = ([], "Int") },[]) -> true + | TAbstract({ a_path = (["cs"], "Pointer") },_) -> false + | TAbstract(a, _) -> List.exists (fun t -> like_int t) a.a_from || List.exists (fun t -> like_int t) a.a_to + | _ -> false + +let rec like_i64 t = + match follow t with + | TInst({ cl_path = (["cs"], "Int64") },[]) + | TAbstract({ a_path = (["cs"], "Int64") },[]) + | TInst({ cl_path = (["cs"], "UInt64") },[]) + | TInst({ cl_path = (["java"], "Int64") },[]) + | TAbstract({ a_path = (["java"], "Int64") },[]) + | TInst({ cl_path = (["haxe"], "Int64") },[]) + | TAbstract({ a_path = (["haxe"], "Int64") },[]) -> true + | TAbstract(a, _) -> List.exists (fun t -> like_i64 t) a.a_from || List.exists (fun t -> like_i64 t) a.a_to + | _ -> false let follow_once t = - match t with + match t with | TMono r -> (match !r with | Some t -> t @@ -88,11 +102,15 @@ let follow_once t = | TLazy f -> !f() | TType (t,tl) -> - apply_params t.t_types tl t.t_type + apply_params t.t_params tl t.t_type | _ -> t let t_empty = TAnon({ a_fields = PMap.empty; a_status = ref (Closed) }) +let tmp_count = ref 0 + +let reset_temps () = tmp_count := 0 + (* the undefined is a special var that works like null, but can have special meaning *) let v_undefined = alloc_var "__undefined__" t_dynamic @@ -100,75 +118,80 @@ let undefined pos = { eexpr = TLocal(v_undefined); etype = t_dynamic; epos = pos module ExprHashtblHelper = struct - type hash_texpr_t = - { - hepos : pos; - heexpr : int; - hetype : int; - } - - let mk_heexpr = function - | TConst _ -> 0 | TLocal _ -> 1 | TArray _ -> 3 | TBinop _ -> 4 | TField _ -> 5 | TTypeExpr _ -> 7 | TParenthesis _ -> 8 | TObjectDecl _ -> 9 - | TArrayDecl _ -> 10 | TCall _ -> 11 | TNew _ -> 12 | TUnop _ -> 13 | TFunction _ -> 14 | TVars _ -> 15 | TBlock _ -> 16 | TFor _ -> 17 | TIf _ -> 18 | TWhile _ -> 19 - | TSwitch _ -> 20 | TMatch _ -> 21 | TTry _ -> 22 | TReturn _ -> 23 | TBreak -> 24 | TContinue -> 25 | TThrow _ -> 26 | TCast _ -> 27 - - let mk_heetype = function - | TMono _ -> 0 | TEnum _ -> 1 | TInst _ -> 2 | TType _ -> 3 | TFun _ -> 4 - | TAnon _ -> 5 | TDynamic _ -> 6 | TLazy _ -> 7 | TAbstract _ -> 8 - - let mk_type e = - { - hepos = e.epos; - heexpr = mk_heexpr e.eexpr; - hetype = mk_heetype e.etype; - } + type hash_texpr_t = + { + hepos : pos; + heexpr : int; + hetype : int; + } + + let mk_heexpr = function + | TConst _ -> 0 | TLocal _ -> 1 | TArray _ -> 3 | TBinop _ -> 4 | TField _ -> 5 | TTypeExpr _ -> 7 | TParenthesis _ -> 8 | TObjectDecl _ -> 9 + | TArrayDecl _ -> 10 | TCall _ -> 11 | TNew _ -> 12 | TUnop _ -> 13 | TFunction _ -> 14 | TVar _ -> 15 | TBlock _ -> 16 | TFor _ -> 17 | TIf _ -> 18 | TWhile _ -> 19 + | TSwitch _ -> 20 (* | TPatMatch _ -> 21 *) | TTry _ -> 22 | TReturn _ -> 23 | TBreak -> 24 | TContinue -> 25 | TThrow _ -> 26 | TCast _ -> 27 | TMeta _ -> 28 | TEnumParameter _ -> 29 + + let mk_heetype = function + | TMono _ -> 0 | TEnum _ -> 1 | TInst _ -> 2 | TType _ -> 3 | TFun _ -> 4 + | TAnon _ -> 5 | TDynamic _ -> 6 | TLazy _ -> 7 | TAbstract _ -> 8 + + let mk_type e = + { + hepos = e.epos; + heexpr = mk_heexpr e.eexpr; + hetype = mk_heetype e.etype; + } end;; +let path_of_md_def md_def = + match md_def.m_types with + | [TClassDecl c] -> c.cl_path + | _ -> md_def.m_path + open ExprHashtblHelper;; (* Expression Hashtbl. This shouldn't be kept indefinately as it's not a weak Hashtbl. *) module ExprHashtbl = Hashtbl.Make( - struct - type t = Type.texpr + struct + type t = Type.texpr - let equal = (==) - let hash t = Hashtbl.hash (mk_type t) - end + let equal = (==) + let hash t = Hashtbl.hash (mk_type t) + end );; (* ******************************************* *) -(* Gen Common +(* Gen Common This is the key module for generation of Java and C# sources In order for both modules to share as much code as possible, some rules were devised: - every feature has its own submodule, and may contain the following methods: - - configure - sets all the configuration variables for the module to run. If a module has this method, - it *should* be called once before running any filter - - run_filter -> - runs the filter immediately on the context - - add_filter -> - adds the filter to an expr->expr list. Most filter modules will provide this option so the filter - function can only run once. + - configure + sets all the configuration variables for the module to run. If a module has this method, + it *should* be called once before running any filter + - run_filter -> + runs the filter immediately on the context + - add_filter -> + adds the filter to an expr->expr list. Most filter modules will provide this option so the filter + function can only run once. - most submodules will have side-effects so the order of operations will matter. - When running configure / add_filter this might be taken care of with the rule-based dispatch system working - underneath, but still there might be some incompatibilities. There will be an effort to document it. - The modules can hint on the order by suffixing their functions with _first or _last. + When running configure / add_filter this might be taken care of with the rule-based dispatch system working + underneath, but still there might be some incompatibilities. There will be an effort to document it. + The modules can hint on the order by suffixing their functions with _first or _last. - any of those methods might have different parameters, that configure how the filter will run. - For example, a simple filter that maps switch() expressions to if () .. else if... might receive - a function that filters what content should be mapped + For example, a simple filter that maps switch() expressions to if () .. else if... might receive + a function that filters what content should be mapped - Other targets can use those filters on their own code. In order to do that, - a simple configuration step is needed: you need to initialize a generator_ctx type with - Gencommon.new_gen (context:Common.context) - with a generator_ctx context you will be able to add filters to your code, and execute them with - Gencommon.run_filters (gen_context:Gencommon.generator_ctx) + a simple configuration step is needed: you need to initialize a generator_ctx type with + Gencommon.new_gen (context:Common.context) + with a generator_ctx context you will be able to add filters to your code, and execute them with + Gencommon.run_filters (gen_context:Gencommon.generator_ctx) - After running the filters, you can run your own generator normally. + After running the filters, you can run your own generator normally. - (* , or you can run - Gencommon.generate_modules (gen_context:Gencommon.generator_ctx) (extension:string) (module_gen:module_type list->bool) - where module_gen will take a whole module (can be *) + (* , or you can run + Gencommon.generate_modules (gen_context:Gencommon.generator_ctx) (extension:string) (module_gen:module_type list->bool) + where module_gen will take a whole module (can be *) *) @@ -186,147 +209,148 @@ let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) (* helper function for creating Anon types of class / enum modules *) let anon_of_classtype cl = - TAnon { - a_fields = cl.cl_statics; - a_status = ref (Statics cl) - } + TAnon { + a_fields = cl.cl_statics; + a_status = ref (Statics cl) + } let anon_of_enum e = - TAnon { - a_fields = PMap.empty; - a_status = ref (EnumStatics e) - } + TAnon { + a_fields = PMap.empty; + a_status = ref (EnumStatics e) + } let anon_of_abstract a = - TAnon { - a_fields = PMap.empty; - a_status = ref (AbstractStatics a) - } + TAnon { + a_fields = PMap.empty; + a_status = ref (AbstractStatics a) + } let anon_of_mt mt = match mt with - | TClassDecl cl -> anon_of_classtype cl - | TEnumDecl e -> anon_of_enum e - | TAbstractDecl a -> anon_of_abstract a - | _ -> assert false + | TClassDecl cl -> anon_of_classtype cl + | TEnumDecl e -> anon_of_enum e + | TAbstractDecl a -> anon_of_abstract a + | _ -> assert false let anon_class t = - match follow t with - | TAnon anon -> - (match !(anon.a_status) with - | Statics (cl) -> Some(TClassDecl(cl)) - | EnumStatics (e) -> Some(TEnumDecl(e)) - | AbstractStatics (a) -> Some(TAbstractDecl(a)) - | _ -> None) - | _ -> None + match follow t with + | TAnon anon -> + (match !(anon.a_status) with + | Statics (cl) -> Some(TClassDecl(cl)) + | EnumStatics (e) -> Some(TEnumDecl(e)) + | AbstractStatics (a) -> Some(TAbstractDecl(a)) + | _ -> None) + | _ -> None let path_s path = - match path with | ([], s) -> s | (p, s) -> (String.concat "." (fst path)) ^ "." ^ (snd path) + match path with | ([], s) -> s | (p, s) -> (String.concat "." (fst path)) ^ "." ^ (snd path) let rec t_to_md t = match t with - | TInst (cl,_) -> TClassDecl cl - | TEnum (e,_) -> TEnumDecl e - | TType (t,_) -> TTypeDecl t - | TAbstract (a,_) -> TAbstractDecl a - | TAnon anon -> - (match !(anon.a_status) with - | EnumStatics e -> TEnumDecl e - | Statics cl -> TClassDecl cl - | AbstractStatics a -> TAbstractDecl a - | _ -> assert false) - | TLazy f -> t_to_md (!f()) - | TMono r -> (match !r with | Some t -> t_to_md t | None -> assert false) - | _ -> assert false + | TInst (cl,_) -> TClassDecl cl + | TEnum (e,_) -> TEnumDecl e + | TType (t,_) -> TTypeDecl t + | TAbstract (a,_) -> TAbstractDecl a + | TAnon anon -> + (match !(anon.a_status) with + | EnumStatics e -> TEnumDecl e + | Statics cl -> TClassDecl cl + | AbstractStatics a -> TAbstractDecl a + | _ -> assert false) + | TLazy f -> t_to_md (!f()) + | TMono r -> (match !r with | Some t -> t_to_md t | None -> assert false) + | _ -> assert false let get_cl mt = match mt with | TClassDecl cl -> cl | _ -> failwith ("Unexpected module type of '" ^ path_s (t_path mt) ^ "'") +let get_abstract mt = match mt with | TAbstractDecl a -> a | _ -> failwith ("Unexpected module type of '" ^ path_s (t_path mt) ^ "'") + let get_tdef mt = match mt with | TTypeDecl t -> t | _ -> assert false let mk_mt_access mt pos = { eexpr = TTypeExpr(mt); etype = anon_of_mt mt; epos = pos } let is_void t = match follow t with - | TEnum({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> - true - | _ -> false + | TAbstract ({ a_path = ([], "Void") },[]) -> + true + | _ -> false let mk_local var pos = { eexpr = TLocal(var); etype = var.v_type; epos = pos } (* this function is used by CastDetection module *) let get_fun t = - match follow t with | TFun(r1,r2) -> (r1,r2) | _ -> (trace (s_type (print_context()) (follow t) )); assert false + match follow t with | TFun(r1,r2) -> (r1,r2) | _ -> (trace (s_type (print_context()) (follow t) )); assert false let mk_cast t e = - { eexpr = TCast(e, None); etype = t; epos = e.epos } + { eexpr = TCast(e, None); etype = t; epos = e.epos } let mk_classtype_access cl pos = - { eexpr = TTypeExpr(TClassDecl(cl)); etype = anon_of_classtype cl; epos = pos } + { eexpr = TTypeExpr(TClassDecl(cl)); etype = anon_of_classtype cl; epos = pos } let mk_static_field_access_infer cl field pos params = - try - let cf = (PMap.find field cl.cl_statics) in - { eexpr = TField(mk_classtype_access cl pos, FStatic(cl, cf)); etype = (if params = [] then cf.cf_type else apply_params cf.cf_params params cf.cf_type); epos = pos } - with | Not_found -> failwith ("Cannot find field " ^ field ^ " in type " ^ (path_s cl.cl_path)) + try + let cf = (PMap.find field cl.cl_statics) in + { eexpr = TField(mk_classtype_access cl pos, FStatic(cl, cf)); etype = (if params = [] then cf.cf_type else apply_params cf.cf_params params cf.cf_type); epos = pos } + with | Not_found -> failwith ("Cannot find field " ^ field ^ " in type " ^ (path_s cl.cl_path)) let mk_static_field_access cl field fieldt pos = - { (mk_static_field_access_infer cl field pos []) with etype = fieldt } + { (mk_static_field_access_infer cl field pos []) with etype = fieldt } (* stolen from Hugh's sources ;-) *) (* this used to be a class, but there was something in there that crashed ocaml native compiler in windows *) module SourceWriter = struct - type source_writer = - { - sw_buf : Buffer.t; - mutable sw_has_content : bool; - mutable sw_indent : string; - mutable sw_indents : string list; - } + type source_writer = + { + sw_buf : Buffer.t; + mutable sw_has_content : bool; + mutable sw_indent : string; + mutable sw_indents : string list; + } - let new_source_writer () = - { - sw_buf = Buffer.create 0; - sw_has_content = false; - sw_indent = ""; - sw_indents = []; - } + let new_source_writer () = + { + sw_buf = Buffer.create 0; + sw_has_content = false; + sw_indent = ""; + sw_indents = []; + } - let add_writer w_write w_read = Buffer.add_buffer w_read.sw_buf w_write.sw_buf + let add_writer w_write w_read = Buffer.add_buffer w_read.sw_buf w_write.sw_buf - let contents w = Buffer.contents w.sw_buf + let contents w = Buffer.contents w.sw_buf - let len w = Buffer.length w.sw_buf + let len w = Buffer.length w.sw_buf - let write w x = - (if not w.sw_has_content then begin w.sw_has_content <- true; Buffer.add_string w.sw_buf w.sw_indent; Buffer.add_string w.sw_buf x; end else Buffer.add_string w.sw_buf x); - let len = (String.length x)-1 in - if len >= 0 && String.get x len = '\n' then begin w.sw_has_content <- false end else w.sw_has_content <- true + let write w x = + (if not w.sw_has_content then begin w.sw_has_content <- true; Buffer.add_string w.sw_buf w.sw_indent; Buffer.add_string w.sw_buf x; end else Buffer.add_string w.sw_buf x); + let len = (String.length x)-1 in + if len >= 0 && String.get x len = '\n' then begin w.sw_has_content <- false end else w.sw_has_content <- true - let push_indent w = w.sw_indents <- "\t"::w.sw_indents; w.sw_indent <- String.concat "" w.sw_indents + let push_indent w = w.sw_indents <- "\t"::w.sw_indents; w.sw_indent <- String.concat "" w.sw_indents - let pop_indent w = - match w.sw_indents with - | h::tail -> w.sw_indents <- tail; w.sw_indent <- String.concat "" w.sw_indents - | [] -> w.sw_indent <- "/*?*/" + let pop_indent w = + match w.sw_indents with + | h::tail -> w.sw_indents <- tail; w.sw_indent <- String.concat "" w.sw_indents + | [] -> w.sw_indent <- "/*?*/" - let newline w = write w "\n" + let newline w = write w "\n" - let begin_block w = (if w.sw_has_content then newline w); write w "{"; push_indent w; newline w + let begin_block w = (if w.sw_has_content then newline w); write w "{"; push_indent w; newline w - let end_block w = pop_indent w; (if w.sw_has_content then newline w); write w "}"; newline w + let end_block w = pop_indent w; (if w.sw_has_content then newline w); write w "}"; newline w - let print w = - (if not w.sw_has_content then begin w.sw_has_content <- true; Buffer.add_string w.sw_buf w.sw_indent end); - bprintf w.sw_buf; + let print w = + (if not w.sw_has_content then begin w.sw_has_content <- true; Buffer.add_string w.sw_buf w.sw_indent end); + bprintf w.sw_buf; end;; (* rule_dispatcher's priority *) type priority = - | PFirst - | PLast - | PZero - | PCustom of float + | PFirst + | PLast + | PZero + | PCustom of float exception DuplicateName of string exception NoRulesApplied @@ -336,1027 +360,1149 @@ let indent = ref [] (* the rule dispatcher is the primary way to deal with distributed "plugins" *) (* we will define rules that will form a distributed / extensible match system *) class ['tp, 'ret] rule_dispatcher name ignore_not_found = - object(self) - val tbl = Hashtbl.create 16 - val mutable keys = [] - val names = Hashtbl.create 16 - val mutable temp = 0 - - method add ?(name : string option) (* name helps debugging *) ?(priority : priority = PZero) (rule : 'tp->'ret option) = - let p = match priority with - | PFirst -> infinity - | PLast -> neg_infinity - | PZero -> 0.0 - | PCustom i -> i - in - - let q = if not( Hashtbl.mem tbl p ) then begin - let q = Stack.create() in - Hashtbl.add tbl p q; - keys <- p :: keys; - keys <- List.sort (fun x y -> - (compare x y)) keys; - q - end else Hashtbl.find tbl p in - let name = match name with - | None -> temp <- temp + 1; "$_" ^ (string_of_int temp) - | Some s -> s - in - (if Hashtbl.mem names name then raise (DuplicateName(name))); - Hashtbl.add names name q; - - Stack.push (name, rule) q - - method describe = - Hashtbl.iter (fun s _ -> (trace s)) names; - - method remove (name : string) = - if Hashtbl.mem names name then begin - let q = Hashtbl.find names name in - let q_temp = Stack.create () in - Stack.iter (function - | (n, _) when n = name -> () - | _ as r -> Stack.push r q_temp - ) q; - - Stack.clear q; - Stack.iter (fun r -> Stack.push r q) q_temp; - - Hashtbl.remove names name; - true - end else false - - method run_f tp = get (self#run tp) - - method did_run tp = is_some (self#run tp) - - method get_list = - let ret = ref [] in - List.iter (fun key -> - let q = Hashtbl.find tbl key in - Stack.iter (fun (_, rule) -> ret := rule :: !ret) q - ) keys; - - List.rev !ret - - method run_from (priority:float) (tp:'tp) : 'ret option = - let ok = ref ignore_not_found in - let ret = ref None in - indent := "\t" :: !indent; - - (try begin - List.iter (fun key -> - if key < priority then begin - let q = Hashtbl.find tbl key in - Stack.iter (fun (n, rule) -> - let t = if !debug_mode then Common.timer ("rule dispatcher rule: " ^ n) else fun () -> () in - let r = rule(tp) in - t(); - if is_some r then begin ret := r; raise Exit end - ) q - end - ) keys - - end with Exit -> ok := true); - - (match !indent with - | [] -> () - | h::t -> indent := t); - - (if not (!ok) then raise NoRulesApplied); - !ret - - method run (tp:'tp) : 'ret option = - self#run_from infinity tp + object(self) + val tbl = Hashtbl.create 16 + val mutable keys = [] + val names = Hashtbl.create 16 + val mutable temp = 0 + + method add ?(name : string option) (* name helps debugging *) ?(priority : priority = PZero) (rule : 'tp->'ret option) = + let p = match priority with + | PFirst -> infinity + | PLast -> neg_infinity + | PZero -> 0.0 + | PCustom i -> i + in + + let q = if not( Hashtbl.mem tbl p ) then begin + let q = Stack.create() in + Hashtbl.add tbl p q; + keys <- p :: keys; + keys <- List.sort (fun x y -> - (compare x y)) keys; + q + end else Hashtbl.find tbl p in + let name = match name with + | None -> temp <- temp + 1; "$_" ^ (string_of_int temp) + | Some s -> s + in + (if Hashtbl.mem names name then raise (DuplicateName(name))); + Hashtbl.add names name q; + + Stack.push (name, rule) q + + method describe = + Hashtbl.iter (fun s _ -> (trace s)) names; + + method remove (name : string) = + if Hashtbl.mem names name then begin + let q = Hashtbl.find names name in + let q_temp = Stack.create () in + Stack.iter (function + | (n, _) when n = name -> () + | _ as r -> Stack.push r q_temp + ) q; + + Stack.clear q; + Stack.iter (fun r -> Stack.push r q) q_temp; + + Hashtbl.remove names name; + true + end else false + + method run_f tp = get (self#run tp) + + method did_run tp = is_some (self#run tp) + + method get_list = + let ret = ref [] in + List.iter (fun key -> + let q = Hashtbl.find tbl key in + Stack.iter (fun (_, rule) -> ret := rule :: !ret) q + ) keys; + + List.rev !ret + + method run_from (priority:float) (tp:'tp) : 'ret option = + let ok = ref ignore_not_found in + let ret = ref None in + indent := "\t" :: !indent; + + (try begin + List.iter (fun key -> + if key < priority then begin + let q = Hashtbl.find tbl key in + Stack.iter (fun (n, rule) -> + let t = if !debug_mode then Common.timer ("rule dispatcher rule: " ^ n) else fun () -> () in + let r = rule(tp) in + t(); + if is_some r then begin ret := r; raise Exit end + ) q + end + ) keys + + end with Exit -> ok := true); + + (match !indent with + | [] -> () + | h::t -> indent := t); + + (if not (!ok) then raise NoRulesApplied); + !ret + + method run (tp:'tp) : 'ret option = + self#run_from infinity tp end;; (* this is a special case where tp = tret and you stack their output as the next's input *) class ['tp] rule_map_dispatcher name = - object(self) - inherit ['tp, 'tp] rule_dispatcher name true as super - - method run_f tp = get (self#run tp) - - method run_from (priority:float) (tp:'tp) : 'ret option = - let cur = ref tp in - (try begin - List.iter (fun key -> - - if key < priority then begin - let q = Hashtbl.find tbl key in - Stack.iter (fun (n, rule) -> - trace ("running rule " ^ n); - let t = if !debug_mode then Common.timer ("rule map dispatcher rule: " ^ n) else fun () -> () in - let r = rule(!cur) in - t(); - if is_some r then begin cur := get r end - ) q - end - ) keys - - end with Exit -> ()); - Some (!cur) + object(self) + inherit ['tp, 'tp] rule_dispatcher name true as super + + method run_f tp = get (self#run tp) + + method run_from (priority:float) (tp:'tp) : 'ret option = + let cur = ref tp in + (try begin + List.iter (fun key -> + + if key < priority then begin + let q = Hashtbl.find tbl key in + Stack.iter (fun (n, rule) -> + trace ("running rule " ^ n); + let t = if !debug_mode then Common.timer ("rule map dispatcher rule: " ^ n) else fun () -> () in + let r = rule(!cur) in + t(); + if is_some r then begin cur := get r end + ) q + end + ) keys + + end with Exit -> ()); + Some (!cur) end;; type generator_ctx = { - (* these are the basic context fields. If another target is using this context, *) - (* this is all you need to care about *) - mutable gcon : Common.context; - - gclasses : gen_classes; - - gtools : gen_tools; - - (* - configurable function that receives a desired name and makes it "internal", doing the best - to ensure that it will not be called from outside. - To avoid name clashes between internal names, user must specify two strings: a "namespace" and the name itself - *) - mutable gmk_internal_name : string->string->string; - - (* - module filters run before module filters and they should generate valid haxe syntax as a result. - Module filters shouldn't go through the expressions as it adds an unnecessary burden to the GC, - and it can all be done in a single step with gexpr_filters and proper priority selection. - - As a convention, Module filters should end their name with Modf, so they aren't mistaken with expression filters - *) - gmodule_filters : (module_type) rule_map_dispatcher; - - (* - expression filters are the most common filters to be applied. - They should also generate only valid haxe expressions, so e.g. calls to non-existant methods - should be avoided, although there are some ways around them (like gspecial_methods) - *) - gexpr_filters : (texpr) rule_map_dispatcher; - (* - syntax filters are also expression filters but they no longer require - that the resulting expressions be valid haxe expressions. - They then have no guarantee that either the input expressions or the output one follow the same - rules as normal haxe code. - *) - gsyntax_filters : (texpr) rule_map_dispatcher; - - (* these are more advanced features, but they would require a rewrite of targets *) - (* they are just helpers to ditribute functions like "follow" or "type to string" *) - (* so adding a module will already take care of correctly following a certain type of *) - (* variable, for example *) - - (* follows the type through typedefs, lazy typing, etc. *) - (* it's the place to put specific rules to handle typedefs, like *) - (* other basic types like UInt *) - gfollow : (t, t) rule_dispatcher; - - gtypes : (path, module_type) Hashtbl.t; - - (* cast detection helpers / settings *) - (* this is a cache for all field access types *) - greal_field_types : (path * string, (tclass_field (* does the cf exist *) * t (*cf's type in relation to current class type params *) * t * tclass (* declared class *) ) option) Hashtbl.t; - (* this function allows any code to handle casts as if it were inside the cast_detect module *) - mutable ghandle_cast : t->t->texpr->texpr; - (* when an unsafe cast is made, we can warn the user *) - mutable gon_unsafe_cast : t->t->pos->unit; - (* does this type needs to be boxed? Normally always false, unless special type handling must be made *) - mutable gneeds_box : t->bool; - (* does this 'special type' needs cast to this other type? *) - (* this is here so we can implement custom behavior for "opaque" typedefs *) - mutable gspecial_needs_cast : t->t->bool; - (* sometimes we may want to support unrelated conversions on cast detection *) - (* for example, haxe.lang.Null -> T on C# *) - (* every time an unrelated conversion is found, each to/from path is searched on this hashtbl *) - (* if found, the function will be executed with from_type, to_type. If returns true, it means that *) - (* it is a supported conversion, and the unsafe cast routine changes to a simple cast *) - gsupported_conversions : (path, t->t->bool) Hashtbl.t; - - (* API for filters *) - (* add type can be called at any time, and will add a new module_def that may or may not be filtered *) - (* module_type -> should_filter *) - mutable gadd_type : module_type -> bool -> unit; - (* during expr filters, add_to_module will be available so module_types can be added to current module_def. we must pass the priority argument so the filters can be resumed *) - mutable gadd_to_module : module_type -> float -> unit; - (* during expr filters, shows the current class path *) - mutable gcurrent_path : path; - (* current class *) - mutable gcurrent_class : tclass option; - (* current class field, if any *) - mutable gcurrent_classfield : tclass_field option; - - (* events *) - (* is executed once every new classfield *) - mutable gon_classfield_start : (unit -> unit) list; - (* is executed once every new module type *) - mutable gon_new_module_type : (unit -> unit) list; - (* after module filters ended *) - mutable gafter_mod_filters_ended : (unit -> unit) list; - (* after expression filters ended *) - mutable gafter_expr_filters_ended : (unit -> unit) list; - (* after all filters are run *) - mutable gafter_filters_ended : (unit -> unit) list; - - mutable gbase_class_fields : (string, tclass_field) PMap.t; - - (* real type is the type as it is read by the target. *) - (* This function is here because most targets don't have *) - (* a 1:1 translation between haxe types and its native types *) - (* But types aren't changed to this representation as we might lose *) - (* some valuable type information in the process *) - mutable greal_type : t -> t; - (* - the same as greal_type but for type parameters. - *) - mutable greal_type_param : module_type -> tparams -> tparams; - (* - is the type a value type? - This may be used in some optimizations where reference types and value types - are handled differently. At first the default is very good to use, and if tweaks are needed, - it's best to be done by adding @:struct meta to the value types - * - mutable gis_value_type : t -> bool;*) - - (* misc configuration *) - (* - Should the target allow type parameter dynamic conversion, - or should we add a cast to those cases as well? - *) - mutable gallow_tp_dynamic_conversion : bool; - - (* - Does the target support type parameter constraints? - If not, they will be ignored when detecting casts - *) - mutable guse_tp_constraints : bool; - - (* internal apis *) - (* param_func_call : used by TypeParams and CastDetection *) - mutable gparam_func_call : texpr->texpr->tparams->texpr list->texpr; - (* does it already have a type parameter cast handler? This is used by CastDetect to know if it should handle type parameter casts *) - mutable ghas_tparam_cast_handler : bool; - (* type parameter casts - special cases *) - (* function cast_from, cast_to -> texpr *) - gtparam_cast : (path, (texpr->t->texpr)) Hashtbl.t; - - (* - special vars are used for adding special behavior to - *) - gspecial_vars : (string, bool) Hashtbl.t; + (* these are the basic context fields. If another target is using this context, *) + (* this is all you need to care about *) + mutable gcon : Common.context; + + gclasses : gen_classes; + + gtools : gen_tools; + + (* + configurable function that receives a desired name and makes it "internal", doing the best + to ensure that it will not be called from outside. + To avoid name clashes between internal names, user must specify two strings: a "namespace" and the name itself + *) + mutable gmk_internal_name : string->string->string; + + (* + module filters run before module filters and they should generate valid haxe syntax as a result. + Module filters shouldn't go through the expressions as it adds an unnecessary burden to the GC, + and it can all be done in a single step with gexpr_filters and proper priority selection. + + As a convention, Module filters should end their name with Modf, so they aren't mistaken with expression filters + *) + gmodule_filters : (module_type) rule_map_dispatcher; + + (* + expression filters are the most common filters to be applied. + They should also generate only valid haxe expressions, so e.g. calls to non-existant methods + should be avoided, although there are some ways around them (like gspecial_methods) + *) + gexpr_filters : (texpr) rule_map_dispatcher; + (* + syntax filters are also expression filters but they no longer require + that the resulting expressions be valid haxe expressions. + They then have no guarantee that either the input expressions or the output one follow the same + rules as normal haxe code. + *) + gsyntax_filters : (texpr) rule_map_dispatcher; + + (* these are more advanced features, but they would require a rewrite of targets *) + (* they are just helpers to ditribute functions like "follow" or "type to string" *) + (* so adding a module will already take care of correctly following a certain type of *) + (* variable, for example *) + + (* follows the type through typedefs, lazy typing, etc. *) + (* it's the place to put specific rules to handle typedefs, like *) + (* other basic types like UInt *) + gfollow : (t, t) rule_dispatcher; + + gtypes : (path, module_type) Hashtbl.t; + mutable gtypes_list : module_type list; + mutable gmodules : Type.module_def list; + + (* cast detection helpers / settings *) + (* this is a cache for all field access types *) + greal_field_types : (path * string, (tclass_field (* does the cf exist *) * t (*cf's type in relation to current class type params *) * t * tclass (* declared class *) ) option) Hashtbl.t; + (* this function allows any code to handle casts as if it were inside the cast_detect module *) + mutable ghandle_cast : t->t->texpr->texpr; + (* when an unsafe cast is made, we can warn the user *) + mutable gon_unsafe_cast : t->t->pos->unit; + (* does this type needs to be boxed? Normally always false, unless special type handling must be made *) + mutable gneeds_box : t->bool; + (* does this 'special type' needs cast to this other type? *) + (* this is here so we can implement custom behavior for "opaque" typedefs *) + mutable gspecial_needs_cast : t->t->bool; + (* sometimes we may want to support unrelated conversions on cast detection *) + (* for example, haxe.lang.Null -> T on C# *) + (* every time an unrelated conversion is found, each to/from path is searched on this hashtbl *) + (* if found, the function will be executed with from_type, to_type. If returns true, it means that *) + (* it is a supported conversion, and the unsafe cast routine changes to a simple cast *) + gsupported_conversions : (path, t->t->bool) Hashtbl.t; + + (* API for filters *) + (* add type can be called at any time, and will add a new module_def that may or may not be filtered *) + (* module_type -> should_filter *) + mutable gadd_type : module_type -> bool -> unit; + (* during expr filters, add_to_module will be available so module_types can be added to current module_def. we must pass the priority argument so the filters can be resumed *) + mutable gadd_to_module : module_type -> float -> unit; + (* during expr filters, shows the current class path *) + mutable gcurrent_path : path; + (* current class *) + mutable gcurrent_class : tclass option; + (* current class field, if any *) + mutable gcurrent_classfield : tclass_field option; + + (* events *) + (* is executed once every new classfield *) + mutable gon_classfield_start : (unit -> unit) list; + (* is executed once every new module type *) + mutable gon_new_module_type : (unit -> unit) list; + (* after module filters ended *) + mutable gafter_mod_filters_ended : (unit -> unit) list; + (* after expression filters ended *) + mutable gafter_expr_filters_ended : (unit -> unit) list; + (* after all filters are run *) + mutable gafter_filters_ended : (unit -> unit) list; + + mutable gbase_class_fields : (string, tclass_field) PMap.t; + + (* real type is the type as it is read by the target. *) + (* This function is here because most targets don't have *) + (* a 1:1 translation between haxe types and its native types *) + (* But types aren't changed to this representation as we might lose *) + (* some valuable type information in the process *) + mutable greal_type : t -> t; + (* + the same as greal_type but for type parameters. + *) + mutable greal_type_param : module_type -> tparams -> tparams; + (* + is the type a value type? + This may be used in some optimizations where reference types and value types + are handled differently. At first the default is very good to use, and if tweaks are needed, + it's best to be done by adding @:struct meta to the value types + * + mutable gis_value_type : t -> bool;*) + + (* misc configuration *) + (* + Should the target allow type parameter dynamic conversion, + or should we add a cast to those cases as well? + *) + mutable gallow_tp_dynamic_conversion : bool; + + (* + Does the target support type parameter constraints? + If not, they will be ignored when detecting casts + *) + mutable guse_tp_constraints : bool; + + (* internal apis *) + (* param_func_call : used by TypeParams and CastDetection *) + mutable gparam_func_call : texpr->texpr->tparams->texpr list->texpr; + (* does it already have a type parameter cast handler? This is used by CastDetect to know if it should handle type parameter casts *) + mutable ghas_tparam_cast_handler : bool; + (* type parameter casts - special cases *) + (* function cast_from, cast_to -> texpr *) + gtparam_cast : (path, (texpr->t->texpr)) Hashtbl.t; + + (* + special vars are used for adding special behavior to + *) + gspecial_vars : (string, bool) Hashtbl.t; } and gen_classes = { - cl_reflect : tclass; - cl_type : tclass; - cl_dyn : tclass; + cl_reflect : tclass; + cl_type : tclass; + cl_dyn : tclass; - t_iterator : tdef; + t_iterator : tdef; + + mutable nativearray_len : texpr -> pos -> texpr; + mutable nativearray_type : Type.t -> Type.t; + mutable nativearray : Type.t -> Type.t; } (* add here all reflection transformation additions *) and gen_tools = { - (* (klass : texpr, t : t) : texpr *) - mutable r_create_empty : texpr->t->texpr; - (* Reflect.fields(). The bool is if we are iterating in a read-only manner. If it is read-only we might not need to allocate a new array *) - mutable r_fields : bool->texpr->texpr; - (* (first argument = return type. should be void in most cases) Reflect.setField(obj, field, val) *) - mutable r_set_field : t->texpr->texpr->texpr->texpr; - (* Reflect.field. bool indicates if is safe (no error throwing) or unsafe; t is the expected return type true = safe *) - mutable r_field : bool->t->texpr->texpr->texpr; - - (* - these are now the functions that will later be used when creating the reflection classes - *) - - (* on the default implementation (at OverloadingCtors), it will be new SomeClass(EmptyInstance) *) - mutable rf_create_empty : tclass->tparams->pos->texpr; + (* (klass : texpr, t : t) : texpr *) + mutable r_create_empty : texpr->t->texpr; + (* Reflect.fields(). The bool is if we are iterating in a read-only manner. If it is read-only we might not need to allocate a new array *) + mutable r_fields : bool->texpr->texpr; + (* (first argument = return type. should be void in most cases) Reflect.setField(obj, field, val) *) + mutable r_set_field : t->texpr->texpr->texpr->texpr; + (* Reflect.field. bool indicates if is safe (no error throwing) or unsafe; t is the expected return type true = safe *) + mutable r_field : bool->t->texpr->texpr->texpr; + + (* + these are now the functions that will later be used when creating the reflection classes + *) + + (* on the default implementation (at OverloadingCtors), it will be new SomeClass(EmptyInstance) *) + mutable rf_create_empty : tclass->tparams->pos->texpr; } let get_type types path = - List.find (fun md -> match md with - | TClassDecl cl when cl.cl_path = path -> true - | TEnumDecl e when e.e_path = path -> true - | TTypeDecl t when t.t_path = path -> true - | TAbstractDecl a when a.a_path = path -> true - | _ -> false - ) types + List.find (fun md -> match md with + | TClassDecl cl when cl.cl_path = path -> true + | TEnumDecl e when e.e_path = path -> true + | TTypeDecl t when t.t_path = path -> true + | TAbstractDecl a when a.a_path = path -> true + | _ -> false + ) types let new_ctx con = - let types = Hashtbl.create (List.length con.types) in - List.iter (fun mt -> - match mt with - | TClassDecl cl -> Hashtbl.add types cl.cl_path mt - | TEnumDecl e -> Hashtbl.add types e.e_path mt - | TTypeDecl t -> Hashtbl.add types t.t_path mt - | TAbstractDecl a -> Hashtbl.add types a.a_path mt - ) con.types; - - let cl_dyn = match get_type con.types ([], "Dynamic") with - | TClassDecl c -> c - | TAbstractDecl a -> - mk_class a.a_module ([], "Dynamic") a.a_pos - | _ -> assert false - in - - let rec gen = { - gcon = con; - gclasses = { - cl_reflect = get_cl (get_type con.types ([], "Reflect")); - cl_type = get_cl (get_type con.types ([], "Type")); - cl_dyn = cl_dyn; - - t_iterator = get_tdef (get_type con.types ([], "Iterator")); - }; - gtools = { - r_create_empty = (fun eclass t -> - let fieldcall = mk_static_field_access_infer gen.gclasses.cl_type "createEmptyInstance" eclass.epos [t] in - { eexpr = TCall(fieldcall, [eclass]); etype = t; epos = eclass.epos } - ); - r_fields = (fun is_used_only_by_iteration expr -> - let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "fields" expr.epos [] in - { eexpr = TCall(fieldcall, [expr]); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = expr.epos } - ); - (* Reflect.setField(obj, field, val). t by now is ignored. FIXME : fix this implementation *) - r_set_field = (fun t obj field v -> - let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "setField" v.epos [] in - { eexpr = TCall(fieldcall, [obj; field; v]); etype = t_dynamic; epos = v.epos } - ); - (* Reflect.field. bool indicates if is safe (no error throwing) or unsafe. true = safe *) - r_field = (fun is_safe t obj field -> - let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "field" obj.epos [] in - (* FIXME: should we see if needs to cast? *) - mk_cast t { eexpr = TCall(fieldcall, [obj; field]); etype = t_dynamic; epos = obj.epos } - ); - - rf_create_empty = (fun cl p pos -> - gen.gtools.r_create_empty { eexpr = TTypeExpr(TClassDecl cl); epos = pos; etype = t_dynamic } (TInst(cl,p)) - ); (* TODO: Maybe implement using normal reflection? Type.createEmpty(MyClass) *) - }; - gmk_internal_name = (fun ns s -> sprintf "__%s_%s" ns s); - gexpr_filters = new rule_map_dispatcher "gexpr_filters"; - gmodule_filters = new rule_map_dispatcher "gmodule_filters"; - gsyntax_filters = new rule_map_dispatcher "gsyntax_filters"; - gfollow = new rule_dispatcher "gfollow" false; - gtypes = types; - - greal_field_types = Hashtbl.create 0; - ghandle_cast = (fun to_t from_t e -> mk_cast to_t e); - gon_unsafe_cast = (fun t t2 pos -> (gen.gcon.warning ("Type " ^ (debug_type t2) ^ " is being cast to the unrelated type " ^ (s_type (print_context()) t)) pos)); - gneeds_box = (fun t -> false); - gspecial_needs_cast = (fun to_t from_t -> true); - gsupported_conversions = Hashtbl.create 0; - - gadd_type = (fun md should_filter -> - if should_filter then begin - con.types <- md :: con.types; - con.modules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_extra = module_extra "" "" 0. MFake } :: con.modules - end else gen.gafter_filters_ended <- (fun () -> - con.types <- md :: con.types; - con.modules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_extra = module_extra "" "" 0. MFake } :: con.modules - ) :: gen.gafter_filters_ended; - ); - gadd_to_module = (fun md pr -> failwith "module added outside expr filters"); - gcurrent_path = ([],""); - gcurrent_class = None; - gcurrent_classfield = None; - - gon_classfield_start = []; - gon_new_module_type = []; - gafter_mod_filters_ended = []; - gafter_expr_filters_ended = []; - gafter_filters_ended = []; - - gbase_class_fields = PMap.empty; - - greal_type = (fun t -> t); - greal_type_param = (fun _ t -> t); - - gallow_tp_dynamic_conversion = false; - - guse_tp_constraints = false; - - (* as a default, ignore the params *) - gparam_func_call = (fun ecall efield params elist -> { ecall with eexpr = TCall(efield, elist) }); - ghas_tparam_cast_handler = false; - gtparam_cast = Hashtbl.create 0; - - gspecial_vars = Hashtbl.create 0; - } in - - (*gen.gtools.r_create_empty <- - gen.gtools.r_get_class <- - gen.gtools.r_fields <- *) - - gen + let types = Hashtbl.create (List.length con.types) in + List.iter (fun mt -> + match mt with + | TClassDecl cl -> Hashtbl.add types cl.cl_path mt + | TEnumDecl e -> Hashtbl.add types e.e_path mt + | TTypeDecl t -> Hashtbl.add types t.t_path mt + | TAbstractDecl a -> Hashtbl.add types a.a_path mt + ) con.types; + + let cl_dyn = match get_type con.types ([], "Dynamic") with + | TClassDecl c -> c + | TAbstractDecl a -> + mk_class a.a_module ([], "Dynamic") a.a_pos + | _ -> assert false + in + + let rec gen = { + gcon = con; + gclasses = { + cl_reflect = get_cl (get_type con.types ([], "Reflect")); + cl_type = get_cl (get_type con.types ([], "Type")); + cl_dyn = cl_dyn; + + t_iterator = get_tdef (get_type con.types ([], "Iterator")); + + nativearray = (fun _ -> assert false); + nativearray_type = (fun _ -> assert false); + nativearray_len = (fun _ -> assert false); + }; + gtools = { + r_create_empty = (fun eclass t -> + let fieldcall = mk_static_field_access_infer gen.gclasses.cl_type "createEmptyInstance" eclass.epos [t] in + { eexpr = TCall(fieldcall, [eclass]); etype = t; epos = eclass.epos } + ); + r_fields = (fun is_used_only_by_iteration expr -> + let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "fields" expr.epos [] in + { eexpr = TCall(fieldcall, [expr]); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = expr.epos } + ); + (* Reflect.setField(obj, field, val). t by now is ignored. FIXME : fix this implementation *) + r_set_field = (fun t obj field v -> + let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "setField" v.epos [] in + { eexpr = TCall(fieldcall, [obj; field; v]); etype = t_dynamic; epos = v.epos } + ); + (* Reflect.field. bool indicates if is safe (no error throwing) or unsafe. true = safe *) + r_field = (fun is_safe t obj field -> + let fieldcall = mk_static_field_access_infer gen.gclasses.cl_reflect "field" obj.epos [] in + (* FIXME: should we see if needs to cast? *) + mk_cast t { eexpr = TCall(fieldcall, [obj; field]); etype = t_dynamic; epos = obj.epos } + ); + + rf_create_empty = (fun cl p pos -> + gen.gtools.r_create_empty { eexpr = TTypeExpr(TClassDecl cl); epos = pos; etype = t_dynamic } (TInst(cl,p)) + ); (* TODO: Maybe implement using normal reflection? Type.createEmpty(MyClass) *) + }; + gmk_internal_name = (fun ns s -> sprintf "__%s_%s" ns s); + gexpr_filters = new rule_map_dispatcher "gexpr_filters"; + gmodule_filters = new rule_map_dispatcher "gmodule_filters"; + gsyntax_filters = new rule_map_dispatcher "gsyntax_filters"; + gfollow = new rule_dispatcher "gfollow" false; + gtypes = types; + gtypes_list = con.types; + gmodules = con.modules; + + greal_field_types = Hashtbl.create 0; + ghandle_cast = (fun to_t from_t e -> mk_cast to_t e); + gon_unsafe_cast = (fun t t2 pos -> (gen.gcon.warning ("Type " ^ (debug_type t2) ^ " is being cast to the unrelated type " ^ (s_type (print_context()) t)) pos)); + gneeds_box = (fun t -> false); + gspecial_needs_cast = (fun to_t from_t -> true); + gsupported_conversions = Hashtbl.create 0; + + gadd_type = (fun md should_filter -> + if should_filter then begin + gen.gtypes_list <- md :: gen.gtypes_list; + gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_extra = module_extra "" "" 0. MFake } :: gen.gmodules; + Hashtbl.add gen.gtypes (t_path md) md; + end else gen.gafter_filters_ended <- (fun () -> + gen.gtypes_list <- md :: gen.gtypes_list; + gen.gmodules <- { m_id = alloc_mid(); m_path = (t_path md); m_types = [md]; m_extra = module_extra "" "" 0. MFake } :: gen.gmodules; + Hashtbl.add gen.gtypes (t_path md) md; + ) :: gen.gafter_filters_ended; + ); + gadd_to_module = (fun md pr -> failwith "module added outside expr filters"); + gcurrent_path = ([],""); + gcurrent_class = None; + gcurrent_classfield = None; + + gon_classfield_start = []; + gon_new_module_type = []; + gafter_mod_filters_ended = []; + gafter_expr_filters_ended = []; + gafter_filters_ended = []; + + gbase_class_fields = PMap.empty; + + greal_type = (fun t -> t); + greal_type_param = (fun _ t -> t); + + gallow_tp_dynamic_conversion = false; + + guse_tp_constraints = false; + + (* as a default, ignore the params *) + gparam_func_call = (fun ecall efield params elist -> { ecall with eexpr = TCall(efield, elist) }); + ghas_tparam_cast_handler = false; + gtparam_cast = Hashtbl.create 0; + + gspecial_vars = Hashtbl.create 0; + } in + + (*gen.gtools.r_create_empty <- + gen.gtools.r_get_class <- + gen.gtools.r_fields <- *) + + gen let init_ctx gen = - (* ultimately add a follow once handler as the last follow handler *) - let follow_f = gen.gfollow#run in - let follow t = - match t with - | TMono r -> - (match !r with - | Some t -> follow_f t - | _ -> Some t) - | TLazy f -> - follow_f (!f()) - | TType (t,tl) -> - follow_f (apply_params t.t_types tl t.t_type) - | _ -> Some t - in - gen.gfollow#add ~name:"final" ~priority:PLast follow + (* ultimately add a follow once handler as the last follow handler *) + let follow_f = gen.gfollow#run in + let follow t = + match t with + | TMono r -> + (match !r with + | Some t -> follow_f t + | _ -> Some t) + | TLazy f -> + follow_f (!f()) + | TType (t,tl) -> + follow_f (apply_params t.t_params tl t.t_type) + | _ -> Some t + in + gen.gfollow#add ~name:"final" ~priority:PLast follow (* run_follow (gen:generator_ctx) (t:t) *) let run_follow gen = gen.gfollow#run_f let reorder_modules gen = - let modules = Hashtbl.create 20 in - List.iter (fun md -> - Hashtbl.add modules ( (t_infos md).mt_module ).m_path md - ) gen.gcon.types; - - let con = gen.gcon in - con.modules <- []; - let processed = Hashtbl.create 20 in - Hashtbl.iter (fun md_path _ -> - if not (Hashtbl.mem processed md_path) then begin - Hashtbl.add processed md_path true; - con.modules <- { m_id = alloc_mid(); m_path = md_path; m_types = List.rev ( Hashtbl.find_all modules md_path ); m_extra = module_extra "" "" 0. MFake } :: con.modules - end - ) modules + let modules = Hashtbl.create 20 in + List.iter (fun md -> + Hashtbl.add modules ( (t_infos md).mt_module ).m_path md + ) gen.gtypes_list; + + gen.gmodules <- []; + let processed = Hashtbl.create 20 in + Hashtbl.iter (fun md_path md -> + if not (Hashtbl.mem processed md_path) then begin + Hashtbl.add processed md_path true; + gen.gmodules <- { m_id = alloc_mid(); m_path = md_path; m_types = List.rev ( Hashtbl.find_all modules md_path ); m_extra = (t_infos md).mt_module.m_extra } :: gen.gmodules + end + ) modules let run_filters_from gen t filters = - match t with - | TClassDecl c -> - trace (snd c.cl_path); - gen.gcurrent_path <- c.cl_path; - gen.gcurrent_class <- Some(c); - - List.iter (fun fn -> fn()) gen.gon_new_module_type; - - gen.gcurrent_classfield <- None; - let rec process_field f = - gen.gcurrent_classfield <- Some(f); - List.iter (fun fn -> fn()) gen.gon_classfield_start; - - trace f.cf_name; - (match f.cf_expr with - | None -> () - | Some e -> - f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters)); - List.iter process_field f.cf_overloads; - in - List.iter process_field c.cl_ordered_fields; - List.iter process_field c.cl_ordered_statics; - - gen.gcurrent_classfield <- None; - (match c.cl_constructor with - | None -> () - | Some f -> process_field f); - (match c.cl_init with - | None -> () - | Some e -> - c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters)); - | TEnumDecl _ -> () - | TTypeDecl _ -> () - | TAbstractDecl _ -> () + match t with + | TClassDecl c -> + trace (snd c.cl_path); + gen.gcurrent_path <- c.cl_path; + gen.gcurrent_class <- Some(c); + + List.iter (fun fn -> fn()) gen.gon_new_module_type; + + gen.gcurrent_classfield <- None; + let rec process_field f = + reset_temps(); + gen.gcurrent_classfield <- Some(f); + List.iter (fun fn -> fn()) gen.gon_classfield_start; + + trace f.cf_name; + (match f.cf_expr with + | None -> () + | Some e -> + f.cf_expr <- Some (List.fold_left (fun e f -> f e) e filters)); + List.iter process_field f.cf_overloads; + in + List.iter process_field c.cl_ordered_fields; + List.iter process_field c.cl_ordered_statics; + + (match c.cl_constructor with + | None -> () + | Some f -> process_field f); + gen.gcurrent_classfield <- None; + (match c.cl_init with + | None -> () + | Some e -> + c.cl_init <- Some (List.fold_left (fun e f -> f e) e filters)); + | TEnumDecl _ -> () + | TTypeDecl _ -> () + | TAbstractDecl _ -> () let run_filters gen = - (* first of all, we have to make sure that the filters won't trigger a major Gc collection *) - let t = Common.timer "gencommon_filters" in - (if Common.defined gen.gcon Define.GencommonDebug then debug_mode := true); - let run_filters filter = - let rec loop acc mds = - match mds with - | [] -> acc - | md :: tl -> - let filters = [ filter#run_f ] in - let added_types = ref [] in - gen.gadd_to_module <- (fun md_type priority -> - gen.gcon.types <- md_type :: gen.gcon.types; - added_types := (md_type, priority) :: !added_types - ); - - run_filters_from gen md filters; - - let added_types = List.map (fun (t,p) -> - run_filters_from gen t [ fun e -> get (filter#run_from p e) ]; - if Hashtbl.mem gen.gtypes (t_path t) then begin - let rec loop i = - let p = t_path t in - let new_p = (fst p, snd p ^ "_" ^ (string_of_int i)) in - if Hashtbl.mem gen.gtypes new_p then - loop (i+1) - else - match t with - | TClassDecl cl -> cl.cl_path <- new_p - | TEnumDecl e -> e.e_path <- new_p - | TTypeDecl _ | TAbstractDecl _ -> () - in - loop 0 - end; - Hashtbl.add gen.gtypes (t_path t) t; - t - ) !added_types in - - loop (added_types @ (md :: acc)) tl - in - List.rev (loop [] gen.gcon.types) - in - - let run_mod_filter filter = - let last_add_to_module = gen.gadd_to_module in - let added_types = ref [] in - gen.gadd_to_module <- (fun md_type priority -> - Hashtbl.add gen.gtypes (t_path md_type) md_type; - added_types := (md_type, priority) :: !added_types - ); - - let rec loop processed not_processed = - match not_processed with - | hd :: tl -> - let new_hd = filter#run_f hd in - - let added_types_new = !added_types in - added_types := []; - let added_types = List.map (fun (t,p) -> - get (filter#run_from p t) - ) added_types_new in - - loop ( added_types @ (new_hd :: processed) ) tl - | [] -> - processed - in - - let filtered = loop [] gen.gcon.types in - gen.gadd_to_module <- last_add_to_module; - gen.gcon.types <- List.rev (filtered) - in - - run_mod_filter gen.gmodule_filters; - List.iter (fun fn -> fn()) gen.gafter_mod_filters_ended; - - let last_add_to_module = gen.gadd_to_module in - gen.gcon.types <- run_filters gen.gexpr_filters; - gen.gadd_to_module <- last_add_to_module; - - List.iter (fun fn -> fn()) gen.gafter_expr_filters_ended; - (* Codegen.post_process gen.gcon.types [gen.gexpr_filters#run_f]; *) - gen.gcon.types <- run_filters gen.gsyntax_filters; - List.iter (fun fn -> fn()) gen.gafter_filters_ended; - - reorder_modules gen; - t() + let last_error = gen.gcon.error in + let has_errors = ref false in + gen.gcon.error <- (fun msg pos -> has_errors := true; last_error msg pos); + (* first of all, we have to make sure that the filters won't trigger a major Gc collection *) + let t = Common.timer "gencommon_filters" in + (if Common.defined gen.gcon Define.GencommonDebug then debug_mode := true else debug_mode := false); + let run_filters filter = + let rec loop acc mds = + match mds with + | [] -> acc + | md :: tl -> + let filters = [ filter#run_f ] in + let added_types = ref [] in + gen.gadd_to_module <- (fun md_type priority -> + gen.gtypes_list <- md_type :: gen.gtypes_list; + added_types := (md_type, priority) :: !added_types + ); + + run_filters_from gen md filters; + + let added_types = List.map (fun (t,p) -> + run_filters_from gen t [ fun e -> get (filter#run_from p e) ]; + if Hashtbl.mem gen.gtypes (t_path t) then begin + let rec loop i = + let p = t_path t in + let new_p = (fst p, snd p ^ "_" ^ (string_of_int i)) in + if Hashtbl.mem gen.gtypes new_p then + loop (i+1) + else + match t with + | TClassDecl cl -> cl.cl_path <- new_p + | TEnumDecl e -> e.e_path <- new_p + | TTypeDecl _ | TAbstractDecl _ -> () + in + loop 0 + end; + Hashtbl.add gen.gtypes (t_path t) t; + t + ) !added_types in + + loop (added_types @ (md :: acc)) tl + in + List.rev (loop [] gen.gtypes_list) + in + + let run_mod_filter filter = + let last_add_to_module = gen.gadd_to_module in + let added_types = ref [] in + gen.gadd_to_module <- (fun md_type priority -> + Hashtbl.add gen.gtypes (t_path md_type) md_type; + added_types := (md_type, priority) :: !added_types + ); + + let rec loop processed not_processed = + match not_processed with + | hd :: tl -> + (match hd with + | TClassDecl c -> + gen.gcurrent_class <- Some c + | _ -> + gen.gcurrent_class <- None); + let new_hd = filter#run_f hd in + + let added_types_new = !added_types in + added_types := []; + let added_types = List.map (fun (t,p) -> + get (filter#run_from p t) + ) added_types_new in + + loop ( added_types @ (new_hd :: processed) ) tl + | [] -> + processed + in + + let filtered = loop [] gen.gtypes_list in + gen.gadd_to_module <- last_add_to_module; + gen.gtypes_list <- List.rev (filtered) + in + + run_mod_filter gen.gmodule_filters; + List.iter (fun fn -> fn()) gen.gafter_mod_filters_ended; + + let last_add_to_module = gen.gadd_to_module in + gen.gtypes_list <- run_filters gen.gexpr_filters; + gen.gadd_to_module <- last_add_to_module; + + List.iter (fun fn -> fn()) gen.gafter_expr_filters_ended; + (* Codegen.post_process gen.gtypes_list [gen.gexpr_filters#run_f]; *) + gen.gtypes_list <- run_filters gen.gsyntax_filters; + List.iter (fun fn -> fn()) gen.gafter_filters_ended; + + reorder_modules gen; + t(); + if !has_errors then raise (Abort("Compilation aborted with errors",null_pos)) (* ******************************************* *) (* basic generation module that source code compilation implementations can use *) (* ******************************************* *) -let write_file gen w source_dir path extension = - let t = timer "write file" in - let s_path = gen.gcon.file ^ "/" ^ source_dir ^ "/" ^ (String.concat "/" (fst path)) ^ "/" ^ (snd path) ^ "." ^ (extension) in - (* create the folders if they don't exist *) - let rec create 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 (d :: acc) l - in - let p = gen.gcon.file :: source_dir :: fst path in - create [] p; - - let contents = SourceWriter.contents w in - let should_write = if not (Common.defined gen.gcon Define.ReplaceFiles) && Sys.file_exists s_path then begin - let in_file = open_in s_path in - let old_contents = Std.input_all in_file in - close_in in_file; - contents <> old_contents - end else true in - - if should_write then begin - let f = open_out s_path in - output_string f contents; - close_out f - end; - t() +let write_file gen w source_dir path extension out_files = + let t = timer "write file" in + let s_path = source_dir ^ "/" ^ (snd path) ^ "." ^ (extension) in + (* create the folders if they don't exist *) + mkdir_from_path s_path; + + let contents = SourceWriter.contents w in + let should_write = if not (Common.defined gen.gcon Define.ReplaceFiles) && Sys.file_exists s_path then begin + let in_file = open_in s_path in + let old_contents = Std.input_all in_file in + close_in in_file; + contents <> old_contents + end else true in + + if should_write then begin + let f = open_out_bin s_path in + output_string f contents; + close_out f + end; + + out_files := (unique_full_path s_path) :: !out_files; + + t() + + +let clean_files path excludes verbose = + let rec iter_files pack dir path = try + let file = Unix.readdir dir in + + if file <> "." && file <> ".." then begin + let filepath = path ^ "/" ^ file in + if (Unix.stat filepath).st_kind = S_DIR then + 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 (unique_full_path filepath) excludes) then begin + if verbose then print_endline ("Removing " ^ filepath); + Sys.remove filepath + end + end; + + iter_files pack dir path + with | End_of_file | Unix.Unix_error _ -> + Unix.closedir dir + in + iter_files [] (Unix.opendir path) path + let dump_descriptor gen name path_s module_s = - let w = SourceWriter.new_source_writer () in - (* dump called path *) - SourceWriter.write w (Sys.getcwd()); - SourceWriter.newline w; - (* dump all defines. deprecated *) - SourceWriter.write w "begin defines"; - SourceWriter.newline w; - PMap.iter (fun name _ -> - SourceWriter.write w name; - SourceWriter.newline w - ) gen.gcon.defines; - SourceWriter.write w "end defines"; - SourceWriter.newline w; - (* dump all defines with their values; keeping the old defines for compatibility *) - SourceWriter.write w "begin defines_data"; - SourceWriter.newline w; - PMap.iter (fun name v -> - SourceWriter.write w name; - SourceWriter.write w "="; - SourceWriter.write w v; - SourceWriter.newline w - ) gen.gcon.defines; - SourceWriter.write w "end defines_data"; - SourceWriter.newline w; - (* dump all generated types *) - SourceWriter.write w "begin modules"; - SourceWriter.newline w; - let main_paths = Hashtbl.create 0 in - List.iter (fun md_def -> - SourceWriter.write w "M "; - SourceWriter.write w (path_s md_def.m_path); - SourceWriter.newline w; - List.iter (fun m -> - match m with - | TClassDecl cl when not cl.cl_extern -> - SourceWriter.write w "C "; - let s = module_s m in - Hashtbl.add main_paths cl.cl_path s; - SourceWriter.write w (s); - SourceWriter.newline w - | TEnumDecl e when not e.e_extern -> - SourceWriter.write w "E "; - SourceWriter.write w (module_s m); - SourceWriter.newline w - | _ -> () (* still no typedef or abstract is generated *) - ) md_def.m_types - ) gen.gcon.modules; - 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 + let w = SourceWriter.new_source_writer () in + (* dump called path *) + SourceWriter.write w (Sys.getcwd()); + SourceWriter.newline w; + (* dump all defines. deprecated *) + SourceWriter.write w "begin defines"; + SourceWriter.newline w; + PMap.iter (fun name _ -> + SourceWriter.write w name; + SourceWriter.newline w + ) gen.gcon.defines; + SourceWriter.write w "end defines"; + SourceWriter.newline w; + (* dump all defines with their values; keeping the old defines for compatibility *) + SourceWriter.write w "begin defines_data"; + SourceWriter.newline w; + PMap.iter (fun name v -> + SourceWriter.write w name; + SourceWriter.write w "="; + SourceWriter.write w v; + SourceWriter.newline w + ) gen.gcon.defines; + SourceWriter.write w "end defines_data"; + SourceWriter.newline w; + (* dump all generated types *) + SourceWriter.write w "begin modules"; + SourceWriter.newline w; + let main_paths = Hashtbl.create 0 in + List.iter (fun md_def -> + SourceWriter.write w "M "; + SourceWriter.write w (path_s (path_of_md_def md_def)); + SourceWriter.newline w; + List.iter (fun m -> + match m with + | TClassDecl cl when not cl.cl_extern -> + SourceWriter.write w "C "; + let s = module_s m in + Hashtbl.add main_paths cl.cl_path s; + SourceWriter.write w (s); + SourceWriter.newline w + | TEnumDecl e when not e.e_extern -> + SourceWriter.write w "E "; + SourceWriter.write w (module_s m); + SourceWriter.newline w + | _ -> () (* still no typedef or abstract is generated *) + ) md_def.m_types + ) gen.gmodules; + 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 | _ -> () - ); - SourceWriter.write w "begin resources"; - SourceWriter.newline w; - Hashtbl.iter (fun name _ -> - SourceWriter.write w name; - SourceWriter.newline w - ) gen.gcon.resources; - SourceWriter.write w "end resources"; - SourceWriter.newline w; - SourceWriter.write w "begin libs"; - SourceWriter.newline w; - if Common.platform gen.gcon Java then - List.iter (fun (s,std,_,_,_) -> - if not std then begin - SourceWriter.write w s; - SourceWriter.newline w; - end - ) gen.gcon.java_libs; - SourceWriter.write w "end libs"; - - let contents = SourceWriter.contents w in - let f = open_out (gen.gcon.file ^ "/" ^ name) in - output_string f contents; - close_out f + ); + SourceWriter.write w "begin resources"; + SourceWriter.newline w; + Hashtbl.iter (fun name _ -> + SourceWriter.write w name; + SourceWriter.newline w + ) gen.gcon.resources; + SourceWriter.write w "end resources"; + SourceWriter.newline w; + SourceWriter.write w "begin libs"; + SourceWriter.newline w; + let path file ext = + if Sys.file_exists file then + file + else try Common.find_file gen.gcon file with + | Not_found -> try Common.find_file gen.gcon (file ^ ext) with + | Not_found -> + file + in + if Common.platform gen.gcon Java then + List.iter (fun (s,std,_,_,_) -> + if not std then begin + SourceWriter.write w (path s ".jar"); + SourceWriter.newline w; + end + ) gen.gcon.java_libs + else if Common.platform gen.gcon Cs then + List.iter (fun (s,std,_,_) -> + if not std then begin + SourceWriter.write w (path s ".dll"); + SourceWriter.newline w; + end + ) gen.gcon.net_libs; + SourceWriter.write w "end libs"; + SourceWriter.newline w; + let args = gen.gcon.c_args in + if args <> [] then begin + SourceWriter.write w "begin opts"; + SourceWriter.newline w; + List.iter (fun opt -> SourceWriter.write w opt; SourceWriter.newline w) (List.rev args); + SourceWriter.write w "end opts"; + SourceWriter.newline w; + end; + + let contents = SourceWriter.contents w in + let f = open_out (gen.gcon.file ^ "/" ^ name) in + output_string f contents; + close_out f + +let path_regex = Str.regexp "[/\\]+" + +let normalize path = + let rec normalize acc m = match m with + | [] -> + List.rev acc + | Str.Text "." :: Str.Delim _ :: tl when acc = [] -> + normalize [] tl + | Str.Text ".." :: Str.Delim _ :: tl -> (match acc with + | [] -> raise Exit + | _ :: acc -> normalize acc tl) + | Str.Text t :: Str.Delim _ :: tl -> + normalize (t :: acc) tl + | Str.Delim _ :: tl -> + normalize ("" :: acc) tl + | Str.Text t :: [] -> + List.rev (t :: acc) + | Str.Text _ :: Str.Text _ :: _ -> assert false + in + String.concat "/" (normalize [] (Str.full_split path_regex path)) + +let is_relative cwd rel = + try + let rel = normalize rel in + Filename.is_relative rel || (String.starts_with rel cwd || String.starts_with (Common.unique_full_path rel) cwd) + with | Exit -> + String.starts_with rel cwd || String.starts_with (Common.unique_full_path rel) cwd (* - helper function to create the source structure. Will send each module_def to the function passed. - If received true, it means that module_gen has generated this content, so the file must be saved. - See that it will write a whole module + helper function to create the source structure. Will send each module_def to the function passed. + If received true, it means that module_gen has generated this content, so the file must be saved. + See that it will write a whole module *) -let generate_modules gen extension source_dir (module_gen : SourceWriter.source_writer->module_def->bool) = - List.iter (fun md_def -> - let w = SourceWriter.new_source_writer () in - (*let should_write = List.fold_left (fun should md -> module_gen w md or should) false md_def.m_types in*) - let should_write = module_gen w md_def in - if should_write then begin - let path = md_def.m_path in - write_file gen w source_dir path extension; - - - end - ) gen.gcon.modules - -let generate_modules_t gen extension source_dir change_path (module_gen : SourceWriter.source_writer->module_type->bool) = - List.iter (fun md -> - let w = SourceWriter.new_source_writer () in - (*let should_write = List.fold_left (fun should md -> module_gen w md or should) false md_def.m_types in*) - let should_write = module_gen w md in - if should_write then begin - let path = change_path (t_path md) in - write_file gen w source_dir path extension; - end - ) gen.gcon.types +let generate_modules gen extension source_dir (module_gen : SourceWriter.source_writer->module_def->bool) out_files = + List.iter (fun md_def -> + let source_dir = + gen.gcon.file ^ "/" ^ source_dir ^ "/" ^ (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_gen w md or should) false md_def.m_types in*) + let should_write = module_gen w md_def in + if should_write then begin + let path = path_of_md_def md_def in + write_file gen w source_dir path extension out_files + end + ) gen.gmodules + +let generate_modules_t gen extension source_dir change_path (module_gen : SourceWriter.source_writer->module_type->bool) out_files = + let source_dir = gen.gcon.file ^ "/" ^ source_dir in + List.iter (fun md -> + let w = SourceWriter.new_source_writer () in + (*let should_write = List.fold_left (fun should md -> module_gen w md or should) false md_def.m_types in*) + let should_write = module_gen w md in + if should_write then begin + let path = change_path (t_path md) in + write_file gen w (source_dir ^ "/" ^ (String.concat "/" (fst path))) path extension out_files; + end + ) gen.gtypes_list (* - various helper functions + various helper functions *) let mk_paren e = - match e.eexpr with | TParenthesis _ -> e | _ -> { e with eexpr=TParenthesis(e) } + match e.eexpr with | TParenthesis _ -> e | _ -> { e with eexpr=TParenthesis(e) } (* private *) -let tmp_count = ref 0 let get_real_fun gen t = - match follow t with - | TFun(args,t) -> TFun(List.map (fun (n,o,t) -> n,o,gen.greal_type t) args, gen.greal_type t) - | _ -> t + match follow t with + | TFun(args,t) -> TFun(List.map (fun (n,o,t) -> n,o,gen.greal_type t) args, gen.greal_type t) + | _ -> t let mk_int gen i pos = { eexpr = TConst(TInt ( Int32.of_int i)); etype = gen.gcon.basic.tint; epos = pos } let mk_return e = { eexpr = TReturn (Some e); etype = e.etype; epos = e.epos } let mk_temp gen name t = - incr tmp_count; - let name = gen.gmk_internal_name "temp" (name ^ (string_of_int !tmp_count)) in - alloc_var name t + incr tmp_count; + let name = gen.gmk_internal_name "temp" (name ^ (string_of_int !tmp_count)) in + alloc_var name t + +let v_nativearray = alloc_var "__array__" t_dynamic +let mk_nativearray_decl gen t el pos = + { + eexpr = TCall(mk_local v_nativearray pos, el); + etype = gen.gclasses.nativearray t; + epos = pos; + } let ensure_local gen block name e = - match e.eexpr with - | TLocal _ -> e - | _ -> - let var = mk_temp gen name e.etype in - block := { e with eexpr = TVars([ var, Some e ]); etype = gen.gcon.basic.tvoid; } :: !block; - { e with eexpr = TLocal var } - -let reset_temps () = tmp_count := 0 + match e.eexpr with + | TLocal _ -> e + | _ -> + let var = mk_temp gen name e.etype in + block := { e with eexpr = TVar(var, Some e); etype = gen.gcon.basic.tvoid; } :: !block; + { e with eexpr = TLocal var } let follow_module follow_func md = match md with - | TClassDecl _ - | TEnumDecl _ - | TAbstractDecl _ -> md - | TTypeDecl tdecl -> match (follow_func (TType(tdecl, List.map snd tdecl.t_types))) with - | TInst(cl,_) -> TClassDecl cl - | TEnum(e,_) -> TEnumDecl e - | TType(t,_) -> TTypeDecl t - | TAbstract(a,_) -> TAbstractDecl a - | _ -> assert false + | TClassDecl _ + | TEnumDecl _ + | TAbstractDecl _ -> md + | TTypeDecl tdecl -> match (follow_func (TType(tdecl, List.map snd tdecl.t_params))) with + | TInst(cl,_) -> TClassDecl cl + | TEnum(e,_) -> TEnumDecl e + | TType(t,_) -> TTypeDecl t + | TAbstract(a,_) -> TAbstractDecl a + | _ -> assert false (* - hxgen means if the type was generated by haxe. If a type was generated by haxe, it means - it will contain special constructs for speedy reflection, for example + hxgen means if the type was generated by haxe. If a type was generated by haxe, it means + it will contain special constructs for speedy reflection, for example - @see SetHXGen module + @see SetHXGen module *) let rec is_hxgen md = - match md with - | TClassDecl cl -> Meta.has Meta.HxGen cl.cl_meta - | TEnumDecl e -> Meta.has Meta.HxGen e.e_meta - | TTypeDecl t -> Meta.has Meta.HxGen t.t_meta || ( match follow t.t_type with | TInst(cl,_) -> is_hxgen (TClassDecl cl) | TEnum(e,_) -> is_hxgen (TEnumDecl e) | _ -> false ) - | TAbstractDecl a -> Meta.has Meta.HxGen a.a_meta + match md with + | TClassDecl cl -> Meta.has Meta.HxGen cl.cl_meta + | TEnumDecl e -> Meta.has Meta.HxGen e.e_meta + | TTypeDecl t -> Meta.has Meta.HxGen t.t_meta || ( match follow t.t_type with | TInst(cl,_) -> is_hxgen (TClassDecl cl) | TEnum(e,_) -> is_hxgen (TEnumDecl e) | _ -> false ) + | TAbstractDecl a -> Meta.has Meta.HxGen a.a_meta let is_hxgen_t t = - match t with - | TInst (cl, _) -> Meta.has Meta.HxGen cl.cl_meta - | TEnum (e, _) -> Meta.has Meta.HxGen e.e_meta - | TAbstract (a, _) -> Meta.has Meta.HxGen a.a_meta - | TType (t, _) -> Meta.has Meta.HxGen t.t_meta - | _ -> false + match t with + | TInst (cl, _) -> Meta.has Meta.HxGen cl.cl_meta + | TEnum (e, _) -> Meta.has Meta.HxGen e.e_meta + | TAbstract (a, _) -> Meta.has Meta.HxGen a.a_meta + | TType (t, _) -> Meta.has Meta.HxGen t.t_meta + | _ -> false let mt_to_t_dyn md = - match md with - | TClassDecl cl -> TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_types) - | TEnumDecl e -> TEnum(e, List.map (fun _ -> t_dynamic) e.e_types) - | TAbstractDecl a -> TAbstract(a, List.map (fun _ -> t_dynamic) a.a_types) - | TTypeDecl t -> TType(t, List.map (fun _ -> t_dynamic) t.t_types) + match md with + | TClassDecl cl -> TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_params) + | TEnumDecl e -> TEnum(e, List.map (fun _ -> t_dynamic) e.e_params) + | TAbstractDecl a -> TAbstract(a, List.map (fun _ -> t_dynamic) a.a_params) + | TTypeDecl t -> TType(t, List.map (fun _ -> t_dynamic) t.t_params) let mt_to_t mt params = - match mt with - | TClassDecl (cl) -> TInst(cl, params) - | TEnumDecl (e) -> TEnum(e, params) - | TAbstractDecl a -> TAbstract(a, params) - | _ -> assert false + match mt with + | TClassDecl (cl) -> TInst(cl, params) + | TEnumDecl (e) -> TEnum(e, params) + | TAbstractDecl a -> TAbstract(a, params) + | _ -> assert false let t_to_mt t = - match follow t with - | TInst(cl, _) -> TClassDecl(cl) - | TEnum(e, _) -> TEnumDecl(e) - | TAbstract(a, _) -> TAbstractDecl a - | _ -> assert false - -let mk_paren e = - match e.eexpr with - | TParenthesis _ -> e - | _ -> { e with eexpr = TParenthesis(e) } + match follow t with + | TInst(cl, _) -> TClassDecl(cl) + | TEnum(e, _) -> TEnumDecl(e) + | TAbstract(a, _) -> TAbstractDecl a + | _ -> assert false 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 + 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 let add_constructor cl cf = - match cl.cl_constructor with - | None -> cl.cl_constructor <- Some cf - | Some ctor -> - if ctor != cf && not (List.memq cf ctor.cf_overloads) then - ctor.cf_overloads <- cf :: ctor.cf_overloads + match cl.cl_constructor with + | None -> cl.cl_constructor <- Some cf + | Some ctor -> + if ctor != cf && not (List.memq cf ctor.cf_overloads) then + ctor.cf_overloads <- cf :: ctor.cf_overloads (* replace open TMonos with TDynamic *) let rec replace_mono t = - match follow t with - | TMono t -> t := Some t_dynamic - | TEnum (_,p) | TInst (_,p) | TType (_,p) | TAbstract (_,p) -> - List.iter replace_mono p - | TFun (args,ret) -> - List.iter (fun (_,_,t) -> replace_mono t) args; - replace_mono ret - | TAnon _ - | TDynamic _ -> () - | _ -> assert false - + match t with + | TMono t -> + (match !t with + | None -> t := Some t_dynamic + | Some _ -> ()) + | TEnum (_,p) | TInst (_,p) | TType (_,p) | TAbstract (_,p) -> + List.iter replace_mono p + | TFun (args,ret) -> + List.iter (fun (_,_,t) -> replace_mono t) args; + replace_mono ret + | TAnon _ + | TDynamic _ -> () + | TLazy f -> + replace_mono (!f()) (* helper *) let mk_class_field name t public pos kind params = - { - cf_name = name; - cf_type = t; - cf_public = public; - cf_pos = pos; - cf_doc = None; - cf_meta = [ Meta.CompilerGenerated, [], Ast.null_pos ]; (* annotate that this class field was generated by the compiler *) - cf_kind = kind; - cf_params = params; - cf_expr = None; - cf_overloads = []; - } + { + cf_name = name; + cf_type = t; + cf_public = public; + cf_pos = pos; + cf_doc = None; + cf_meta = [ Meta.CompilerGenerated, [], Ast.null_pos ]; (* annotate that this class field was generated by the compiler *) + cf_kind = kind; + cf_params = params; + cf_expr = None; + cf_overloads = []; + } (* this helper just duplicates the type parameter class, which is assumed that cl is. *) (* This is so we can use class parameters on function parameters, without running the risk of name clash *) (* between both *) let map_param cl = - let ret = mk_class cl.cl_module cl.cl_path cl.cl_pos in - ret.cl_implements <- cl.cl_implements; - ret.cl_kind <- cl.cl_kind; - ret + let ret = mk_class cl.cl_module (fst cl.cl_path, snd cl.cl_path ^ "_c") cl.cl_pos in + ret.cl_implements <- cl.cl_implements; + ret.cl_kind <- cl.cl_kind; + ret let get_cl_t t = - match follow t with | TInst (cl,_) -> cl | _ -> assert false + match follow t with | TInst (cl,_) -> cl | _ -> assert false let mk_class m path pos = - let cl = Type.mk_class m path pos in - cl.cl_meta <- [ Meta.CompilerGenerated, [], Ast.null_pos ]; - cl + let cl = Type.mk_class m path pos in + cl.cl_meta <- [ Meta.CompilerGenerated, [], Ast.null_pos ]; + cl type tfield_access = - | FClassField of tclass * tparams * tclass (* declared class *) * tclass_field * bool (* is static? *) * t (* the actual cf type, in relation to the class type params *) * t (* declared type *) - | FEnumField of tenum * tenum_field * bool (* is parameterized enum ? *) - | FAnonField of tclass_field - | FDynamicField of t - | FNotFound - -let find_first_declared_field gen orig_cl ?exact_field field = - let chosen = ref None in - let is_overload = ref false in - let rec loop_cl depth c tl tlch = - (try - let ret = PMap.find field c.cl_fields in - if Meta.has Meta.Overload ret.cf_meta then is_overload := true; - match !chosen, exact_field with - | Some(d,_,_,_,_), _ when depth <= d -> () - | _, None -> - chosen := Some(depth,ret,c,tl,tlch) - | _, Some f2 -> - List.iter (fun f -> - let declared_t = apply_params c.cl_types tl f.cf_type in - if Typeload.same_overload_args declared_t f2.cf_type f f2 then - chosen := Some(depth,f,c,tl,tlch) - ) (ret :: ret.cf_overloads) - with | Not_found -> ()); - (match c.cl_super with - | Some (sup,stl) -> - let tl = List.map (apply_params c.cl_types tl) stl in - let stl = gen.greal_type_param (TClassDecl sup) stl in - let tlch = List.map (apply_params c.cl_types tlch) stl in - loop_cl (depth+1) sup tl tlch - | None -> ()); - if c.cl_interface then - List.iter (fun (sup,stl) -> - let tl = List.map (apply_params c.cl_types tl) stl in - let stl = gen.greal_type_param (TClassDecl sup) stl in - let tlch = List.map (apply_params c.cl_types tlch) stl in - loop_cl (depth+1) sup tl tlch - ) c.cl_implements - in - loop_cl 0 orig_cl (List.map snd orig_cl.cl_types) (List.map snd orig_cl.cl_types); - match !chosen with - | None -> None - | Some(_,f,c,tl,tlch) -> - if !is_overload && not (Meta.has Meta.Overload f.cf_meta) then - f.cf_meta <- (Meta.Overload,[],f.cf_pos) :: f.cf_meta; - let declared_t = apply_params c.cl_types tl f.cf_type in - let params_t = apply_params c.cl_types tlch f.cf_type in - let actual_t = match follow params_t with - | TFun(args,ret) -> TFun(List.map (fun (n,o,t) -> (n,o,gen.greal_type t)) args, gen.greal_type ret) - | _ -> gen.greal_type params_t in - Some(f,actual_t,declared_t,params_t,c,tl,tlch) + | FClassField of tclass * tparams * tclass (* declared class *) * tclass_field * bool (* is static? *) * t (* the actual cf type, in relation to the class type params *) * t (* declared type *) + | FEnumField of tenum * tenum_field * bool (* is parameterized enum ? *) + | FAnonField of tclass_field + | FDynamicField of t + | FNotFound + +let is_var f = match f.cf_kind with | Var _ -> true | _ -> false + +let find_first_declared_field gen orig_cl ?get_vmtype ?exact_field field = + let get_vmtype = match get_vmtype with None -> (fun t -> t) | Some f -> f in + let chosen = ref None in + let is_overload = ref false in + let rec loop_cl depth c tl tlch = + (try + let ret = PMap.find field c.cl_fields in + if Meta.has Meta.Overload ret.cf_meta then is_overload := true; + match !chosen, exact_field with + | Some(d,f,_,_,_), _ when depth <= d || (is_var ret && not (is_var f)) -> () + | _, None -> + chosen := Some(depth,ret,c,tl,tlch) + | _, Some f2 -> + List.iter (fun f -> + let declared_t = apply_params c.cl_params tl f.cf_type in + if Typeload.same_overload_args ~get_vmtype declared_t f2.cf_type f f2 then + chosen := Some(depth,f,c,tl,tlch) + ) (ret :: ret.cf_overloads) + with | Not_found -> ()); + (match c.cl_super with + | Some (sup,stl) -> + let tl = List.map (apply_params c.cl_params tl) stl in + let stl = gen.greal_type_param (TClassDecl sup) stl in + let tlch = List.map (apply_params c.cl_params tlch) stl in + loop_cl (depth+1) sup tl tlch + | None -> ()); + if c.cl_interface then + List.iter (fun (sup,stl) -> + let tl = List.map (apply_params c.cl_params tl) stl in + let stl = gen.greal_type_param (TClassDecl sup) stl in + let tlch = List.map (apply_params c.cl_params tlch) stl in + loop_cl (depth+1) sup tl tlch + ) c.cl_implements + in + loop_cl 0 orig_cl (List.map snd orig_cl.cl_params) (List.map snd orig_cl.cl_params); + match !chosen with + | None -> None + | Some(_,f,c,tl,tlch) -> + if !is_overload && not (Meta.has Meta.Overload f.cf_meta) then + f.cf_meta <- (Meta.Overload,[],f.cf_pos) :: f.cf_meta; + let declared_t = apply_params c.cl_params tl f.cf_type in + let params_t = apply_params c.cl_params tlch f.cf_type in + let actual_t = match follow params_t with + | TFun(args,ret) -> TFun(List.map (fun (n,o,t) -> (n,o,gen.greal_type t)) args, gen.greal_type ret) + | _ -> gen.greal_type params_t in + Some(f,actual_t,declared_t,params_t,c,tl,tlch) let field_access gen (t:t) (field:string) : (tfield_access) = - (* - t can be either an haxe-type as a real-type; - 'follow' should be applied here since we can generalize that a TType will be accessible as its - underlying type. - *) - - match follow t with - | TInst(cl, params) -> - let orig_cl = cl in - let orig_params = params in - let rec not_found cl params = - match cl.cl_dynamic with - | Some t -> - let t = apply_params cl.cl_types params t in - FDynamicField t - | None -> - match cl.cl_super with - | None -> FNotFound - | Some (super,p) -> not_found super p - in - - let not_found () = - try - let cf = PMap.find field gen.gbase_class_fields in - FClassField (orig_cl, orig_params, gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) - with - | Not_found -> not_found cl params - in - - (* this is a hack for C#'s different generic types with same path *) - let hashtbl_field = (String.concat "" (List.map (fun _ -> "]") cl.cl_types)) ^ field in - let types = try - Hashtbl.find gen.greal_field_types (orig_cl.cl_path, hashtbl_field) - with | Not_found -> - let ret = find_first_declared_field gen cl field in - let ret = match ret with - | None -> None - | Some(cf,t,dt,_,cl,_,_) -> Some(cf,t,dt,cl) - in - Hashtbl.add gen.greal_field_types (orig_cl.cl_path, hashtbl_field) ret; - ret - in - (match types with - | None -> not_found() - | Some (cf, actual_t, declared_t, declared_cl) -> - FClassField(orig_cl, orig_params, declared_cl, cf, false, actual_t, declared_t)) - | TEnum _ | TAbstract _ -> - (* enums have no field *) FNotFound - | TAnon anon -> - (try match !(anon.a_status) with - | Statics cl -> - let cf = PMap.find field cl.cl_statics in - FClassField(cl, List.map (fun _ -> t_dynamic) cl.cl_types, cl, cf, true, cf.cf_type, cf.cf_type) - | EnumStatics e -> - let f = PMap.find field e.e_constrs in - let is_param = match follow f.ef_type with | TFun _ -> true | _ -> false in - FEnumField(e, f, is_param) - | _ when PMap.mem field gen.gbase_class_fields -> - let cf = PMap.find field gen.gbase_class_fields in - FClassField(gen.gclasses.cl_dyn, [t_dynamic], gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) - | _ -> - FAnonField(PMap.find field anon.a_fields) - with | Not_found -> FNotFound) - | _ when PMap.mem field gen.gbase_class_fields -> - let cf = PMap.find field gen.gbase_class_fields in - FClassField(gen.gclasses.cl_dyn, [t_dynamic], gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) - | TDynamic t -> FDynamicField t - | TMono _ -> FDynamicField t_dynamic - | _ -> FNotFound + (* + t can be either an haxe-type as a real-type; + 'follow' should be applied here since we can generalize that a TType will be accessible as its + underlying type. + *) + + (* let pointers to values be accessed as the underlying values *) + let t = match gen.greal_type t with + | TAbstract({ a_path = ["cs"],"Pointer" },[t]) -> + gen.greal_type t + | _ -> t + in + + match follow t with + | TInst(cl, params) -> + let orig_cl = cl in + let orig_params = params in + let rec not_found cl params = + match cl.cl_dynamic with + | Some t -> + let t = apply_params cl.cl_params params t in + FDynamicField t + | None -> + match cl.cl_super with + | None -> FNotFound + | Some (super,p) -> not_found super p + in + + let not_found () = + try + let cf = PMap.find field gen.gbase_class_fields in + FClassField (orig_cl, orig_params, gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) + with + | Not_found -> not_found cl params + in + + (* this is a hack for C#'s different generic types with same path *) + let hashtbl_field = (String.concat "" (List.map (fun _ -> "]") cl.cl_params)) ^ field in + let types = try + Hashtbl.find gen.greal_field_types (orig_cl.cl_path, hashtbl_field) + with | Not_found -> + let ret = find_first_declared_field gen cl field in + let ret = match ret with + | None -> None + | Some(cf,t,dt,_,cl,_,_) -> Some(cf,t,dt,cl) + in + if ret <> None then Hashtbl.add gen.greal_field_types (orig_cl.cl_path, hashtbl_field) ret; + ret + in + (match types with + | None -> not_found() + | Some (cf, actual_t, declared_t, declared_cl) -> + FClassField(orig_cl, orig_params, declared_cl, cf, false, actual_t, declared_t)) + | TEnum _ | TAbstract _ -> + (* enums have no field *) FNotFound + | TAnon anon -> + (try match !(anon.a_status) with + | Statics cl -> + let cf = PMap.find field cl.cl_statics in + FClassField(cl, List.map (fun _ -> t_dynamic) cl.cl_params, cl, cf, true, cf.cf_type, cf.cf_type) + | EnumStatics e -> + let f = PMap.find field e.e_constrs in + let is_param = match follow f.ef_type with | TFun _ -> true | _ -> false in + FEnumField(e, f, is_param) + | _ when PMap.mem field gen.gbase_class_fields -> + let cf = PMap.find field gen.gbase_class_fields in + FClassField(gen.gclasses.cl_dyn, [t_dynamic], gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) + | _ -> + FAnonField(PMap.find field anon.a_fields) + with | Not_found -> FNotFound) + | _ when PMap.mem field gen.gbase_class_fields -> + let cf = PMap.find field gen.gbase_class_fields in + FClassField(gen.gclasses.cl_dyn, [t_dynamic], gen.gclasses.cl_dyn, cf, false, cf.cf_type, cf.cf_type) + | TDynamic t -> FDynamicField t + | TMono _ -> FDynamicField t_dynamic + | _ -> FNotFound + +let field_access_esp gen t field = match field with + | FStatic(cl,cf) | FInstance(cl,_,cf) when Meta.has Meta.Extern cf.cf_meta -> + let static = match field with + | FStatic _ -> true + | _ -> false + in + let p = match follow (run_follow gen t) with + | TInst(_,p) -> p + | _ -> List.map snd cl.cl_params + in + FClassField(cl,p,cl,cf,static,cf.cf_type,cf.cf_type) + | _ -> field_access gen t (field_name field) let mk_field_access gen expr field pos = - match field_access gen expr.etype field with - | FClassField(c,p,dc,cf,false,at,_) -> - { eexpr = TField(expr, FInstance(dc,cf)); etype = apply_params c.cl_types p at; epos = pos } - | FClassField(c,p,dc,cf,true,at,_) -> - { eexpr = TField(expr, FStatic(dc,cf)); etype = at; epos = pos } - | FAnonField cf -> - { eexpr = TField(expr, FAnon cf); etype = cf.cf_type; epos = pos } - | FDynamicField t -> - { eexpr = TField(expr, FDynamic field); etype = t; epos = pos } - | FNotFound -> - { eexpr = TField(expr, FDynamic field); etype = t_dynamic; epos = pos } - | FEnumField _ -> assert false + match field_access gen expr.etype field with + | FClassField(c,p,dc,cf,false,at,_) -> + { eexpr = TField(expr, FInstance(dc,p,cf)); etype = apply_params c.cl_params p at; epos = pos } + | FClassField(c,p,dc,cf,true,at,_) -> + { eexpr = TField(expr, FStatic(dc,cf)); etype = at; epos = pos } + | FAnonField cf -> + { eexpr = TField(expr, FAnon cf); etype = cf.cf_type; epos = pos } + | FDynamicField t -> + { eexpr = TField(expr, FDynamic field); etype = t; epos = pos } + | FNotFound -> + { eexpr = TField(expr, FDynamic field); etype = t_dynamic; epos = pos } + | FEnumField _ -> assert false let mk_iterator_access gen t expr = - let pos = expr.epos in - let itf = mk_field_access gen expr "iterator" pos in - { eexpr = TCall(itf, []); epos = pos; etype = snd (get_fun itf.etype) } + let pos = expr.epos in + let itf = mk_field_access gen expr "iterator" pos in + { eexpr = TCall(itf, []); epos = pos; etype = snd (get_fun itf.etype) } (* ******************************************* *) (* Module dependency resolution *) (* ******************************************* *) type t_dependency = - | DAfter of float - | DBefore of float + | DAfter of float + | DBefore of float exception ImpossibleDependency of string @@ -1364,51 +1510,51 @@ let max_dep = 10000.0 let min_dep = - (10000.0) let solve_deps name (deps:t_dependency list) = - let vmin = min_dep -. 1.0 in - let vmax = max_dep +. 1.0 in - let rec loop dep vmin vmax = - match dep with - | [] -> - (if vmin >= vmax then raise (ImpossibleDependency name)); - (vmin +. vmax) /. 2.0 - | head :: tail -> - match head with - | DBefore f -> - loop tail (max vmin f) vmax - | DAfter f -> - loop tail vmin (min vmax f) - in - loop deps vmin vmax + let vmin = min_dep -. 1.0 in + let vmax = max_dep +. 1.0 in + let rec loop dep vmin vmax = + match dep with + | [] -> + (if vmin >= vmax then raise (ImpossibleDependency name)); + (vmin +. vmax) /. 2.0 + | head :: tail -> + match head with + | DBefore f -> + loop tail (max vmin f) vmax + | DAfter f -> + loop tail vmin (min vmax f) + in + loop deps vmin vmax (* type resolution *) exception TypeNotFound of path let get_type gen path = - try Hashtbl.find gen.gtypes path with | Not_found -> raise (TypeNotFound path) + try Hashtbl.find gen.gtypes path with | Not_found -> raise (TypeNotFound path) (* ******************************************* *) (* follow all module *) (* ******************************************* *) (* - this module will follow each and every type using the rules defined in - gen.gfollow. This is a minor helper module, so we don't end up - having to follow the same time multiple times in the many filter iterations - because of this, it will be one of the first modules to run. + this module will follow each and every type using the rules defined in + gen.gfollow. This is a minor helper module, so we don't end up + having to follow the same time multiple times in the many filter iterations + because of this, it will be one of the first modules to run. *) module FollowAll = struct - let follow gen e = - let follow_func = gen.gfollow#run_f in - Some (Type.map_expr_type (fun e->e) (follow_func) (fun tvar-> tvar.v_type <- (follow_func tvar.v_type); tvar) e) + let follow gen e = + let follow_func = gen.gfollow#run_f in + Some (Type.map_expr_type (fun e->e) (follow_func) (fun tvar-> tvar.v_type <- (follow_func tvar.v_type); tvar) e) - let priority = max_dep + let priority = max_dep - (* will add an expression filter as the first filter *) - let configure gen = - gen.gexpr_filters#add ~name:"follow_all" ~priority:(PCustom(priority)) (follow gen) + (* will add an expression filter as the first filter *) + let configure gen = + gen.gexpr_filters#add ~name:"follow_all" ~priority:(PCustom(priority)) (follow gen) end;; @@ -1417,49 +1563,70 @@ end;; (* ******************************************* *) (* - goes through all module types and sets the :hxgen meta on all which - then is_hxgen_func returns true. There is a default is_hxgen_func implementation also + goes through all module types and sets the :hxgen meta on all which + then is_hxgen_func returns true. There is a default is_hxgen_func implementation also *) module SetHXGen = struct - (* - basically, everything that is extern is assumed to not be hxgen, unless meta :hxgen is set, and - everything that is not extern is assumed to be hxgen, unless meta :nativegen is set - *) - let default_hxgen_func md = - match md with - | TClassDecl cl -> - let rec is_hxgen_class c = - if c.cl_extern then begin - if Meta.has Meta.HxGen c.cl_meta then true else Option.map_default (fun (c,_) -> is_hxgen_class c) false c.cl_super - end else begin - if Meta.has Meta.NativeGen c.cl_meta then Option.map_default (fun (c, _) -> is_hxgen_class c) false c.cl_super else true - end - in - - is_hxgen_class cl - | TEnumDecl e -> if e.e_extern then Meta.has Meta.HxGen e.e_meta else not (Meta.has Meta.NativeGen e.e_meta) - | TAbstractDecl a -> not (Meta.has Meta.NativeGen a.a_meta) - | TTypeDecl t -> (* TODO see when would we use this *) - false - - (* - by now the only option is to run it eagerly, because it must be one of the first filters to run, - since many others depend of it - *) - let run_filter gen is_hxgen_func = - let filter md = - if is_hxgen_func md then begin - match md with - | TClassDecl cl -> cl.cl_meta <- (Meta.HxGen, [], cl.cl_pos) :: cl.cl_meta - | TEnumDecl e -> e.e_meta <- (Meta.HxGen, [], e.e_pos) :: e.e_meta - | TTypeDecl t -> t.t_meta <- (Meta.HxGen, [], t.t_pos) :: t.t_meta - | TAbstractDecl a -> a.a_meta <- (Meta.HxGen, [], a.a_pos) :: a.a_meta - end - in - List.iter filter gen.gcon.types + (* + basically, everything that is extern is assumed to not be hxgen, unless meta :hxgen is set, and + everything that is not extern is assumed to be hxgen, unless meta :nativegen is set + *) + let rec default_hxgen_func md = + match md with + | TClassDecl { cl_kind = KAbstractImpl a } -> + default_hxgen_func (TAbstractDecl a) + | TClassDecl cl -> + let rec is_hxgen_class (c,_) = + if c.cl_extern then begin + if Meta.has Meta.HxGen c.cl_meta then true else Option.map_default (is_hxgen_class) false c.cl_super || List.exists is_hxgen_class c.cl_implements + end else begin + if Meta.has Meta.NativeChildren c.cl_meta || Meta.has Meta.NativeGen c.cl_meta then + Option.map_default (is_hxgen_class) false c.cl_super || List.exists is_hxgen_class c.cl_implements + else + let rec has_nativec (c,p) = + if is_hxgen_class (c,p) then + false + else + (Meta.has Meta.NativeChildren c.cl_meta && not (Option.map_default is_hxgen_class false c.cl_super || List.exists is_hxgen_class c.cl_implements)) + || Option.map_default has_nativec false c.cl_super + in + if Option.map_default has_nativec false c.cl_super && not (List.exists is_hxgen_class c.cl_implements) then + false + else + true + end + in + + is_hxgen_class (cl,[]) + | TEnumDecl e -> if e.e_extern then Meta.has Meta.HxGen e.e_meta else not (Meta.has Meta.NativeGen e.e_meta) + | TAbstractDecl a when Meta.has Meta.CoreType a.a_meta -> not (Meta.has Meta.NativeGen a.a_meta) + | TAbstractDecl a -> (match follow a.a_this with + | TInst _ | TEnum _ | TAbstract _ -> + default_hxgen_func (t_to_md (follow a.a_this)) + | _ -> + not (Meta.has Meta.NativeGen a.a_meta)) + | TTypeDecl t -> (* TODO see when would we use this *) + false + + (* + by now the only option is to run it eagerly, because it must be one of the first filters to run, + since many others depend of it + *) + let run_filter gen is_hxgen_func = + let filter md = + let meta = if is_hxgen_func md then Meta.HxGen else Meta.NativeGen in + begin + match md with + | TClassDecl cl -> cl.cl_meta <- (meta, [], cl.cl_pos) :: cl.cl_meta + | TEnumDecl e -> e.e_meta <- (meta, [], e.e_pos) :: e.e_meta + | TTypeDecl t -> t.t_meta <- (meta, [], t.t_pos) :: t.t_meta + | TAbstractDecl a -> a.a_meta <- (meta, [], a.a_pos) :: a.a_meta + end + in + List.iter filter gen.gtypes_list end;; @@ -1468,841 +1635,810 @@ end;; (* ******************************************* *) (* - this module works on languages that support function overloading and - enable function hiding via static functions. - it takes the constructor body out of the constructor and adds it to a special ctor - static function. The static function will receive the same parameters as the constructor, - plus the special "me" var, which will replace "this" + this module works on languages that support function overloading and + enable function hiding via static functions. + it takes the constructor body out of the constructor and adds it to a special ctor + static function. The static function will receive the same parameters as the constructor, + plus the special "me" var, which will replace "this" - Then it always adds two constructors to the function: one that receives a special class, - indicating that it should be constructed without any parameters, and one that receives its normal constructor. - Both will only include a super() call to the superclasses' emtpy constructor. + Then it always adds two constructors to the function: one that receives a special class, + indicating that it should be constructed without any parameters, and one that receives its normal constructor. + Both will only include a super() call to the superclasses' emtpy constructor. - This enables two things: - empty construction without the need of incompatibility with the platform's native construction method - the ability to call super() constructor in any place in the constructor + This enables two things: + empty construction without the need of incompatibility with the platform's native construction method + the ability to call super() constructor in any place in the constructor - This will insert itself in the default reflection-related module filter + This will insert itself in the default reflection-related module filter *) module OverloadingConstructor = struct - let priority = 0.0 - - let name = "overloading_constructor" - - let set_new_create_empty gen empty_ctor_expr = - let old = gen.gtools.rf_create_empty in - gen.gtools.rf_create_empty <- (fun cl params pos -> - if is_hxgen (TClassDecl cl) then - { eexpr = TNew(cl,params,[empty_ctor_expr]); etype = TInst(cl,params); epos = pos } - else - old cl params pos - ) - - let rec cur_ctor c tl = - match c.cl_constructor with - | Some ctor -> ctor, c, tl - | None -> match c.cl_super with - | None -> raise Not_found - | Some (sup,stl) -> - cur_ctor sup (List.map (apply_params c.cl_types tl) stl) - - let rec prev_ctor c tl = - match c.cl_super with - | None -> raise Not_found - | Some (sup,stl) -> let stl = List.map (apply_params c.cl_types tl) stl in - match sup.cl_constructor with - | None -> prev_ctor sup stl - | Some ctor -> ctor, sup, stl - - (* replaces super() call with last static constructor call *) - let replace_super_call gen name c tl with_params me p = - let rec loop_super c tl = match c.cl_super with - | None -> raise Not_found - | Some(sup,stl) -> - let stl = List.map (apply_params c.cl_types tl) stl in - try - let static_ctor_name = name ^ "_" ^ (String.concat "_" (fst sup.cl_path)) ^ "_" ^ (snd sup.cl_path) in - sup, stl, PMap.find static_ctor_name sup.cl_statics - with | Not_found -> - loop_super sup stl - in - let sup, stl, cf = loop_super c tl in - let with_params = { eexpr = TLocal me; etype = me.v_type; epos = p } :: with_params in - let cf = match cf.cf_overloads with - (* | [] -> cf *) - | _ -> try - (* choose best super function *) - List.iter (fun e -> replace_mono e.etype) with_params; - List.find (fun cf -> - replace_mono cf.cf_type; - let args, _ = get_fun (apply_params cf.cf_params stl cf.cf_type) in - try - List.for_all2 (fun (_,_,t) e -> try - unify e.etype t; true - with | Unify_error _ -> false) args with_params - with | Invalid_argument("List.for_all2") -> false - ) (cf :: cf.cf_overloads) - with | Not_found -> - gen.gcon.error "No suitable overload for the super call arguments was found" p; cf - in - { - eexpr = TCall({ - eexpr = TField( - mk_classtype_access sup p, - FStatic(sup,cf)); - etype = apply_params cf.cf_params stl cf.cf_type; - epos = p}, - with_params); - etype = gen.gcon.basic.tvoid; - epos = p; - } - - (* will create a static counterpart of 'ctor', and replace its contents to a call to the static version*) - let create_static_ctor gen ~empty_ctor_expr cl name ctor = - match Meta.has Meta.SkipCtor ctor.cf_meta with - | true -> () - | false when is_none ctor.cf_expr -> () - | false -> - let static_ctor_name = name ^ "_" ^ (String.concat "_" (fst cl.cl_path)) ^ "_" ^ (snd cl.cl_path) in - (* create the static constructor *) - let basic = gen.gcon.basic in - let ctor_types = List.map (fun (s,t) -> (s, TInst(map_param (get_cl_t t), []))) cl.cl_types in - let me = mk_temp gen "me" (TInst(cl, List.map snd ctor_types)) in - me.v_capture <- true; - - let fn_args, _ = get_fun ctor.cf_type in - let ctor_params = List.map snd ctor_types in - let fn_type = TFun((me.v_name,false, me.v_type) :: List.map (fun (n,o,t) -> (n,o,apply_params cl.cl_types ctor_params t)) fn_args, basic.tvoid) in - let cur_tf_args = match ctor.cf_expr with - | Some { eexpr = TFunction(tf) } -> tf.tf_args - | _ -> assert false - in - - let changed_tf_args = List.map (fun (v,_) -> (v,None)) cur_tf_args in - - let local_map = Hashtbl.create (List.length cur_tf_args) in - let static_tf_args = (me, None) :: List.map (fun (v,b) -> - let new_v = alloc_var v.v_name (apply_params cl.cl_types ctor_params v.v_type) in - Hashtbl.add local_map v.v_id new_v; - (new_v, b) - ) cur_tf_args in - - let static_ctor = mk_class_field static_ctor_name fn_type false ctor.cf_pos (Method MethNormal) ctor_types in - - (* change ctor contents to reference the 'me' var instead of 'this' *) - let actual_super_call = ref None in - let rec map_expr ~is_first e = match e.eexpr with - | TCall (({ eexpr = TConst TSuper } as tsuper), params) -> (try - let params = List.map (fun e -> map_expr ~is_first:false e) params in - actual_super_call := Some { e with eexpr = TCall(tsuper, [empty_ctor_expr]) }; - replace_super_call gen name cl ctor_params params me e.epos - with | Not_found -> - (* last static function was not found *) - actual_super_call := Some e; - if not is_first then - gen.gcon.error "Super call must be the first call when extending native types" e.epos; - { e with eexpr = TBlock([]) }) - | TFunction tf when is_first -> - do_map ~is_first:true e - | TConst TThis -> - mk_local me e.epos - | TBlock (fst :: bl) -> - let fst = map_expr ~is_first:is_first fst in - { e with eexpr = TBlock(fst :: List.map (fun e -> map_expr ~is_first:false e) bl); etype = apply_params cl.cl_types ctor_params e.etype } - | _ -> - do_map e - and do_map ?(is_first=false) e = - let do_t = apply_params cl.cl_types ctor_params in - let do_v v = try - Hashtbl.find local_map v.v_id - with | Not_found -> - v.v_type <- do_t v.v_type; v - in - Type.map_expr_type (map_expr ~is_first:is_first) do_t do_v e - in - - let expr = do_map ~is_first:true (get ctor.cf_expr) in - 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 - static_ctor.cf_expr <- Some expr; - (* add to the statics *) - (try - let stat = PMap.find static_ctor_name cl.cl_statics in - stat.cf_overloads <- static_ctor :: stat.cf_overloads - with | Not_found -> - cl.cl_ordered_statics <- static_ctor :: cl.cl_ordered_statics; - cl.cl_statics <- PMap.add static_ctor_name static_ctor cl.cl_statics); - (* change current super call *) - match ctor.cf_expr with - | Some({ eexpr = TFunction(tf) } as e) -> - let block_contents, p = match !actual_super_call with - | None -> [], ctor.cf_pos - | Some super -> [super], super.epos - in - let block_contents = block_contents @ [{ - eexpr = TCall( - { - eexpr = TField( - mk_classtype_access cl p, - FStatic(cl, static_ctor)); - etype = apply_params static_ctor.cf_params (List.map snd cl.cl_types) static_ctor.cf_type; - epos = p - }, - [{ eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_types); epos = p }] - @ List.map (fun (v,_) -> mk_local v p) cur_tf_args - ); - etype = basic.tvoid; - 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 - - (* makes constructors that only call super() for the 'ctor' argument *) - let clone_ctors gen ctor sup stl cl = - let basic = gen.gcon.basic in - let rec clone cf = - let ncf = mk_class_field "new" (apply_params sup.cl_types stl cf.cf_type) cf.cf_public cf.cf_pos cf.cf_kind cf.cf_params in - let args, ret = get_fun ncf.cf_type in - (* single expression: call to super() *) - let tf_args = List.map (fun (name,_,t) -> - (* the constructor will have no optional arguments, as presumably this will be handled by the underlying expr *) - alloc_var name t, None - ) args in - let super_call = - { - eexpr = TCall( - { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_types); epos = ctor.cf_pos }, - List.map (fun (v,_) -> mk_local v ctor.cf_pos) tf_args); - etype = basic.tvoid; - epos = ctor.cf_pos; - } in - ncf.cf_expr <- Some - { - eexpr = TFunction { - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = mk_block super_call; - }; - etype = ncf.cf_type; - epos = ctor.cf_pos; - }; - ncf - in - (* take off createEmpty *) - let all = List.filter (fun cf -> replace_mono cf.cf_type; not (Meta.has Meta.SkipCtor cf.cf_meta)) (ctor :: ctor.cf_overloads) in - let clones = List.map clone all in - match clones with - | [] -> - (* raise Not_found *) - assert false (* should never happen *) - | cf :: [] -> cf - | cf :: overl -> - cf.cf_meta <- (Meta.Overload,[],cf.cf_pos) :: cf.cf_meta; - cf.cf_overloads <- overl; cf - - let rec descends_from_native_or_skipctor cl = - not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta || match cl.cl_super with - | None -> false - | Some(c,_) -> descends_from_native_or_skipctor c - - let ensure_super_is_first gen cf = - let rec loop e = - match e.eexpr with - | TBlock (b :: block) -> - loop b - | TBlock [] - | TCall({ eexpr = TConst TSuper },_) -> () - | _ -> - gen.gcon.error "Types that derive from a native class must have its super() call as the first statement in the constructor" cf.cf_pos - in - match cf.cf_expr with - | None -> () - | Some e -> Type.iter loop e - - (* major restructring made at r6493 *) - let configure ~(empty_ctor_type : t) ~(empty_ctor_expr : texpr) ~supports_ctor_inheritance gen = - set_new_create_empty gen empty_ctor_expr; - - let basic = gen.gcon.basic in - let should_change cl = not cl.cl_interface && (not cl.cl_extern || is_hxgen (TClassDecl cl)) in - let static_ctor_name = gen.gmk_internal_name "hx" "ctor" in - let msize = List.length gen.gcon.types in - let processed, empty_ctors = Hashtbl.create msize, Hashtbl.create msize in - - - let rec get_last_empty cl = - try - Hashtbl.find empty_ctors cl.cl_path - with | Not_found -> - match cl.cl_super with - | None -> raise Not_found - | Some (sup,_) -> get_last_empty sup - in - - let rec change cl = - match Hashtbl.mem processed cl.cl_path with - | true -> () - | false -> - Hashtbl.add processed cl.cl_path true; - (* make sure we've processed the super types *) - (match cl.cl_super with - | Some (super,_) when should_change super && not (Hashtbl.mem processed super.cl_path) -> - change super - | _ -> ()); - - (* implement static hx_ctor and reimplement constructors *) - (try - let ctor = match cl.cl_constructor with - | Some ctor -> ctor - | None -> try - let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_types) in - (* we have a previous constructor. if we support inheritance, exit *) - if supports_ctor_inheritance then raise Exit; - (* we'll make constructors that will only call super() *) - let ctor = clone_ctors gen sctor sup stl cl in - cl.cl_constructor <- Some ctor; - ctor - with | Not_found -> (* create default constructor *) - let ctor = mk_class_field "new" (TFun([], basic.tvoid)) false cl.cl_pos (Method MethNormal) [] in - ctor.cf_expr <- Some - { - eexpr = TFunction { - tf_args = []; - tf_type = basic.tvoid; - tf_expr = { eexpr = TBlock[]; etype = basic.tvoid; epos = cl.cl_pos }; - }; - etype = ctor.cf_type; - epos = ctor.cf_pos; - }; - cl.cl_constructor <- Some ctor; - ctor - in - (* now that we made sure we have a constructor, exit if native gen *) - if not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta then raise Exit; - - (* if cl descends from a native class, we cannot use the static constructor strategy *) - if descends_from_native_or_skipctor cl && is_some cl.cl_super then - List.iter (fun cf -> ensure_super_is_first gen cf) (ctor :: ctor.cf_overloads) - else - (* now that we have a current ctor, create the static counterparts *) - List.iter (fun cf -> - create_static_ctor gen ~empty_ctor_expr:empty_ctor_expr cl static_ctor_name cf - ) (ctor :: ctor.cf_overloads) - with | Exit -> ()); - - (* implement empty ctor *) - (try - (* now that we made sure we have a constructor, exit if native gen *) - if not (is_hxgen (TClassDecl cl)) then raise Exit; - (* get first *) - let empty_type = TFun(["empty",false,empty_ctor_type],basic.tvoid) in - let super = match cl.cl_super with - | None -> (* implement empty *) - [] - | Some (sup,_) -> try - ignore (get_last_empty sup); - if supports_ctor_inheritance && is_none cl.cl_constructor then raise Exit; - [{ - eexpr = TCall( - { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_types); epos = cl.cl_pos }, - [ empty_ctor_expr ]); - etype = basic.tvoid; - epos = cl.cl_pos - }] - with | Not_found -> try - (* super type is native: find super constructor with least arguments *) - let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_types) in - let rec loop remaining (best,n) = - match remaining with - | [] -> best - | cf :: r -> - let args,_ = get_fun cf.cf_type in - if (List.length args) < n then - loop r (cf,List.length args) - else - loop r (best,n) - in - let args,_ = get_fun sctor.cf_type in - let best = loop sctor.cf_overloads (sctor, List.length args) in - let args,_ = get_fun best.cf_type in - [{ - eexpr = TCall( - { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_types); epos = cl.cl_pos }, - List.map (fun (n,o,t) -> null t cl.cl_pos) args); - etype = basic.tvoid; - epos = cl.cl_pos - }] - with | Not_found -> - (* extends native type, but no ctor found *) - [] - in - let ctor = mk_class_field "new" empty_type false cl.cl_pos (Method MethNormal) [] in - ctor.cf_expr <- Some { - eexpr = TFunction { - tf_type = basic.tvoid; - tf_args = [alloc_var "empty" empty_ctor_type, None]; - tf_expr = { eexpr = TBlock super; etype = basic.tvoid; epos = cl.cl_pos } - }; - etype = empty_type; - epos = cl.cl_pos; - }; - ctor.cf_meta <- [Meta.SkipCtor, [], ctor.cf_pos]; - Hashtbl.add empty_ctors cl.cl_path ctor; - match cl.cl_constructor with - | None -> cl.cl_constructor <- Some ctor - | Some c -> c.cf_overloads <- ctor :: c.cf_overloads - with | Exit -> ()); - - in - let module_filter md = match md with - | TClassDecl cl when should_change cl && not (Hashtbl.mem processed cl.cl_path) -> - change cl; - None - | _ -> None - in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) module_filter - - end;; - - (* ******************************************* *) - (* init function module *) - (* ******************************************* *) - - (* - This module will take proper care of the init function, by taking off all expressions from static vars and putting them - in order in the init function. - It will also initialize dynamic functions, both by putting them in the constructor and in the init function - - depends on: - (syntax) must run before ExprStatement module - (ok) must run before OverloadingCtor module so the constructor can be in the correct place - (syntax) must run before FunctionToClass module - *) - - module InitFunction = - struct - - let name = "init_funcs" - - let priority = solve_deps name [DBefore OverloadingConstructor.priority] - - let configure gen should_handle_dynamic_functions = - let handle_override_dynfun acc e this field = - let add_expr = ref None in - let v = mk_temp gen ("super_" ^ field) e.etype in - v.v_capture <- true; - - let rec loop e = - match e.eexpr with - | TField({ eexpr = TConst(TSuper) }, f) -> - let n = field_name f in - (if n <> field then assert false); - let local = mk_local v e.epos in - (match !add_expr with - | None -> - add_expr := Some { e with eexpr = TVars([v, Some this]) } - | Some _ -> ()); - local - | TConst TSuper -> assert false - | _ -> Type.map_expr loop e - in - let e = loop e in - - match !add_expr with - | None -> e :: acc - | Some add_expr -> add_expr :: e :: acc - in - - let handle_class cl = - let init = match cl.cl_init with - | None -> [] - | Some i -> [i] - in - let init = List.fold_left (fun acc cf -> - match cf.cf_kind, should_handle_dynamic_functions with - | (Var _, _) - | (Method (MethDynamic), true) when not (Type.is_extern_field cf) -> - (match cf.cf_expr with - | Some e -> - (match cf.cf_params with - | [] -> - let var = { eexpr = TField(mk_classtype_access cl cf.cf_pos, FStatic(cl,cf)); etype = cf.cf_type; epos = cf.cf_pos } in - let ret = ({ eexpr = TBinop(Ast.OpAssign, var, e); etype = cf.cf_type; epos = cf.cf_pos; }) in - cf.cf_expr <- None; - - ret :: acc - | _ -> - let params = List.map (fun _ -> t_dynamic) cf.cf_params in - let fn = apply_params cf.cf_params params in - let var = { eexpr = TField(mk_classtype_access cl cf.cf_pos, FStatic(cl,cf)); etype = fn cf.cf_type; epos = cf.cf_pos } in - let rec change_expr e = - Type.map_expr_type (change_expr) fn (fun v -> v.v_type <- fn v.v_type; v) e - in - - let ret = ({ eexpr = TBinop(Ast.OpAssign, var, change_expr e); etype = fn cf.cf_type; epos = cf.cf_pos; }) in - cf.cf_expr <- None; - ret :: acc - ) - | None -> acc) - | _ -> acc - ) init cl.cl_ordered_statics - in - let init = List.rev init in - (match init with - | [] -> cl.cl_init <- None - | _ -> cl.cl_init <- Some { eexpr = TBlock(init); epos = cl.cl_pos; etype = gen.gcon.basic.tvoid; }); - - (* FIXME: find a way to tell OverloadingCtors to execute this code even with empty constructors *) - if should_handle_dynamic_functions then begin - let funs = List.fold_left (fun acc cf -> - match cf.cf_kind with - | Var _ - | Method(MethDynamic) -> - (match cf.cf_expr, cf.cf_params with - | Some e, [] -> - let var = { eexpr = TField({ eexpr = TConst(TThis); epos = cf.cf_pos; etype = TInst(cl, List.map snd cl.cl_types); }, FInstance(cl, cf)); etype = cf.cf_type; epos = cf.cf_pos } in - let ret = ({ eexpr = TBinop(Ast.OpAssign, var, e); etype = cf.cf_type; epos = cf.cf_pos; }) in - cf.cf_expr <- None; - let is_override = List.memq cf cl.cl_overrides in - - if is_override then begin - cl.cl_ordered_fields <- List.filter (fun f -> f.cf_name <> cf.cf_name) cl.cl_ordered_fields; - cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; - handle_override_dynfun acc ret var cf.cf_name - end else ret :: acc - | Some e, _ -> - let params = List.map (fun _ -> t_dynamic) cf.cf_params in - let fn = apply_params cf.cf_params params in - let var = { eexpr = TField({ eexpr = TConst(TThis); epos = cf.cf_pos; etype = TInst(cl, List.map snd cl.cl_types); }, FInstance(cl, cf)); etype = cf.cf_type; epos = cf.cf_pos } in - let rec change_expr e = - Type.map_expr_type (change_expr) fn (fun v -> v.v_type <- fn v.v_type; v) e - in - - let ret = ({ eexpr = TBinop(Ast.OpAssign, var, change_expr e); etype = fn cf.cf_type; epos = cf.cf_pos; }) in - cf.cf_expr <- None; - let is_override = List.memq cf cl.cl_overrides in - - if is_override then begin - cl.cl_ordered_fields <- List.filter (fun f -> f.cf_name <> cf.cf_name) cl.cl_ordered_fields; - cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; - handle_override_dynfun acc ret var cf.cf_name - end else ret :: acc - | None, _ -> acc) - | _ -> acc - ) [] cl.cl_ordered_fields - in - (* see if there is any *) - (match funs with - | [] -> () - | _ -> - (* if there is, we need to find the constructor *) - let ctors = match cl.cl_constructor with - | Some ctor -> ctor - | None -> try - let sctor, sup, stl = OverloadingConstructor.prev_ctor cl (List.map snd cl.cl_types) in - let ctor = OverloadingConstructor.clone_ctors gen sctor sup stl cl in - cl.cl_constructor <- Some ctor; - ctor - with | Not_found -> - let basic = gen.gcon.basic in - let ctor = mk_class_field "new" (TFun([], basic.tvoid)) false cl.cl_pos (Method MethNormal) [] in - ctor.cf_expr <- Some - { - eexpr = TFunction { - tf_args = []; - tf_type = basic.tvoid; - tf_expr = { eexpr = TBlock[]; etype = basic.tvoid; epos = cl.cl_pos }; - }; - etype = ctor.cf_type; - epos = ctor.cf_pos; - }; - cl.cl_constructor <- Some ctor; - ctor - in - - let process ctor = - let func = match ctor.cf_expr with - | Some({eexpr = TFunction(tf)} as e) -> - let rec add_fn e = match e.eexpr with - | TBlock(hd :: tl) -> (match hd.eexpr with - | TCall({ eexpr = TConst TSuper }, _) -> - { e with eexpr = TBlock(hd :: (funs @ tl)) } - | TBlock(_) -> - { e with eexpr = TBlock( (add_fn hd) :: tl ) } - | _ -> - { e with eexpr = TBlock( funs @ (hd :: tl) ) }) - | _ -> Codegen.concat { e with eexpr = TBlock(funs) } e - in - let tf_expr = add_fn (mk_block tf.tf_expr) in - { e with eexpr = TFunction({ tf with tf_expr = tf_expr }) } - | _ -> assert false - in - ctor.cf_expr <- Some(func) - in - List.iter process (ctors :: ctors.cf_overloads) - ) - end - - in - - let mod_filter = function - | TClassDecl cl -> (if not cl.cl_extern then handle_class cl); None - | _ -> None in - - gen.gmodule_filters#add ~name:"init_funcs" ~priority:(PCustom priority) mod_filter - - end;; - - (* ******************************************* *) - (* Dynamic Binop/Unop handler *) - (* ******************************************* *) - - (* - On some languages there is limited support for operations on - dynamic variables, so those operations must be changed. - - There are 5 types of binary operators: - 1 - can take any variable and returns a bool (== and !=) - 2 - can take either a string, or a number and returns either a bool or the underlying type ( >, < for bool and + for returning its type) - 3 - take numbers and return a number ( *, /, ...) - 4 - take ints and return an int (bit manipulation) - 5 - take a bool and returns a bool ( &&, || ...) - - On the default implementation, type 1 and the plus function will be handled with a function call; - Type 2 will be handled with the parameter "compare_handler", which will do something like Reflect.compare(x1, x2); - Types 3, 4 and 5 will perform a cast to double, int and bool, which will then be handled normally by the platform - - Unary operators are the most difficult to handle correctly. - With unary operators, there are 2 types: - - 1 - can take a number, changes and returns the result (++, --, ~) - 2 - can take a number (-) or bool (!), and returns the result - - The first case is much trickier, because it doesn't seem a good idea to change any variable to double just because it is dynamic, - but this is how we will handle right now. - something like that: - - var x:Dynamic = 10; - x++; - - will be: - object x = 10; - x = ((IConvertible)x).ToDouble(null) + 1; - - depends on: - (syntax) must run before expression/statment normalization because it may generate complex expressions - must run before OverloadingCtor due to later priority conflicts. Since ExpressionUnwrap is only - defined afterwards, we will set this value with absolute values - *) - - module DynamicOperators = - struct - - let name = "dyn_ops" - - let priority = 0.0 - - let priority_as_synf = 100.0 (*solve_deps name [DBefore ExpressionUnwrap.priority]*) - - let abstract_implementation gen ?(handle_strings = true) (should_change:texpr->bool) (equals_handler:texpr->texpr->texpr) (dyn_plus_handler:texpr->texpr->texpr->texpr) (compare_handler:texpr->texpr->texpr) = - - - let get_etype_one e = - if like_int e.etype then - (gen.gcon.basic.tint, { eexpr = TConst(TInt(Int32.one)); etype = gen.gcon.basic.tint; epos = e.epos }) - else - (gen.gcon.basic.tfloat, { eexpr = TConst(TFloat("1.0")); etype = gen.gcon.basic.tfloat; epos = e.epos }) - in - - let basic = gen.gcon.basic in - - let rec run e = - match e.eexpr with - | TBinop (OpAssignOp op, e1, e2) when should_change e -> (* e1 will never contain another TBinop *) - (match e1.eexpr with - | TLocal _ -> - mk_paren { e with eexpr = TBinop(OpAssign, e1, run { e with eexpr = TBinop(op, e1, e2) }) } - | TField _ | TArray _ -> - let eleft, rest = match e1.eexpr with - | TField(ef, f) -> - let v = mk_temp gen "dynop" ef.etype in - { e1 with eexpr = TField(mk_local v ef.epos, f) }, [ { eexpr = TVars([v,Some (run ef)]); etype = basic.tvoid; epos = ef.epos } ] - | TArray(e1a, e2a) -> - let v = mk_temp gen "dynop" e1a.etype in - let v2 = mk_temp gen "dynopi" e2a.etype in - { e1 with eexpr = TArray(mk_local v e1a.epos, mk_local v2 e2a.epos) }, [ { eexpr = TVars([v,Some (run e1a); v2, Some (run e2a)]); etype = basic.tvoid; epos = e1.epos } ] - | _ -> assert false - in - { e with - eexpr = TBlock (rest @ [ { e with eexpr = TBinop(OpAssign, eleft, run { e with eexpr = TBinop(op, eleft, e2) }) } ]); - } - | _ -> - assert false - ) - - | TBinop (OpAssign, e1, e2) - | TBinop (OpInterval, e1, e2) -> Type.map_expr run e - | TBinop (op, e1, e2) when should_change e-> - (match op with - | OpEq -> (* type 1 *) - equals_handler (run e1) (run e2) - | OpNotEq -> (* != -> !equals() *) - mk_paren { eexpr = TUnop(Ast.Not, Prefix, (equals_handler (run e1) (run e2))); etype = gen.gcon.basic.tbool; epos = e.epos } - | OpAdd -> - if handle_strings && (is_string e.etype or is_string e1.etype or is_string e2.etype) then - { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tstring (run e1), mk_cast gen.gcon.basic.tstring (run e2)) } - else - dyn_plus_handler e (run e1) (run e2) - | OpGt | OpGte | OpLt | OpLte -> (* type 2 *) - { eexpr = TBinop(op, compare_handler (run e1) (run e2), { eexpr = TConst(TInt(Int32.zero)); etype = gen.gcon.basic.tint; epos = e.epos} ); etype = gen.gcon.basic.tbool; epos = e.epos } - | OpMult | OpDiv | OpSub -> (* always cast everything to double *) - let etype, _ = get_etype_one e in - { e with eexpr = TBinop(op, mk_cast etype (run e1), mk_cast etype (run e2)) } - | OpBoolAnd | OpBoolOr -> - { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tbool (run e1), mk_cast gen.gcon.basic.tbool (run e2)) } - | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod -> - { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tint (run e1), mk_cast gen.gcon.basic.tint (run e2)) } - | OpAssign | OpAssignOp _ | OpInterval | OpArrow -> assert false) - | TUnop (Increment as op, flag, e1) - | TUnop (Decrement as op, flag, e1) when should_change e -> - (* - some naming definitions: - * ret => the returning variable - * _g => the get body - * getvar => the get variable expr - - This will work like this: - - if e1 is a TField, set _g = get body, getvar = (get body).varname - - if Prefix, return getvar = getvar + 1.0 - - if Postfix, set ret = getvar; getvar = getvar + 1.0; ret; - *) - let etype, one = get_etype_one e in - let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false) in - - let tvars, getvar = - match e1.eexpr with - | TField(fexpr, field) -> - let tmp = mk_temp gen "getvar" fexpr.etype in - let tvars = [tmp, Some(run fexpr)] in - (tvars, { eexpr = TField( { fexpr with eexpr = TLocal(tmp) }, field); etype = etype; epos = e1.epos }) - | _ -> - ([], e1) - in - - (match flag with - | Prefix -> - let tvars = match tvars with - | [] -> [] - | _ -> [{ eexpr = TVars(tvars); etype = gen.gcon.basic.tvoid; epos = e.epos }] - in - let block = tvars @ - [ - mk_cast etype { e with eexpr = TBinop(OpAssign, getvar,{ eexpr = TBinop(op, mk_cast etype getvar, one); etype = etype; epos = e.epos }); etype = getvar.etype; } - ] in - { eexpr = TBlock(block); etype = etype; epos = e.epos } - | Postfix -> - let ret = mk_temp gen "ret" etype in - let tvars = { eexpr = TVars(tvars @ [ret, Some (mk_cast etype getvar)]); etype = gen.gcon.basic.tvoid; epos = e.epos } in - let retlocal = { eexpr = TLocal(ret); etype = etype; epos = e.epos } in - let block = tvars :: - [ - { e with eexpr = TBinop(OpAssign, getvar, { eexpr = TBinop(op, retlocal, one); etype = getvar.etype; epos = e.epos }) }; - retlocal - ] in - { eexpr = TBlock(block); etype = etype; epos = e.epos } - ) - | TUnop (op, flag, e1) when should_change e -> - let etype = match op with | Not -> gen.gcon.basic.tbool | _ -> gen.gcon.basic.tint in - mk_paren { eexpr = TUnop(op, flag, mk_cast etype (run e1)); etype = etype; epos = e.epos } - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dyn_ops" ~priority:(PCustom priority) map - - let configure_as_synf gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dyn_ops" ~priority:(PCustom priority_as_synf) map + let priority = 0.0 + + let name = "overloading_constructor" + + let set_new_create_empty gen empty_ctor_expr = + let old = gen.gtools.rf_create_empty in + gen.gtools.rf_create_empty <- (fun cl params pos -> + if is_hxgen (TClassDecl cl) then + { eexpr = TNew(cl,params,[empty_ctor_expr]); etype = TInst(cl,params); epos = pos } + else + old cl params pos + ) + + let rec cur_ctor c tl = + match c.cl_constructor with + | Some ctor -> ctor, c, tl + | None -> match c.cl_super with + | None -> raise Not_found + | Some (sup,stl) -> + cur_ctor sup (List.map (apply_params c.cl_params tl) stl) + + let rec prev_ctor c tl = + match c.cl_super with + | None -> raise Not_found + | Some (sup,stl) -> + let stl = List.map (apply_params c.cl_params tl) stl in + match sup.cl_constructor with + | None -> prev_ctor sup stl + | Some ctor -> ctor, sup, stl + + (* replaces super() call with last static constructor call *) + let replace_super_call gen name c tl with_params me p = + let rec loop_super c tl = match c.cl_super with + | None -> raise Not_found + | Some(sup,stl) -> + let stl = List.map (apply_params c.cl_params tl) stl in + try + let static_ctor_name = name ^ "_" ^ (String.concat "_" (fst sup.cl_path)) ^ "_" ^ (snd sup.cl_path) in + sup, stl, PMap.find static_ctor_name sup.cl_statics + with | Not_found -> + loop_super sup stl + in + let sup, stl, cf = loop_super c tl in + let with_params = { eexpr = TLocal me; etype = me.v_type; epos = p } :: with_params in + let cf = match cf.cf_overloads with + (* | [] -> cf *) + | _ -> try + (* choose best super function *) + List.iter (fun e -> replace_mono e.etype) with_params; + List.find (fun cf -> + replace_mono cf.cf_type; + let args, _ = get_fun (apply_params cf.cf_params stl cf.cf_type) in + try + List.for_all2 (fun (_,_,t) e -> try + let e_etype = run_follow gen e.etype in + let t = run_follow gen t in + unify e_etype t; true + with | Unify_error _ -> false) args with_params + with | Invalid_argument("List.for_all2") -> false + ) (cf :: cf.cf_overloads) + with | Not_found -> + gen.gcon.error "No suitable overload for the super call arguments was found" p; cf + in + { + eexpr = TCall({ + eexpr = TField( + mk_classtype_access sup p, + FStatic(sup,cf)); + etype = apply_params cf.cf_params stl cf.cf_type; + epos = p}, + with_params); + etype = gen.gcon.basic.tvoid; + epos = p; + } + + (* will create a static counterpart of 'ctor', and replace its contents to a call to the static version*) + let create_static_ctor gen ~empty_ctor_expr cl name ctor = + match Meta.has Meta.SkipCtor ctor.cf_meta with + | true -> () + | false when is_none ctor.cf_expr -> () + | false -> + let static_ctor_name = name ^ "_" ^ (String.concat "_" (fst cl.cl_path)) ^ "_" ^ (snd cl.cl_path) in + (* create the static constructor *) + let basic = gen.gcon.basic in + let ctor_types = List.map (fun (s,t) -> (s, TInst(map_param (get_cl_t t), []))) cl.cl_params in + let me = mk_temp gen "me" (TInst(cl, List.map snd ctor_types)) in + me.v_capture <- true; + + let fn_args, _ = get_fun ctor.cf_type in + let ctor_params = List.map snd ctor_types in + 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, basic.tvoid) in + let cur_tf_args = match ctor.cf_expr with + | Some { eexpr = TFunction(tf) } -> tf.tf_args + | _ -> assert false + in + + let changed_tf_args = List.map (fun (v,_) -> (v,None)) cur_tf_args in + + let local_map = Hashtbl.create (List.length cur_tf_args) in + let static_tf_args = (me, None) :: List.map (fun (v,b) -> + let new_v = alloc_var v.v_name (apply_params cl.cl_params ctor_params v.v_type) in + new_v.v_capture <- v.v_capture; + Hashtbl.add local_map v.v_id new_v; + (new_v, b) + ) cur_tf_args in + + let static_ctor = mk_class_field static_ctor_name fn_type false ctor.cf_pos (Method MethNormal) ctor_types in + + (* change ctor contents to reference the 'me' var instead of 'this' *) + let actual_super_call = ref None in + let rec map_expr ~is_first e = match e.eexpr with + | TCall (({ eexpr = TConst TSuper } as tsuper), params) -> (try + let params = List.map (fun e -> map_expr ~is_first:false e) params in + actual_super_call := Some { e with eexpr = TCall(tsuper, [empty_ctor_expr]) }; + replace_super_call gen name cl ctor_params params me e.epos + with | Not_found -> + (* last static function was not found *) + actual_super_call := Some e; + if not is_first then + gen.gcon.error "Super call must be the first call when extending native types" e.epos; + { e with eexpr = TBlock([]) }) + | TFunction tf when is_first -> + do_map ~is_first:true e + | TConst TThis -> + mk_local me e.epos + | TBlock (fst :: bl) -> + let fst = map_expr ~is_first:is_first fst in + { e with eexpr = TBlock(fst :: List.map (fun e -> map_expr ~is_first:false e) bl); etype = apply_params cl.cl_params ctor_params e.etype } + | _ -> + do_map e + and do_map ?(is_first=false) e = + let do_t = apply_params cl.cl_params ctor_params in + let do_v v = try + Hashtbl.find local_map v.v_id + with | Not_found -> + v.v_type <- do_t v.v_type; v + in + Type.map_expr_type (map_expr ~is_first:is_first) do_t do_v e + in + + let expr = do_map ~is_first:true (get ctor.cf_expr) in + 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 + static_ctor.cf_expr <- Some expr; + (* add to the statics *) + (try + let stat = PMap.find static_ctor_name cl.cl_statics in + stat.cf_overloads <- static_ctor :: stat.cf_overloads + with | Not_found -> + cl.cl_ordered_statics <- static_ctor :: cl.cl_ordered_statics; + cl.cl_statics <- PMap.add static_ctor_name static_ctor cl.cl_statics); + (* change current super call *) + match ctor.cf_expr with + | Some({ eexpr = TFunction(tf) } as e) -> + let block_contents, p = match !actual_super_call with + | None -> [], ctor.cf_pos + | Some super -> [super], super.epos + in + let block_contents = block_contents @ [{ + eexpr = TCall( + { + eexpr = TField( + mk_classtype_access cl p, + FStatic(cl, static_ctor)); + etype = apply_params static_ctor.cf_params (List.map snd cl.cl_params) static_ctor.cf_type; + epos = p + }, + [{ eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = p }] + @ List.map (fun (v,_) -> mk_local v p) cur_tf_args + ); + etype = basic.tvoid; + 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 + + (* makes constructors that only call super() for the 'ctor' argument *) + let clone_ctors gen ctor sup stl cl = + let basic = gen.gcon.basic in + let rec clone cf = + let ncf = mk_class_field "new" (apply_params sup.cl_params stl cf.cf_type) cf.cf_public cf.cf_pos cf.cf_kind cf.cf_params in + let args, ret = get_fun ncf.cf_type in + (* single expression: call to super() *) + let tf_args = List.map (fun (name,_,t) -> + (* the constructor will have no optional arguments, as presumably this will be handled by the underlying expr *) + alloc_var name t, None + ) args in + let super_call = + { + eexpr = TCall( + { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_params); epos = ctor.cf_pos }, + List.map (fun (v,_) -> mk_local v ctor.cf_pos) tf_args); + etype = basic.tvoid; + epos = ctor.cf_pos; + } in + ncf.cf_expr <- Some + { + eexpr = TFunction { + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = mk_block super_call; + }; + etype = ncf.cf_type; + epos = ctor.cf_pos; + }; + ncf + in + (* take off createEmpty *) + let all = List.filter (fun cf -> replace_mono cf.cf_type; not (Meta.has Meta.SkipCtor cf.cf_meta)) (ctor :: ctor.cf_overloads) in + let clones = List.map clone all in + match clones with + | [] -> + (* raise Not_found *) + assert false (* should never happen *) + | cf :: [] -> cf + | cf :: overl -> + cf.cf_meta <- (Meta.Overload,[],cf.cf_pos) :: cf.cf_meta; + cf.cf_overloads <- overl; cf + + let rec descends_from_native_or_skipctor cl = + not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta || match cl.cl_super with + | None -> false + | Some(c,_) -> descends_from_native_or_skipctor c + + let ensure_super_is_first gen cf = + let rec loop e = + match e.eexpr with + | TBlock (b :: block) -> + loop b + | TBlock [] + | TCall({ eexpr = TConst TSuper },_) -> () + | _ -> + gen.gcon.error "Types that derive from a native class must have its super() call as the first statement in the constructor" cf.cf_pos + in + match cf.cf_expr with + | None -> () + | Some e -> Type.iter loop e + + (* major restructring made at r6493 *) + let configure ~(empty_ctor_type : t) ~(empty_ctor_expr : texpr) ~supports_ctor_inheritance gen = + set_new_create_empty gen empty_ctor_expr; + + let basic = gen.gcon.basic in + let should_change cl = not cl.cl_interface && (not cl.cl_extern || is_hxgen (TClassDecl cl)) && (match cl.cl_kind with KAbstractImpl _ -> false | _ -> true) in + let static_ctor_name = gen.gmk_internal_name "hx" "ctor" in + let msize = List.length gen.gtypes_list in + let processed, empty_ctors = Hashtbl.create msize, Hashtbl.create msize in + + + let rec get_last_empty cl = + try + Hashtbl.find empty_ctors cl.cl_path + with | Not_found -> + match cl.cl_super with + | None -> raise Not_found + | Some (sup,_) -> get_last_empty sup + in + + let rec change cl = + match Hashtbl.mem processed cl.cl_path with + | true -> () + | false -> + Hashtbl.add processed cl.cl_path true; + (* make sure we've processed the super types *) + (match cl.cl_super with + | Some (super,_) when should_change super && not (Hashtbl.mem processed super.cl_path) -> + change super + | _ -> ()); + + (* implement static hx_ctor and reimplement constructors *) + (try + let ctor = match cl.cl_constructor with + | Some ctor -> ctor + | None -> try + let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_params) in + (* we have a previous constructor. if we support inheritance, exit *) + if supports_ctor_inheritance then raise Exit; + (* we'll make constructors that will only call super() *) + let ctor = clone_ctors gen sctor sup stl cl in + cl.cl_constructor <- Some ctor; + ctor + with | Not_found -> (* create default constructor *) + let ctor = mk_class_field "new" (TFun([], basic.tvoid)) false cl.cl_pos (Method MethNormal) [] in + ctor.cf_expr <- Some + { + eexpr = TFunction { + tf_args = []; + tf_type = basic.tvoid; + tf_expr = { eexpr = TBlock[]; etype = basic.tvoid; epos = cl.cl_pos }; + }; + etype = ctor.cf_type; + epos = ctor.cf_pos; + }; + cl.cl_constructor <- Some ctor; + ctor + in + (* now that we made sure we have a constructor, exit if native gen *) + if not (is_hxgen (TClassDecl cl)) || Meta.has Meta.SkipCtor cl.cl_meta then begin + if descends_from_native_or_skipctor cl && is_some cl.cl_super then + List.iter (fun cf -> ensure_super_is_first gen cf) (ctor :: ctor.cf_overloads); + raise Exit + end; + + (* if cl descends from a native class, we cannot use the static constructor strategy *) + if descends_from_native_or_skipctor cl && is_some cl.cl_super then + List.iter (fun cf -> ensure_super_is_first gen cf) (ctor :: ctor.cf_overloads) + else + (* now that we have a current ctor, create the static counterparts *) + List.iter (fun cf -> + create_static_ctor gen ~empty_ctor_expr:empty_ctor_expr cl static_ctor_name cf + ) (ctor :: ctor.cf_overloads) + with | Exit ->()); + + (* implement empty ctor *) + (try + (* now that we made sure we have a constructor, exit if native gen *) + if not (is_hxgen (TClassDecl cl)) then raise Exit; + (* get first *) + let empty_type = TFun(["empty",false,empty_ctor_type],basic.tvoid) in + let super = match cl.cl_super with + | None -> (* implement empty *) + [] + | Some (sup,_) -> try + ignore (get_last_empty sup); + if supports_ctor_inheritance && is_none cl.cl_constructor then raise Exit; + [{ + eexpr = TCall( + { eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_params); epos = cl.cl_pos }, + [ empty_ctor_expr ]); + etype = basic.tvoid; + epos = cl.cl_pos + }] + with | Not_found -> try + (* super type is native: find super constructor with least arguments *) + let sctor, sup, stl = prev_ctor cl (List.map snd cl.cl_params) in + let rec loop remaining (best,n) = + match remaining with + | [] -> best + | cf :: r -> + let args,_ = get_fun cf.cf_type in + if (List.length args) < n then + loop r (cf,List.length args) + else + loop r (best,n) + in + let args,_ = get_fun sctor.cf_type in + let best = loop sctor.cf_overloads (sctor, List.length args) in + let args,_ = get_fun (apply_params sup.cl_params stl best.cf_type) in + [{ + eexpr = TCall( + { eexpr = TConst TSuper; etype = TInst(sup, stl); epos = cl.cl_pos }, + List.map (fun (n,o,t) -> null t cl.cl_pos) args); + etype = basic.tvoid; + epos = cl.cl_pos + }] + with | Not_found -> + (* extends native type, but no ctor found *) + [] + in + let ctor = mk_class_field "new" empty_type false cl.cl_pos (Method MethNormal) [] in + ctor.cf_expr <- Some { + eexpr = TFunction { + tf_type = basic.tvoid; + tf_args = [alloc_var "empty" empty_ctor_type, None]; + tf_expr = { eexpr = TBlock super; etype = basic.tvoid; epos = cl.cl_pos } + }; + etype = empty_type; + epos = cl.cl_pos; + }; + ctor.cf_meta <- [Meta.SkipCtor, [], ctor.cf_pos]; + Hashtbl.add empty_ctors cl.cl_path ctor; + match cl.cl_constructor with + | None -> cl.cl_constructor <- Some ctor + | Some c -> c.cf_overloads <- ctor :: c.cf_overloads + with | Exit -> ()); + + in + let module_filter md = match md with + | TClassDecl cl when should_change cl && not (Hashtbl.mem processed cl.cl_path) -> + change cl; + None + | _ -> None + in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) module_filter + + end;; + + (* ******************************************* *) + (* init function module *) + (* ******************************************* *) -end;; + (* + This module will take proper care of the init function, by taking off all expressions from static vars and putting them + in order in the init function. + It will also initialize dynamic functions, both by putting them in the constructor and in the init function + + depends on: + (syntax) must run before ExprStatement module + (ok) must run before OverloadingCtor module so the constructor can be in the correct place + (syntax) must run before FunctionToClass module + *) -(* ******************************************* *) -(* Closure Detection *) -(* ******************************************* *) + module InitFunction = + struct + + let name = "init_funcs" + + let priority = solve_deps name [DBefore OverloadingConstructor.priority] + + let ensure_simple_expr gen e = + let rec iter e = match e.eexpr with + | TConst _ | TLocal _ | TArray _ | TBinop _ + | TField _ | TTypeExpr _ | TParenthesis _ | TCast _ + | TCall _ | TNew _ | TUnop _ -> + Type.iter iter e + | _ -> + print_endline (debug_expr e); + gen.gcon.error "Expression is too complex for a readonly variable initialization" e.epos + in + iter e + + let configure gen should_handle_dynamic_functions readonly_support = + let handle_override_dynfun acc e this field = + let add_expr = ref None in + let v = mk_temp gen ("super_" ^ field) e.etype in + v.v_capture <- true; + + let rec loop e = + match e.eexpr with + | TField({ eexpr = TConst(TSuper) }, f) -> + let n = field_name f in + (if n <> field then assert false); + let local = mk_local v e.epos in + (match !add_expr with + | None -> + add_expr := Some { e with eexpr = TVar(v, Some this) } + | Some _ -> ()); + local + | TConst TSuper -> assert false + | _ -> Type.map_expr loop e + in + let e = loop e in + + match !add_expr with + | None -> e :: acc + | Some add_expr -> add_expr :: e :: acc + in + + let handle_class cl = + let init = match cl.cl_init with + | None -> [] + | Some i -> [i] + in + let init = List.fold_left (fun acc cf -> + match cf.cf_kind, should_handle_dynamic_functions with + | (Var v, _) when Meta.has Meta.ReadOnly cf.cf_meta && readonly_support -> + if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then gen.gcon.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos; + (match cf.cf_expr with + | None -> gen.gcon.warning "Uninitialized readonly variable" cf.cf_pos; acc + | Some e -> ensure_simple_expr gen e; acc) + | (Var _, _) + | (Method (MethDynamic), true) when not (Type.is_extern_field cf) -> + (match cf.cf_expr with + | Some e -> + (match cf.cf_params with + | [] -> + let var = { eexpr = TField(mk_classtype_access cl cf.cf_pos, FStatic(cl,cf)); etype = cf.cf_type; epos = cf.cf_pos } in + let ret = ({ eexpr = TBinop(Ast.OpAssign, var, e); etype = cf.cf_type; epos = cf.cf_pos; }) in + cf.cf_expr <- None; + + ret :: acc + | _ -> + let params = List.map (fun _ -> t_dynamic) cf.cf_params in + let fn = apply_params cf.cf_params params in + let var = { eexpr = TField(mk_classtype_access cl cf.cf_pos, FStatic(cl,cf)); etype = fn cf.cf_type; epos = cf.cf_pos } in + let rec change_expr e = + Type.map_expr_type (change_expr) fn (fun v -> v.v_type <- fn v.v_type; v) e + in + + let ret = ({ eexpr = TBinop(Ast.OpAssign, var, change_expr e); etype = fn cf.cf_type; epos = cf.cf_pos; }) in + cf.cf_expr <- None; + ret :: acc + ) + | None -> acc) + | _ -> acc + ) init cl.cl_ordered_statics + in + let init = List.rev init in + (match init with + | [] -> cl.cl_init <- None + | _ -> cl.cl_init <- Some { eexpr = TBlock(init); epos = cl.cl_pos; etype = gen.gcon.basic.tvoid; }); + + (* FIXME: find a way to tell OverloadingCtors to execute this code even with empty constructors *) + if should_handle_dynamic_functions then begin + let vars, funs = List.fold_left (fun (acc_vars,acc_funs) cf -> + match cf.cf_kind with + | Var v when Meta.has Meta.ReadOnly cf.cf_meta && readonly_support -> + if v.v_write <> AccNever && not (Meta.has Meta.CoreApi cl.cl_meta) then gen.gcon.warning "@:readOnly variable declared without `never` setter modifier" cf.cf_pos; + (match cf.cf_expr with + | None -> (acc_vars,acc_funs) + | Some e -> ensure_simple_expr gen e; (acc_vars,acc_funs)) + | Var _ + | Method(MethDynamic) -> + let is_var = match cf.cf_kind with | Var _ -> true | _ -> false in + (match cf.cf_expr, cf.cf_params with + | Some e, [] -> + let var = { eexpr = TField({ eexpr = TConst(TThis); epos = cf.cf_pos; etype = TInst(cl, List.map snd cl.cl_params); }, FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf.cf_type; epos = cf.cf_pos } in + let ret = ({ eexpr = TBinop(Ast.OpAssign, var, e); etype = cf.cf_type; epos = cf.cf_pos; }) in + cf.cf_expr <- None; + let is_override = List.memq cf cl.cl_overrides in + + if is_override then begin + cl.cl_ordered_fields <- List.filter (fun f -> f.cf_name <> cf.cf_name) cl.cl_ordered_fields; + cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; + acc_vars, handle_override_dynfun acc_funs ret var cf.cf_name + end else if is_var then + ret :: acc_vars, acc_funs + else + acc_vars, ret :: acc_funs + | Some e, _ -> + let params = List.map (fun _ -> t_dynamic) cf.cf_params in + let fn = apply_params cf.cf_params params in + let var = { eexpr = TField({ eexpr = TConst(TThis); epos = cf.cf_pos; etype = TInst(cl, List.map snd cl.cl_params); }, FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf.cf_type; epos = cf.cf_pos } in + let rec change_expr e = + Type.map_expr_type (change_expr) fn (fun v -> v.v_type <- fn v.v_type; v) e + in + + let ret = ({ eexpr = TBinop(Ast.OpAssign, var, change_expr e); etype = fn cf.cf_type; epos = cf.cf_pos; }) in + cf.cf_expr <- None; + let is_override = List.memq cf cl.cl_overrides in + + if is_override then begin + cl.cl_ordered_fields <- List.filter (fun f -> f.cf_name <> cf.cf_name) cl.cl_ordered_fields; + cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; + acc_vars, handle_override_dynfun acc_funs ret var cf.cf_name + end else if is_var then + ret :: acc_vars, acc_funs + else + acc_vars, ret :: acc_funs + | None, _ -> acc_vars,acc_funs) + | _ -> acc_vars,acc_funs + ) ([],[]) cl.cl_ordered_fields + in + (* let vars = List.rev vars in *) + (* let funs = List.rev funs in *) + (* see if there is any *) + (match vars, funs with + | [], [] -> () + | _ -> + (* if there is, we need to find the constructor *) + let ctors = match cl.cl_constructor with + | Some ctor -> ctor + | None -> try + let sctor, sup, stl = OverloadingConstructor.prev_ctor cl (List.map snd cl.cl_params) in + let ctor = OverloadingConstructor.clone_ctors gen sctor sup stl cl in + cl.cl_constructor <- Some ctor; + ctor + with | Not_found -> + let basic = gen.gcon.basic in + let ctor = mk_class_field "new" (TFun([], basic.tvoid)) false cl.cl_pos (Method MethNormal) [] in + ctor.cf_expr <- Some + { + eexpr = TFunction { + tf_args = []; + tf_type = basic.tvoid; + tf_expr = { eexpr = TBlock[]; etype = basic.tvoid; epos = cl.cl_pos }; + }; + etype = ctor.cf_type; + epos = ctor.cf_pos; + }; + cl.cl_constructor <- Some ctor; + ctor + in + + let process ctor = + let func = match ctor.cf_expr with + | Some({eexpr = TFunction(tf)} as e) -> + let rec add_fn e = match e.eexpr with + | TBlock(hd :: tl) -> (match hd.eexpr with + | TCall({ eexpr = TConst TSuper }, _) -> + if not (OverloadingConstructor.descends_from_native_or_skipctor cl) then + { e with eexpr = TBlock(vars @ (hd :: (funs @ tl))) } + else + { e with eexpr = TBlock(hd :: (vars @ funs @ tl)) } + | TBlock(_) -> + { e with eexpr = TBlock( (add_fn hd) :: tl ) } + | _ -> + { e with eexpr = TBlock( vars @ funs @ (hd :: tl) ) }) + | _ -> Type.concat { e with eexpr = TBlock(vars @ funs) } e + in + let tf_expr = add_fn (mk_block tf.tf_expr) in + { e with eexpr = TFunction({ tf with tf_expr = tf_expr }) } + | _ -> assert false + in + ctor.cf_expr <- Some(func) + in + List.iter process (ctors :: ctors.cf_overloads) + ) + end + + in + + let mod_filter = function + | TClassDecl cl -> (if not cl.cl_extern then handle_class cl); None + | _ -> None in + + gen.gmodule_filters#add ~name:"init_funcs" ~priority:(PCustom priority) mod_filter + + end;; + + (* ******************************************* *) + (* Dynamic Binop/Unop handler *) + (* ******************************************* *) -(* + (* + On some languages there is limited support for operations on + dynamic variables, so those operations must be changed. - Just a small utility filter that detects when a closure must be created. - On the default implementation, this means when a function field is being accessed - not via reflection and not to be called instantly + There are 5 types of binary operators: + 1 - can take any variable and returns a bool (== and !=) + 2 - can take either a string, or a number and returns either a bool or the underlying type ( >, < for bool and + for returning its type) + 3 - take numbers and return a number ( *, /, ...) + 4 - take ints and return an int (bit manipulation) + 5 - take a bool and returns a bool ( &&, || ...) -*) + On the default implementation, type 1 and the plus function will be handled with a function call; + Type 2 will be handled with the parameter "compare_handler", which will do something like Reflect.compare(x1, x2); + Types 3, 4 and 5 will perform a cast to double, int and bool, which will then be handled normally by the platform -module FilterClosures = -struct + Unary operators are the most difficult to handle correctly. + With unary operators, there are 2 types: - let priority = 0.0 - - let traverse gen (should_change:texpr->string->bool) (filter:texpr->texpr->string->bool->texpr) = - let rec run e = - match e.eexpr with - (*(* this is precisely the only case where we won't even ask if we should change, because it is a direct use of TClosure *) - | TCall ( {eexpr = TClosure(e1,s)} as clos, args ) -> - { e with eexpr = TCall({ clos with eexpr = TClosure(run e1, s) }, List.map run args ) } - | TCall ( clos, args ) -> - let rec loop clos = match clos.eexpr with - | TClosure(e1,s) -> Some (clos, e1, s) - | TParenthesis p -> loop p - | _ -> None - in - let clos = loop clos in - (match clos with - | Some (clos, e1, s) -> { e with eexpr = TCall({ clos with eexpr = TClosure(run e1, s) }, List.map run args ) } - | None -> Type.map_expr run e)*) - | TCall(({ eexpr = TField(_, _) } as ef), params) -> - { e with eexpr = TCall(Type.map_expr run ef, List.map run params) } - | TField(ef, FEnum(en, field)) -> - (* FIXME replace t_dynamic with actual enum Anon field *) - let ef = run ef in - (match follow field.ef_type with - | TFun _ when should_change ef field.ef_name -> - filter e ef field.ef_name true - | _ -> - { e with eexpr = TField(ef, FEnum(en,field)) } - ) - | TField(({ eexpr = TTypeExpr _ } as tf), f) -> - (match field_access gen tf.etype (field_name f) with - | FClassField(_,_,_,cf,_,_,_) -> - (match cf.cf_kind with - | Method(MethDynamic) - | Var _ -> - e - | _ when should_change tf cf.cf_name -> - filter e tf cf.cf_name true - | _ -> - e - ) - | _ -> e) - | TField(e1, FClosure (Some _, cf)) when should_change e1 cf.cf_name -> - (match cf.cf_kind with - | Method MethDynamic | Var _ -> - Type.map_expr run e - | _ -> - filter e (run e1) cf.cf_name false) - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"closures_filter" ~priority:(PCustom priority) map + 1 - can take a number, changes and returns the result (++, --, ~) + 2 - can take a number (-) or bool (!), and returns the result + + The first case is much trickier, because it doesn't seem a good idea to change any variable to double just because it is dynamic, + but this is how we will handle right now. + something like that: + + var x:Dynamic = 10; + x++; + + will be: + object x = 10; + x = ((IConvertible)x).ToDouble(null) + 1; + + depends on: + (syntax) must run before expression/statment normalization because it may generate complex expressions + must run before OverloadingCtor due to later priority conflicts. Since ExpressionUnwrap is only + defined afterwards, we will set this value with absolute values + *) + + module DynamicOperators = + struct + + let name = "dyn_ops" + + let priority = 0.0 + + let priority_as_synf = 100.0 (*solve_deps name [DBefore ExpressionUnwrap.priority]*) + + let abstract_implementation gen ?(handle_strings = true) (should_change:texpr->bool) (equals_handler:texpr->texpr->texpr) (dyn_plus_handler:texpr->texpr->texpr->texpr) (compare_handler:texpr->texpr->texpr) = + + + let get_etype_one e = + if like_int e.etype then + (gen.gcon.basic.tint, { eexpr = TConst(TInt(Int32.one)); etype = gen.gcon.basic.tint; epos = e.epos }) + else + (gen.gcon.basic.tfloat, { eexpr = TConst(TFloat("1.0")); etype = gen.gcon.basic.tfloat; epos = e.epos }) + in + + let basic = gen.gcon.basic in + + let rec run e = + match e.eexpr with + | TBinop (OpAssignOp op, e1, e2) when should_change e -> (* e1 will never contain another TBinop *) + (match e1.eexpr with + | TLocal _ -> + mk_paren { e with eexpr = TBinop(OpAssign, e1, run { e with eexpr = TBinop(op, e1, e2) }) } + | TField _ | TArray _ -> + let eleft, rest = match e1.eexpr with + | TField(ef, f) -> + let v = mk_temp gen "dynop" ef.etype in + { e1 with eexpr = TField(mk_local v ef.epos, f) }, [ { eexpr = TVar(v,Some (run ef)); etype = basic.tvoid; epos = ef.epos } ] + | TArray(e1a, e2a) -> + let v = mk_temp gen "dynop" e1a.etype in + let v2 = mk_temp gen "dynopi" e2a.etype in + { e1 with eexpr = TArray(mk_local v e1a.epos, mk_local v2 e2a.epos) }, [ + { eexpr = TVar(v,Some (run e1a)); etype = basic.tvoid; epos = e1.epos }; + { eexpr = TVar(v2, Some (run e2a)); etype = basic.tvoid; epos = e1.epos } + ] + | _ -> assert false + in + { e with + eexpr = TBlock (rest @ [ { e with eexpr = TBinop(OpAssign, eleft, run { e with eexpr = TBinop(op, eleft, e2) }) } ]); + } + | _ -> + assert false + ) + + | TBinop (OpAssign, e1, e2) + | TBinop (OpInterval, e1, e2) -> Type.map_expr run e + | TBinop (op, e1, e2) when should_change e-> + (match op with + | OpEq -> (* type 1 *) + equals_handler (run e1) (run e2) + | OpNotEq -> (* != -> !equals() *) + mk_paren { eexpr = TUnop(Ast.Not, Prefix, (equals_handler (run e1) (run e2))); etype = gen.gcon.basic.tbool; epos = e.epos } + | OpAdd -> + if handle_strings && (is_string e.etype || is_string e1.etype || is_string e2.etype) then + { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tstring (run e1), mk_cast gen.gcon.basic.tstring (run e2)) } + else + dyn_plus_handler e (run e1) (run e2) + | OpGt | OpGte | OpLt | OpLte -> (* type 2 *) + { eexpr = TBinop(op, compare_handler (run e1) (run e2), { eexpr = TConst(TInt(Int32.zero)); etype = gen.gcon.basic.tint; epos = e.epos} ); etype = gen.gcon.basic.tbool; epos = e.epos } + | OpMult | OpDiv | OpSub | OpMod -> (* always cast everything to double *) + let etype, _ = get_etype_one e in + { e with eexpr = TBinop(op, mk_cast etype (run e1), mk_cast etype (run e2)) } + | OpBoolAnd | OpBoolOr -> + { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tbool (run e1), mk_cast gen.gcon.basic.tbool (run e2)) } + | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr -> + { e with eexpr = TBinop(op, mk_cast gen.gcon.basic.tint (run e1), mk_cast gen.gcon.basic.tint (run e2)) } + | OpAssign | OpAssignOp _ | OpInterval | OpArrow -> assert false) + | TUnop (Increment as op, flag, e1) + | TUnop (Decrement as op, flag, e1) when should_change e -> + (* + some naming definitions: + * ret => the returning variable + * _g => the get body + * getvar => the get variable expr + + This will work like this: + - if e1 is a TField, set _g = get body, getvar = (get body).varname + - if Prefix, return getvar = getvar + 1.0 + - if Postfix, set ret = getvar; getvar = getvar + 1.0; ret; + *) + let etype, one = get_etype_one e in + let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false) in + + let var, getvar = + match e1.eexpr with + | TField(fexpr, field) -> + let tmp = mk_temp gen "getvar" fexpr.etype in + let var = { eexpr = TVar(tmp, Some(run fexpr)); etype = gen.gcon.basic.tvoid; epos = e.epos } in + (Some var, { eexpr = TField( { fexpr with eexpr = TLocal(tmp) }, field); etype = etype; epos = e1.epos }) + | _ -> + (None, e1) + in + + (match flag with + | Prefix -> + let block = (match var with | Some e -> [e] | None -> []) @ + [ + mk_cast etype { e with eexpr = TBinop(OpAssign, getvar,{ eexpr = TBinop(op, mk_cast etype getvar, one); etype = etype; epos = e.epos }); etype = getvar.etype; } + ] + in + { eexpr = TBlock(block); etype = etype; epos = e.epos } + | Postfix -> + let ret = mk_temp gen "ret" etype in + let vars = (match var with Some e -> [e] | None -> []) @ [{ eexpr = TVar(ret, Some (mk_cast etype getvar)); etype = gen.gcon.basic.tvoid; epos = e.epos }] in + let retlocal = { eexpr = TLocal(ret); etype = etype; epos = e.epos } in + let block = vars @ + [ + { e with eexpr = TBinop(OpAssign, getvar, { eexpr = TBinop(op, retlocal, one); etype = getvar.etype; epos = e.epos }) }; + retlocal + ] in + { eexpr = TBlock(block); etype = etype; epos = e.epos } + ) + | TUnop (op, flag, e1) when should_change e -> + let etype = match op with | Not -> gen.gcon.basic.tbool | _ -> gen.gcon.basic.tint in + mk_paren { eexpr = TUnop(op, flag, mk_cast etype (run e1)); etype = etype; epos = e.epos } + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dyn_ops" ~priority:(PCustom priority) map + + let configure_as_synf gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dyn_ops" ~priority:(PCustom priority_as_synf) map end;; @@ -2311,124 +2447,210 @@ end;; (* ******************************************* *) (* - This module will filter every dynamic field access in haxe. + This module will filter every dynamic field access in haxe. - On platforms that do not support dynamic access, it is with this that you should - replace dynamic calls with x.field / Reflect.setField calls, and guess what - - this is the default implemenation! - Actually there is a problem with Reflect.setField because it returns void, which is a bad thing for us, - so even in the default implementation, the function call should be specified to a Reflect.setField version that returns - the value that was set + On platforms that do not support dynamic access, it is with this that you should + replace dynamic calls with x.field / Reflect.setField calls, and guess what - + this is the default implemenation! + Actually there is a problem with Reflect.setField because it returns void, which is a bad thing for us, + so even in the default implementation, the function call should be specified to a Reflect.setField version that returns + the value that was set - (TODO: should it be separated?) - As a plus, the default implementation adds something that doesn't hurt anybody, it looks for - TAnon with Statics / EnumStatics field accesses and transforms them into real static calls. - This means it will take this + (TODO: should it be separated?) + As a plus, the default implementation adds something that doesn't hurt anybody, it looks for + TAnon with Statics / EnumStatics field accesses and transforms them into real static calls. + This means it will take this - var m = Math; - for (i in 0...1000) m.cos(10); + var m = Math; + for (i in 0...1000) m.cos(10); - which is an optimization in dynamic platforms, but performs horribly on strongly typed platforms - and transform into: + which is an optimization in dynamic platforms, but performs horribly on strongly typed platforms + and transform into: - var m = Math; - for (i in 0...1000) Math.cos(10); + var m = Math; + for (i in 0...1000) Math.cos(10); - (addendum:) - configure_generate_classes will already take care of generating the reflection-enabled class fields and calling abstract_implementation - with the right arguments. + (addendum:) + configure_generate_classes will already take care of generating the reflection-enabled class fields and calling abstract_implementation + with the right arguments. - Also + Also - depends on: - (ok) must run AFTER Binop/Unop handler - so Unops / Binops are already unrolled + depends on: + (ok) must run AFTER Binop/Unop handler - so Unops / Binops are already unrolled *) module DynamicFieldAccess = struct - let name = "dynamic_field_access" - - let priority = solve_deps name [DAfter DynamicOperators.priority] - - let priority_as_synf = solve_deps name [DAfter DynamicOperators.priority_as_synf] - - (* - is_dynamic (expr) (field_access_expr) (field) : a function that indicates if the field access should be changed - - change_expr (expr) (field_access_expr) (field) (setting expr) (is_unsafe) : changes the expression - call_expr (expr) (field_access_expr) (field) (call_params) : changes a call expression - *) - let abstract_implementation gen (is_dynamic:texpr->texpr->string->bool) (change_expr:texpr->texpr->string->texpr option->bool->texpr) (call_expr:texpr->texpr->string->texpr list->texpr) = - let rec run e = - match e.eexpr with - (* class types *) - | TField(fexpr, f) when is_some (anon_class fexpr.etype) -> - let decl = get (anon_class fexpr.etype) in - let name = field_name f in - (try - match decl with - | TClassDecl cl -> - let cf = PMap.find name cl.cl_statics in - { e with eexpr = TField({ fexpr with eexpr = TTypeExpr decl }, FStatic(cl, cf)) } - | TEnumDecl en -> - let ef = PMap.find name en.e_constrs in - { e with eexpr = TField({ fexpr with eexpr = TTypeExpr decl }, FEnum(en, ef)) } - | TAbstractDecl _ -> (* abstracts don't have TFields *) assert false - | TTypeDecl _ -> (* anon_class doesn't return TTypeDecl *) assert false - with - | Not_found -> - change_expr e { fexpr with eexpr = TTypeExpr decl } (field_name f) None true - ) - | TField(fexpr, f) when is_dynamic e fexpr (field_name f) -> - change_expr e (run fexpr) (field_name f) None true - | TCall( - { eexpr = TField(_, FStatic({ cl_path = ([], "Reflect") }, { cf_name = "field" })) } , - [obj; { eexpr = TConst(TString(field)) }] - ) -> - change_expr (mk_field_access gen obj field obj.epos) (run obj) field None false - | TCall( - { eexpr = TField(_, FStatic({ cl_path = ([], "Reflect") }, { cf_name = "setField" } )) }, - [obj; { eexpr = TConst(TString(field)) }; evalue] - ) -> - change_expr (mk_field_access gen obj field obj.epos) (run obj) field (Some (run evalue)) false - | TBinop(OpAssign, ({eexpr = TField(fexpr, f)}), evalue) when is_dynamic e fexpr (field_name f) -> - change_expr e (run fexpr) (field_name f) (Some (run evalue)) true - | TBinop(OpAssign, { eexpr = TField(fexpr, f) }, evalue) -> - (match field_access gen fexpr.etype (field_name f) with - | FClassField(_,_,_,cf,false,t,_) when (try PMap.find cf.cf_name gen.gbase_class_fields == cf with Not_found -> false) -> - change_expr e (run fexpr) (field_name f) (Some (run evalue)) true - | _ -> Type.map_expr run e - ) + let name = "dynamic_field_access" + + let priority = solve_deps name [DAfter DynamicOperators.priority] + + let priority_as_synf = solve_deps name [DAfter DynamicOperators.priority_as_synf] + + (* + is_dynamic (expr) (field_access_expr) (field) : a function that indicates if the field access should be changed + + change_expr (expr) (field_access_expr) (field) (setting expr) (is_unsafe) : changes the expression + call_expr (expr) (field_access_expr) (field) (call_params) : changes a call expression + *) + let abstract_implementation gen (is_dynamic:texpr->texpr->Type.tfield_access->bool) (change_expr:texpr->texpr->string->texpr option->bool->texpr) (call_expr:texpr->texpr->string->texpr list->texpr) = + let rec run e = + match e.eexpr with + (* class types *) + | TField(fexpr, f) when is_some (anon_class fexpr.etype) -> + let decl = get (anon_class fexpr.etype) in + let name = field_name f in + (try + match decl with + | TClassDecl cl -> + let cf = PMap.find name cl.cl_statics in + { e with eexpr = TField({ fexpr with eexpr = TTypeExpr decl }, FStatic(cl, cf)) } + | TEnumDecl en -> + let ef = PMap.find name en.e_constrs in + { e with eexpr = TField({ fexpr with eexpr = TTypeExpr decl }, FEnum(en, ef)) } + | TAbstractDecl _ -> (* abstracts don't have TFields *) assert false + | TTypeDecl _ -> (* anon_class doesn't return TTypeDecl *) assert false + with + | Not_found -> match f with + | FStatic(cl,cf) when Meta.has Meta.Extern cf.cf_meta -> + { e with eexpr = TField({ fexpr with eexpr = TTypeExpr decl }, FStatic(cl, cf)) } + | _ -> + change_expr e { fexpr with eexpr = TTypeExpr decl } (field_name f) None true + ) + | TField(fexpr, f) when is_dynamic e fexpr (f) -> + change_expr e (run fexpr) (field_name f) None true + | TCall( + { eexpr = TField(_, FStatic({ cl_path = ([], "Reflect") }, { cf_name = "field" })) } , + [obj; { eexpr = TConst(TString(field)) }] + ) -> + let t = match gen.greal_type obj.etype with + | TDynamic _ | TAnon _ | TMono _ -> t_dynamic + | t -> t + in + change_expr (mk_field_access gen { obj with etype = t } field obj.epos) (run obj) field None false + | TCall( + { eexpr = TField(_, FStatic({ cl_path = ([], "Reflect") }, { cf_name = "setField" } )) }, + [obj; { eexpr = TConst(TString(field)) }; evalue] + ) -> + change_expr (mk_field_access gen obj field obj.epos) (run obj) field (Some (run evalue)) false + | TBinop(OpAssign, ({eexpr = TField(fexpr, f)}), evalue) when is_dynamic e fexpr (f) -> + change_expr e (run fexpr) (field_name f) (Some (run evalue)) true + | TBinop(OpAssign, { eexpr = TField(fexpr, f) }, evalue) -> + (match field_access_esp gen fexpr.etype (f) with + | FClassField(_,_,_,cf,false,t,_) when (try PMap.find cf.cf_name gen.gbase_class_fields == cf with Not_found -> false) -> + change_expr e (run fexpr) (field_name f) (Some (run evalue)) true + | _ -> Type.map_expr run e + ) (* #if debug *) - | TBinop(OpAssignOp op, ({eexpr = TField(fexpr, f)}), evalue) when is_dynamic e fexpr (field_name f) -> assert false (* this case shouldn't happen *) - | TUnop(Increment, _, ({eexpr = TField( ( { eexpr=TLocal(local) } as fexpr ), f)})) - | TUnop(Decrement, _, ({eexpr = TField( ( { eexpr=TLocal(local) } as fexpr ), f)})) when is_dynamic e fexpr (field_name f) -> assert false (* this case shouldn't happen *) + | TBinop(OpAssignOp op, ({eexpr = TField(fexpr, f)}), evalue) when is_dynamic e fexpr (f) -> assert false (* this case shouldn't happen *) + | TUnop(Increment, _, ({eexpr = TField( ( { eexpr=TLocal(local) } as fexpr ), f)})) + | TUnop(Decrement, _, ({eexpr = TField( ( { eexpr=TLocal(local) } as fexpr ), f)})) when is_dynamic e fexpr (f) -> assert false (* this case shouldn't happen *) (* #end *) - | TCall( ({ eexpr = TField(fexpr, f) }), params ) when is_dynamic e fexpr (field_name f) -> - call_expr e (run fexpr) (field_name f) (List.map run params) - | _ -> Type.map_expr run e - in run - - (* - this function will already configure with the abstract implementation, and also will create the needed class fields to - enable reflection on platforms that don't support reflection. - - this means it will create the following class methods: - - getField(field, isStatic) - gets the value of the field. isStatic - - setField - - - - *) - let configure_generate_classes gen optimize (runtime_getset_field:texpr->texpr->string->texpr option->texpr) (runtime_call_expr:texpr->texpr->string->texpr list->texpr) = - () - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dynamic_field_access" ~priority:(PCustom(priority)) map - - let configure_as_synf gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dynamic_field_access" ~priority:(PCustom(priority_as_synf)) map + | TCall( ({ eexpr = TField(fexpr, f) }), params ) when is_dynamic e fexpr (f) -> + call_expr e (run fexpr) (field_name f) (List.map run params) + | _ -> Type.map_expr run e + in run + + (* + this function will already configure with the abstract implementation, and also will create the needed class fields to + enable reflection on platforms that don't support reflection. + + this means it will create the following class methods: + - getField(field, isStatic) - gets the value of the field. isStatic + - setField - + - + *) + let configure_generate_classes gen optimize (runtime_getset_field:texpr->texpr->string->texpr option->texpr) (runtime_call_expr:texpr->texpr->string->texpr list->texpr) = + () + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dynamic_field_access" ~priority:(PCustom(priority)) map + + let configure_as_synf gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dynamic_field_access" ~priority:(PCustom(priority_as_synf)) map + +end;; + +(* ******************************************* *) +(* Closure Detection *) +(* ******************************************* *) + +(* + + Just a small utility filter that detects when a closure must be created. + On the default implementation, this means when a function field is being accessed + not via reflection and not to be called instantly + + dependencies: + must run after DynamicFieldAccess, so any TAnon { Statics / EnumStatics } will be changed to the corresponding TTypeExpr +*) + +module FilterClosures = +struct + + let name = "filter_closures" + + let priority = solve_deps name [DAfter DynamicFieldAccess.priority] + + let traverse gen (should_change:texpr->string->bool) (filter:texpr->texpr->string->bool->texpr) = + let rec run e = + match e.eexpr with + (*(* this is precisely the only case where we won't even ask if we should change, because it is a direct use of TClosure *) + | TCall ( {eexpr = TClosure(e1,s)} as clos, args ) -> + { e with eexpr = TCall({ clos with eexpr = TClosure(run e1, s) }, List.map run args ) } + | TCall ( clos, args ) -> + let rec loop clos = match clos.eexpr with + | TClosure(e1,s) -> Some (clos, e1, s) + | TParenthesis p -> loop p + | _ -> None + in + let clos = loop clos in + (match clos with + | Some (clos, e1, s) -> { e with eexpr = TCall({ clos with eexpr = TClosure(run e1, s) }, List.map run args ) } + | None -> Type.map_expr run e)*) + | TCall({ eexpr = TLocal{ v_name = "__delegate__" } } as local, [del]) -> + { e with eexpr = TCall(local, [Type.map_expr run del]) } + | TCall(({ eexpr = TField(_, _) } as ef), params) -> + { e with eexpr = TCall(Type.map_expr run ef, List.map run params) } + | TField(ef, FEnum(en, field)) -> + (* FIXME replace t_dynamic with actual enum Anon field *) + let ef = run ef in + (match follow field.ef_type with + | TFun _ when should_change ef field.ef_name -> + filter e ef field.ef_name true + | _ -> + { e with eexpr = TField(ef, FEnum(en,field)) } + ) + | TField(({ eexpr = TTypeExpr _ } as tf), f) -> + (match field_access_esp gen tf.etype (f) with + | FClassField(_,_,_,cf,_,_,_) -> + (match cf.cf_kind with + | Method(MethDynamic) + | Var _ -> + e + | _ when should_change tf cf.cf_name -> + filter e tf cf.cf_name true + | _ -> + e + ) + | _ -> e) + | TField(e1, FClosure (Some _, cf)) when should_change e1 cf.cf_name -> + (match cf.cf_kind with + | Method MethDynamic | Var _ -> + Type.map_expr run e + | _ -> + filter e (run e1) cf.cf_name false) + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -2437,99 +2659,100 @@ end;; (* ******************************************* *) (* - In some languages you cannot overload the [] operator, - so we need to decide what is kept as TArray and what gets mapped. + In some languages you cannot overload the [] operator, + so we need to decide what is kept as TArray and what gets mapped. - - in order to do this you must ensure that + - in order to do this you must ensure that - depends on: - (syntax) must run before expression/statment normalization because it may generate complex expressions - (ok) must run before binop transformations because it may generate some untreated binop ops - (ok) must run before dynamic field access is transformed into reflection + depends on: + (syntax) must run before expression/statment normalization because it may generate complex expressions + (ok) must run before binop transformations because it may generate some untreated binop ops + (ok) must run before dynamic field access is transformed into reflection *) module TArrayTransform = struct - let name = "dyn_tarray" - - let priority = solve_deps name [DBefore DynamicOperators.priority; DBefore DynamicFieldAccess.priority] - - let priority_as_synf = solve_deps name [DBefore DynamicOperators.priority_as_synf; DBefore DynamicFieldAccess.priority_as_synf] - - let default_implementation gen (should_change:texpr->bool) (get_fun:string) (set_fun:string) = - let basic = gen.gcon.basic in - let mk_get e e1 e2 = - let efield = mk_field_access gen e1 get_fun e.epos in - { e with eexpr = TCall(efield, [e2]) } - in - let mk_set e e1 e2 evalue = - let efield = mk_field_access gen e1 set_fun e.epos in - { e with eexpr = TCall(efield, [e2; evalue]) } - in - let rec run e = - match e.eexpr with - | TArray(e1, e2) -> - (* e1 should always be a var; no need to map there *) - if should_change e then mk_get e (run e1) (run e2) else Type.map_expr run e - | TBinop (Ast.OpAssign, ({ eexpr = TArray(e1a,e2a) } as earray), evalue) when should_change earray -> - mk_set e (run e1a) (run e2a) (run evalue) - | TBinop (Ast.OpAssignOp op,({ eexpr = TArray(e1a,e2a) } as earray) , evalue) when should_change earray -> - (* cache all arguments in vars so they don't get executed twice *) - (* let ensure_local gen block name e = *) - let block = ref [] in - - let arr_local = ensure_local gen block "array" (run e1a) in - let idx_local = ensure_local gen block "index" (run e2a) in - block := (mk_set e arr_local idx_local ( { e with eexpr=TBinop(op, mk_get earray arr_local idx_local, run evalue) } )) :: !block; - - { e with eexpr = TBlock (List.rev !block) } - | TUnop(op, flag, ({ eexpr = TArray(e1a, e2a) } as earray)) -> - if should_change earray && match op with | Not | Neg -> false | _ -> true then begin - - let block = ref [] in - - let actual_t = match op with - | Ast.Increment | Ast.Decrement -> (match follow earray.etype with - | TInst _ | TAbstract _ | TEnum _ -> earray.etype - | _ -> basic.tfloat) - | Ast.Not -> basic.tbool - | _ -> basic.tint - in - - let val_v = mk_temp gen "arrVal" actual_t in - let ret_v = mk_temp gen "arrRet" actual_t in - - let arr_local = ensure_local gen block "arr" (run e1a) in - let idx_local = ensure_local gen block "arrIndex" (run e2a) in - - let val_local = { earray with eexpr = TLocal(val_v) } in - let ret_local = { earray with eexpr = TLocal(ret_v) } in - (* var idx = 1; var val = x._get(idx); var ret = val++; x._set(idx, val); ret; *) - block := { eexpr = TVars( - [ - val_v, Some(mk_get earray arr_local idx_local); (* var val = x._get(idx) *) - ret_v, Some { e with eexpr = TUnop(op, flag, val_local) } (* var ret = val++ *) - ]); - etype = gen.gcon.basic.tvoid; - epos = e2a.epos - } :: !block; - block := (mk_set e arr_local idx_local val_local) (*x._set(idx,val)*) :: !block; - block := ret_local :: !block; - { e with eexpr = TBlock (List.rev !block) } - end else - Type.map_expr run e - | _ -> Type.map_expr run e - - in run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dyn_tarray" ~priority:(PCustom priority) map - - let configure_as_synf gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:"dyn_tarray" ~priority:(PCustom priority_as_synf) map + let name = "dyn_tarray" + + let priority = solve_deps name [DBefore DynamicOperators.priority; DBefore DynamicFieldAccess.priority] + + let priority_as_synf = solve_deps name [DBefore DynamicOperators.priority_as_synf; DBefore DynamicFieldAccess.priority_as_synf] + + (* should change signature: tarray expr -> binop operation -> should change? *) + let default_implementation gen (should_change:texpr->Ast.binop option->bool) (get_fun:string) (set_fun:string) = + let basic = gen.gcon.basic in + let mk_get e e1 e2 = + let efield = mk_field_access gen e1 get_fun e.epos in + { e with eexpr = TCall(efield, [e2]) } + in + let mk_set e e1 e2 evalue = + let efield = mk_field_access gen e1 set_fun e.epos in + { e with eexpr = TCall(efield, [e2; evalue]) } + in + let rec run e = + match e.eexpr with + | TArray(e1, e2) -> + (* e1 should always be a var; no need to map there *) + if should_change e None then mk_get e (run e1) (run e2) else Type.map_expr run e + | TBinop (Ast.OpAssign, ({ eexpr = TArray(e1a,e2a) } as earray), evalue) when should_change earray (Some Ast.OpAssign) -> + mk_set e (run e1a) (run e2a) (run evalue) + | TBinop (Ast.OpAssignOp op,({ eexpr = TArray(e1a,e2a) } as earray) , evalue) when should_change earray (Some (Ast.OpAssignOp op)) -> + (* cache all arguments in vars so they don't get executed twice *) + (* let ensure_local gen block name e = *) + let block = ref [] in + + let arr_local = ensure_local gen block "array" (run e1a) in + let idx_local = ensure_local gen block "index" (run e2a) in + block := (mk_set e arr_local idx_local ( { e with eexpr=TBinop(op, mk_get earray arr_local idx_local, run evalue) } )) :: !block; + + { e with eexpr = TBlock (List.rev !block) } + | TUnop(op, flag, ({ eexpr = TArray(e1a, e2a) } as earray)) -> + if should_change earray None && match op with | Not | Neg -> false | _ -> true then begin + + let block = ref [] in + + let actual_t = match op with + | Ast.Increment | Ast.Decrement -> (match follow earray.etype with + | TInst _ | TAbstract _ | TEnum _ -> earray.etype + | _ -> basic.tfloat) + | Ast.Not -> basic.tbool + | _ -> basic.tint + in + + let val_v = mk_temp gen "arrVal" actual_t in + let ret_v = mk_temp gen "arrRet" actual_t in + + let arr_local = ensure_local gen block "arr" (run e1a) in + let idx_local = ensure_local gen block "arrIndex" (run e2a) in + + let val_local = { earray with eexpr = TLocal(val_v) } in + let ret_local = { earray with eexpr = TLocal(ret_v) } in + (* var idx = 1; var val = x._get(idx); var ret = val++; x._set(idx, val); ret; *) + block := { eexpr = TVar(val_v, Some(mk_get earray arr_local idx_local)); (* var val = x._get(idx) *) + etype = gen.gcon.basic.tvoid; + epos = e2a.epos + } :: !block; + block := { eexpr = TVar(ret_v, Some { e with eexpr = TUnop(op, flag, val_local) }); (* var ret = val++ *) + etype = gen.gcon.basic.tvoid; + epos = e2a.epos + } :: !block; + block := (mk_set e arr_local idx_local val_local) (*x._set(idx,val)*) :: !block; + block := ret_local :: !block; + { e with eexpr = TBlock (List.rev !block) } + end else + Type.map_expr run e + | _ -> Type.map_expr run e + + in run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dyn_tarray" ~priority:(PCustom priority) map + + let configure_as_synf gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:"dyn_tarray" ~priority:(PCustom priority_as_synf) map end;; @@ -2539,102 +2762,104 @@ end;; (* - 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() + 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() - dependencies: - must run before dynamic field access (?) TODO review - It's a syntax filter, as it alters types (throw wrapper) + dependencies: + must run before dynamic field access (?) TODO review + It's a syntax filter, as it alters types (throw wrapper) *) module TryCatchWrapper = struct - let priority = solve_deps "try_catch" [DBefore DynamicFieldAccess.priority] - - (* - 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->expr inside throw->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) - *) - let traverse gen (should_wrap:t->bool) (wrap_throw:texpr->texpr->texpr) (unwrap_expr:tvar->pos->texpr) (rethrow_expr:texpr->texpr) (catchall_type:t) (wrapper_type:t) (catch_map:tvar->texpr->texpr) = - let rec run e = - match e.eexpr with - | TThrow texpr when should_wrap texpr.etype -> wrap_throw e (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 (is_none catchall); - (nowrap_catches, must_wrap_catches, Some(v,catch_map v (run catch))) - (* see if we should unwrap it *) - | _ when should_wrap (follow v.v_type) -> - (nowrap_catches, (v,catch_map v (run catch)) :: must_wrap_catches, catchall) - | _ -> - ( (v,catch_map v (run catch)) :: nowrap_catches, must_wrap_catches, catchall ) - ) ([], [], None) 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 = mk_temp gen "catchallException" catchall_type in - let temp_local = { eexpr=TLocal(temp_var); etype = temp_var.v_type; epos = pos } in - let catchall_var = (*match catchall with - | None -> *) mk_temp gen "catchall" t_dynamic - (*| Some (v,_) -> v*) - in - let catchall_decl = { eexpr = TVars([catchall_var, Some(temp_local)]); etype=gen.gcon.basic.tvoid; epos = pos } in - let catchall_local = { eexpr = TLocal(catchall_var); etype = t_dynamic; epos = pos } in - (* if it is of type wrapper_type, unwrap it *) - let std_is = mk_static_field_access (get_cl (get_type gen ([],"Std"))) "is" (TFun(["v",false,t_dynamic;"cl",false,mt_to_t (get_type gen ([], "Class")) [t_dynamic]],gen.gcon.basic.tbool)) pos in - let mk_std_is t pos = { eexpr = TCall(std_is, [catchall_local; mk_mt_access (t_to_mt t) pos]); etype = gen.gcon.basic.tbool; epos = pos } in - - let if_is_wrapper_expr = { eexpr = TIf(mk_std_is wrapper_type pos, - { eexpr = TBinop(OpAssign, catchall_local, unwrap_expr temp_var pos); etype = t_dynamic; epos = pos } - , None); etype = gen.gcon.basic.tvoid; epos = pos } in - let rec loop must_wrap_catches = match must_wrap_catches with - | (vcatch,catch) :: tl -> - { eexpr = TIf(mk_std_is vcatch.v_type catch.epos, - { eexpr = TBlock({ eexpr=TVars([vcatch, Some(mk_cast vcatch.v_type catchall_local)]); etype=gen.gcon.basic.tvoid; epos=catch.epos } :: [catch] ); etype = catch.etype; epos = catch.epos }, - Some (loop tl)); - etype = catch.etype; epos = catch.epos } - | [] -> - match catchall with - | Some (v,s) -> - Codegen.concat { eexpr = TVars([v, Some(catchall_local)]); etype = gen.gcon.basic.tvoid; epos = pos } s - | None -> - mk_block (rethrow_expr temp_local) - in - [ ( temp_var, { e with eexpr = TBlock([ catchall_decl; if_is_wrapper_expr; 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 configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:"try_catch" ~priority:(PCustom priority) map + let priority = solve_deps "try_catch" [DBefore DynamicFieldAccess.priority] + + (* + 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->expr inside throw->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) + *) + let traverse gen (should_wrap:t->bool) (wrap_throw:texpr->texpr->texpr) (unwrap_expr:tvar->pos->texpr) (rethrow_expr:texpr->texpr) (catchall_type:t) (wrapper_type:t) (catch_map:tvar->texpr->texpr) = + let rec run e = + match e.eexpr with + | TThrow texpr when should_wrap texpr.etype -> wrap_throw e (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 (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 = mk_temp gen "catchallException" catchall_type in + let temp_local = { eexpr=TLocal(temp_var); etype = temp_var.v_type; epos = pos } in + let catchall_var = (*match catchall with + | None -> *) mk_temp gen "catchall" t_dynamic + (*| Some (v,_) -> v*) + in + let catchall_decl = { eexpr = TVar(catchall_var, Some(temp_local)); etype=gen.gcon.basic.tvoid; epos = pos } in + let catchall_local = { eexpr = TLocal(catchall_var); etype = t_dynamic; epos = pos } in + (* if it is of type wrapper_type, unwrap it *) + let std_is = mk_static_field_access (get_cl (get_type gen ([],"Std"))) "is" (TFun(["v",false,t_dynamic;"cl",false,mt_to_t (get_type gen ([], "Class")) [t_dynamic]],gen.gcon.basic.tbool)) pos in + let mk_std_is t pos = { eexpr = TCall(std_is, [catchall_local; mk_mt_access (t_to_mt t) pos]); etype = gen.gcon.basic.tbool; epos = pos } in + + let if_is_wrapper_expr = { eexpr = TIf(mk_std_is wrapper_type pos, + { eexpr = TBinop(OpAssign, catchall_local, unwrap_expr temp_var pos); etype = t_dynamic; epos = pos } + , None); etype = gen.gcon.basic.tvoid; epos = pos } in + let rec loop must_wrap_catches = match must_wrap_catches with + | (vcatch,catch) :: tl -> + { eexpr = TIf(mk_std_is vcatch.v_type catch.epos, + { eexpr = TBlock({ eexpr=TVar(vcatch, Some(mk_cast vcatch.v_type catchall_local)); etype=gen.gcon.basic.tvoid; epos=catch.epos } :: [catch] ); etype = catch.etype; epos = catch.epos }, + Some (loop tl)); + etype = catch.etype; epos = catch.epos } + | [] -> + match catchall with + | Some (v,s) -> + Type.concat { eexpr = TVar(v, Some(catchall_local)); etype = gen.gcon.basic.tvoid; epos = pos } s + | None -> + mk_block (rethrow_expr temp_local) + in + [ ( temp_var, catch_map temp_var { e with eexpr = TBlock([ catchall_decl; if_is_wrapper_expr; 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 configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:"try_catch" ~priority:(PCustom priority) map end;; @@ -2646,1031 +2871,1240 @@ let fun_args = List.map (function | (v,s) -> (v.v_name, (match s with | None -> (* - This is a very important filter. It will take all anonymous functions from the AST, will search for all captured variables, and will create a class - that implements an abstract interface for calling functions. This is very important for targets that don't support anonymous functions to work correctly. - Also it is possible to implement some strategies to avoid value type boxing, such as NaN tagging or double/object arguments. All this will be abstracted away - from this interface. + This is a very important filter. It will take all anonymous functions from the AST, will search for all captured variables, and will create a class + that implements an abstract interface for calling functions. This is very important for targets that don't support anonymous functions to work correctly. + Also it is possible to implement some strategies to avoid value type boxing, such as NaN tagging or double/object arguments. All this will be abstracted away + from this interface. - dependencies: - must run after dynamic field access, because of conflicting ways to deal with invokeField - (module filter) must run after OverloadingCtor so we can also change the dynamic function expressions + dependencies: + must run after dynamic field access, because of conflicting ways to deal with invokeField + (module filter) must run after OverloadingCtor so we can also change the dynamic function expressions - uses TArray expressions for array. TODO see interaction - uses TThrow expressions. + uses TArray expressions for array. TODO see interaction + uses TThrow expressions. *) module ClosuresToClass = struct - let name = "closures_to_class" - - let priority = solve_deps name [ DAfter DynamicFieldAccess.priority ] - - let priority_as_synf = solve_deps name [ DAfter DynamicFieldAccess.priority_as_synf ] - - type closures_ctx = - { - fgen : generator_ctx; - - mutable func_class : tclass; - - (* - this is what will actually turn the function into class field. - The standard implementation by default will already take care of creating the class, and setting the captured variables. - - It will also return the super arguments to be called - *) - mutable closure_to_classfield : tfunc->t->pos->tclass_field * (texpr list); - - (* - when a dynamic function call is made, we need to convert it as if it were calling the dynamic function interface. - - TCall expr -> new TCall expr - *) - mutable dynamic_fun_call : texpr->texpr; - - (* - called once so the implementation can make one of a time initializations in the base class - for all functions - *) - mutable initialize_base_class : tclass->unit; - - (* - Base classfields are the class fields for the abstract implementation of either the Function implementation, - or the invokeField implementation for the classes - They will either try to call the right function or will fail with - - (tclass - subject (so we know the type of this)) -> is_function_base -> additional arguments for each function (at the beginning) -> list of the abstract implementation class fields - *) - mutable get_base_classfields_for : tclass->bool->(unit->(tvar * tconstant option) list)->tclass_field list; - - (* - This is a more complex version of get_base_classfields_for. - It's meant to provide a toolchain so we can easily create classes that extend Function - and add more functionality on top of it. - - arguments: - tclass -> subject (so we know the type of this) - bool -> is it a function type - ( int -> (int->t->tconstant option->texpr) -> ( (tvar * tconstant option) list * texpr) ) - int -> current arity of the function whose member will be mapped; -1 for dynamic function. It is guaranteed that dynamic function will be called last - t -> the return type of the function - (int->t->tconstant option->texpr) -> api to get exprs that unwrap arguments correctly - int -> argument wanted to unwrap - t -> solicited type - tconstant option -> map to this default value if null - returns a texpr that tells how the default - should return a list with additional arguments (only works if is_function_base = true) - and the underlying function expression - *) - mutable map_base_classfields : tclass->bool->( int -> t -> (tvar list) -> (int->t->tconstant option->texpr) -> ( (tvar * tconstant option) list * texpr) )->tclass_field list; - - mutable transform_closure : texpr->texpr->string->texpr; - - } - - (* - the default implementation will take 3 transformation functions: - * one that will transform closures that are not called immediately (instance.myFunc). - normally on this case it's best to have a runtime handler that will take the instance, the function and call its invokeField when invoked - * one that will actually handle the anonymous functions themselves. - * one that will transform calling a dynamic function. So for example, dynFunc(arg1, arg2) might turn into dynFunc.apply2(arg1, arg2); - ( suspended ) * an option to match papplied functions - *) - - let traverse gen (transform_closure:texpr->texpr->string->texpr) (handle_anon_func:texpr->tfunc->texpr) (dynamic_func_call:texpr->texpr) e = - let rec run e = - match e.eexpr with - | TCall( { eexpr = TField(_, FEnum _) }, _ ) -> - Type.map_expr run e - (* if a TClosure is being call immediately, there's no need to convert it to a TClosure *) - | TCall(( { eexpr = TField(ecl,f) } as e1), params) -> - (* check to see if called field is known and if it is a MethNormal (only MethNormal fields can be called directly) *) - let name = field_name f in - (match field_access gen (gen.greal_type ecl.etype) name with - | FClassField(_,_,_,cf,_,_,_) -> - (match cf.cf_kind with - | Method MethNormal - | Method MethInline -> - { e with eexpr = TCall({ e1 with eexpr = TField(run ecl, f) }, List.map run params) } - | _ -> - match gen.gfollow#run_f e1.etype with - | TFun _ -> - dynamic_func_call { e with eexpr = TCall(run e1, List.map run params) } - | _ -> - let i = ref 0 in - let t = TFun(List.map (fun e -> incr i; "arg" ^ (string_of_int !i), false, e.etype) params, e.etype) in - dynamic_func_call { e with eexpr = TCall( mk_cast t (run e1), List.map run params ) } - ) - (* | FNotFound -> - { e with eexpr = TCall({ e1 with eexpr = TField(run ecl, f) }, List.map run params) } - (* expressions by now may have generated invalid expressions *) *) - | _ -> - match gen.gfollow#run_f e1.etype with - | TFun _ -> - dynamic_func_call { e with eexpr = TCall(run e1, List.map run params) } - | _ -> - let i = ref 0 in - let t = TFun(List.map (fun e -> incr i; "arg" ^ (string_of_int !i), false, e.etype) params, e.etype) in - dynamic_func_call { e with eexpr = TCall( mk_cast t (run e1), List.map run params ) } - ) - | TField(ecl, FClosure (_,cf)) -> - transform_closure e (run ecl) cf.cf_name - | TFunction tf -> - handle_anon_func e { tf with tf_expr = run tf.tf_expr } - | TCall({ eexpr = TConst(TSuper) }, _) -> - Type.map_expr run e - | TCall({ eexpr = TLocal(v) }, args) when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> - Type.map_expr run e - | TCall(tc,params) -> - let i = ref 0 in - let may_cast = match gen.gfollow#run_f tc.etype with - | TFun _ -> fun e -> e - | _ -> - let t = TFun(List.map (fun e -> - incr i; - ("p" ^ (string_of_int !i), false, e.etype) - ) params, e.etype) - in - fun e -> mk_cast t e - in - dynamic_func_call { e with eexpr = TCall(run (may_cast tc), List.map run params) } - | _ -> Type.map_expr run e - in - - (match e.eexpr with - | TFunction(tf) -> Type.map_expr run e - | _ -> run e) - - let rec get_type_params acc t = - match t with - | TInst(( { cl_kind = KTypeParameter _ } as cl), []) -> - if List.memq cl acc then acc else cl :: acc - | TFun (params,tret) -> - List.fold_left get_type_params acc ( tret :: List.map (fun (_,_,t) -> t) params ) - | TDynamic t -> - (match t with | TDynamic _ -> acc | _ -> get_type_params acc t) - | TAbstract ({ a_impl = Some _ } as a, pl) -> - get_type_params acc ( Codegen.Abstract.get_underlying_type a pl) - | TAnon a -> - PMap.fold (fun cf acc -> get_type_params acc cf.cf_type) a.a_fields acc - | TType(_, []) - | TAbstract (_, []) - | TInst(_, []) - | TEnum(_, []) -> - acc - | TType(_, params) - | TAbstract(_, params) - | TEnum(_, params) - | TInst(_, params) -> - List.fold_left get_type_params acc params - | TMono r -> (match !r with - | Some t -> get_type_params acc t - | None -> acc) - | _ -> get_type_params acc (follow_once t) - - let get_captured expr = - let ret = Hashtbl.create 1 in - let ignored = Hashtbl.create 0 in - - let params = ref [] in - let check_params t = params := get_type_params !params t in - let rec traverse expr = - match expr.eexpr with - | TFor (v, _, _) -> - Hashtbl.add ignored v.v_id v; - check_params v.v_type; - Type.iter traverse expr - | TFunction(tf) -> - List.iter (fun (v,_) -> check_params v.v_type; Hashtbl.add ignored v.v_id v) tf.tf_args; - check_params tf.tf_type; - Type.iter traverse expr - | TVars (vars) -> - List.iter (fun (v, opt) -> check_params v.v_type; Hashtbl.add ignored v.v_id v; ignore(Option.map traverse opt)) vars; - | TLocal(( { v_capture = true } ) as v) -> - (if not (Hashtbl.mem ignored v.v_id || Hashtbl.mem ret v.v_id) then begin check_params v.v_type; Hashtbl.replace ret v.v_id expr end); - | _ -> Type.iter traverse expr - in traverse expr; - ret, !params - - (* - OPTIMIZEME: - - Take off from Codegen the code that wraps captured variables, - - traverse through all variables, looking for their use (just like local_usage) - three possible outcomes for captured variables: - - become a function member variable <- best performance. - Will not work on functions that can be created more than once (functions inside a loop or functions inside functions) - The function will have to be created on top of the block, so its variables can be filled in instead of being declared - - single-element array - the most compatible way, though also creates a slight overhead. - - we'll have some labels for captured variables: - - used in loop - *) - - (* - The default implementation will impose a naming convention: - invoke(arity)_(o for returning object/d for returning double) when arity < max_arity - invoke_dynamic_(o/d) when arity > max_arity - - This means that it also imposes that the dynamic function return types may only be Dynamic or Float, and all other basic types must be converted to/from it. - *) - - let default_implementation ft parent_func_class (* e.g. new haxe.lang.ClassClosure *) = - let gen = ft.fgen in - ft.initialize_base_class parent_func_class; - let cfs = ft.get_base_classfields_for parent_func_class true (fun () -> []) in - List.iter (fun cf -> - (if cf.cf_name = "new" then parent_func_class.cl_constructor <- Some cf else - parent_func_class.cl_fields <- PMap.add cf.cf_name cf parent_func_class.cl_fields - ) - ) cfs; - - parent_func_class.cl_ordered_fields <- (List.filter (fun cf -> cf.cf_name <> "new") cfs) @ parent_func_class.cl_ordered_fields; - - ft.func_class <- parent_func_class; - - traverse - ft.fgen - (* (transform_closure:texpr->texpr->string->texpr) (handle_anon_func:texpr->tfunc->texpr) (dynamic_func_call:texpr->texpr->texpr list->texpr) *) - ft.transform_closure - (fun fexpr tfunc -> (* (handle_anon_func:texpr->tfunc->texpr) *) - (* get all captured variables it uses *) - let captured_ht, tparams = get_captured fexpr in - let captured = Hashtbl.fold (fun _ e acc -> e :: acc) captured_ht [] in - - (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*) - let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(cl, []) )) tparams in - - (* create a new class that extends abstract function class, with a ctor implementation that will setup all captured variables *) - let buf = Buffer.create 72 in - ignore (Type.map_expr (fun e -> - Buffer.add_string buf (Marshal.to_string (ExprHashtblHelper.mk_type e) [Marshal.Closures]); - e - ) tfunc.tf_expr); - let digest = Digest.to_hex (Digest.string (Buffer.contents buf)) in - let path = (fst ft.fgen.gcurrent_path, "Fun_" ^ (String.sub digest 0 8)) in - let cls = mk_class (get ft.fgen.gcurrent_class).cl_module path tfunc.tf_expr.epos in - cls.cl_module <- (get ft.fgen.gcurrent_class).cl_module; - cls.cl_types <- cltypes; - - let mk_this v pos = - { - (mk_field_access gen { eexpr = TConst TThis; etype = TInst(cls, List.map snd cls.cl_types); epos = pos } v.v_name pos) - with etype = v.v_type - } - in - - let mk_this_assign v pos = - { - eexpr = TBinop(OpAssign, mk_this v pos, { eexpr = TLocal(v); etype = v.v_type; epos = pos }); - etype = v.v_type; - epos = pos - } in - - (* mk_class_field name t public pos kind params *) - let ctor_args, ctor_sig, ctor_exprs = List.fold_left (fun (ctor_args, ctor_sig, ctor_exprs) lexpr -> - match lexpr.eexpr with - | TLocal(v) -> - let cf = mk_class_field v.v_name v.v_type false lexpr.epos (Var({ v_read = AccNormal; v_write = AccNormal; })) [] in - cls.cl_fields <- PMap.add v.v_name cf cls.cl_fields; - cls.cl_ordered_fields <- cf :: cls.cl_ordered_fields; - - 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 - ) ([],[],[]) captured in - - (* change all captured variables to this.capturedVariable *) - let rec change_captured e = - match e.eexpr with - | TLocal( ({ v_capture = true }) as v ) when Hashtbl.mem captured_ht v.v_id -> - mk_this v e.epos - | _ -> Type.map_expr change_captured e - in - let func_expr = change_captured tfunc.tf_expr in - - let invoke_field, super_args = ft.closure_to_classfield { tfunc with tf_expr = func_expr } fexpr.etype fexpr.epos in - - - (* create the constructor *) - (* todo properly abstract how type var is set *) - - cls.cl_super <- Some(parent_func_class, []); - let pos = cls.cl_pos in - let super_call = - { - eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(parent_func_class,[]); epos = pos }, super_args); - etype = ft.fgen.gcon.basic.tvoid; - epos = pos; - } in - - let ctor_type = (TFun(ctor_sig, ft.fgen.gcon.basic.tvoid)) in - let ctor = mk_class_field "new" ctor_type true cls.cl_pos (Method(MethNormal)) [] in - ctor.cf_expr <- Some( - { - eexpr = TFunction( - { - tf_args = ctor_args; - tf_type = ft.fgen.gcon.basic.tvoid; - tf_expr = { eexpr = TBlock(super_call :: ctor_exprs); etype = ft.fgen.gcon.basic.tvoid; epos = cls.cl_pos } - }); - etype = ctor_type; - epos = cls.cl_pos; - }); - cls.cl_constructor <- Some(ctor); - - (* add invoke function to the class *) - cls.cl_ordered_fields <- invoke_field :: cls.cl_ordered_fields; - cls.cl_fields <- PMap.add invoke_field.cf_name invoke_field cls.cl_fields; - cls.cl_overrides <- invoke_field :: cls.cl_overrides; - - (* add this class to the module with gadd_to_module *) - ft.fgen.gadd_to_module (TClassDecl(cls)) priority; - - (* if there are no captured variables, we can create a cache so subsequent calls don't need to create a new function *) - match captured, tparams with - | [], [] -> - let cache_var = ft.fgen.gmk_internal_name "hx" "current" in - let cache_cf = mk_class_field cache_var (TInst(cls,[])) false func_expr.epos (Var({ v_read = AccNormal; v_write = AccNormal })) [] in - cls.cl_ordered_statics <- cache_cf :: cls.cl_ordered_statics; - cls.cl_statics <- PMap.add cache_var cache_cf cls.cl_statics; - - (* if (FuncClass.hx_current != null) FuncClass.hx_current; else (FuncClass.hx_current = new FuncClass()); *) - - (* let mk_static_field_access cl field fieldt pos = *) - let hx_current = mk_static_field_access cls cache_var (TInst(cls,[])) func_expr.epos in - - let pos = func_expr.epos in - { - fexpr with - - eexpr = TIf( - { - eexpr = TBinop(OpNotEq, hx_current, null (TInst(cls,[])) pos); - etype = ft.fgen.gcon.basic.tbool; - epos = pos; - }, - - hx_current, - - Some( - { - eexpr = TBinop(OpAssign, hx_current, { fexpr with eexpr = TNew(cls, [], captured) }); - etype = (TInst(cls,[])); - epos = pos; - })) - - } - - | _ -> - (* change the expression so it will be a new "added class" ( captured variables arguments ) *) - { fexpr with eexpr = TNew(cls, List.map (fun cl -> TInst(cl,[])) tparams, List.rev captured) } - - - ) - ft.dynamic_fun_call - (* (dynamic_func_call:texpr->texpr->texpr list->texpr) *) - - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map - - let configure_as_synf gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority_as_synf) map - - - (* - this submodule will provide the default implementation for the C# and Java targets. - - it will have two return types: double and dynamic, and - *) - module DoubleAndDynamicClosureImpl = - struct - - let get_ctx gen max_arity = - - let basic = gen.gcon.basic in - - let func_args_i i = - - let rec loop i (acc1,acc2) = - if i = 0 then (acc1,acc2) else begin - let vfloat = alloc_var (gen.gmk_internal_name "fn" ("float" ^ string_of_int i)) basic.tfloat in - let vdyn = alloc_var (gen.gmk_internal_name "fn" ("dyn" ^ string_of_int i)) t_dynamic in - - loop (i - 1) ((vfloat, None) :: acc1 , (vdyn, None) :: acc2) - end - in - let acc1, acc2 = loop i ([],[]) in - acc1 @ acc2 - - in - - let args_real_to_func args = - - let arity = List.length args in - if arity >= max_arity then - [ alloc_var (gen.gmk_internal_name "fn" "dynargs") (basic.tarray t_dynamic), None ] - else func_args_i arity - in - - let func_sig_i i = - - let rec loop i (acc1,acc2) = - if i = 0 then (acc1,acc2) else begin - let vfloat = gen.gmk_internal_name "fn" ("float" ^ string_of_int i) in - let vdyn = gen.gmk_internal_name "fn" ("dyn" ^ string_of_int i) in - - loop (i - 1) ((vfloat, false, basic.tfloat) :: acc1 , (vdyn, false, t_dynamic) :: acc2) - end - in - let acc1, acc2 = loop i ([],[]) in - acc1 @ acc2 - - in - - let args_real_to_func_sig args = - - let arity = List.length args in - if arity >= max_arity then - [gen.gmk_internal_name "fn" "dynargs", false, basic.tarray t_dynamic] - else begin - func_sig_i arity - end - - in - - let rettype_real_to_func t = - if like_float t then - (1, basic.tfloat) - else - (0, t_dynamic) - in - - let args_real_to_func_call el (pos:Ast.pos) = - if List.length el >= max_arity then - [{ eexpr = TArrayDecl el; etype = basic.tarray t_dynamic; epos = pos }] - else begin - let acc1,acc2 = List.fold_left (fun (acc_f,acc_d) e -> - if like_float (gen.greal_type e.etype) then - ( e :: acc_f, undefined e.epos :: acc_d ) - else - ( null basic.tfloat e.epos :: acc_f, e :: acc_d ) - ) ([],[]) (List.rev el) in - acc1 @ acc2 - end - in - - let const_type c def = - match c with - | TString _ -> basic.tstring | TInt _ -> basic.tint - | TFloat _ -> basic.tfloat | TBool _ -> basic.tbool - | _ -> def - in - - let get_args_func args changed_args pos = - let arity = List.length args in - let mk_const const elocal t = - match const with - | None -> mk_cast t elocal - | Some const -> - { eexpr = TIf( - { elocal with eexpr = TBinop(Ast.OpEq, elocal, null elocal.etype elocal.epos); etype = basic.tbool }, - { elocal with eexpr = TConst(const); etype = const_type const t }, - Some ( mk_cast t elocal ) - ); etype = t; epos = elocal.epos } - in - - if arity >= max_arity then begin - let varray = match changed_args with | [v,_] -> v | _ -> assert false in - let varray_local = mk_local varray pos in - let mk_varray i = { eexpr = TArray(varray_local, { eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }); etype = t_dynamic; epos = pos } in - - snd (List.fold_left (fun (count,acc) (v,const) -> - (count + 1, - { - eexpr = TVars([v, Some(mk_const const ( mk_varray count ) v.v_type)]); - etype = basic.tvoid; - epos = pos; - } :: acc) - ) (0,[]) args) - end else begin - let _, dyn_args, float_args = List.fold_left (fun (count,fargs, dargs) arg -> - if count > arity then - (count + 1, fargs, arg :: dargs) - else - (count + 1, arg :: fargs, dargs) - ) (1,[],[]) (List.rev changed_args) in - - let rec loop acc args fargs dargs = - match args, fargs, dargs with - | [], [], [] -> acc - | (v,const) :: args, (vf,_) :: fargs, (vd,_) :: dargs -> - let acc = { eexpr = TVars([ v, Some( - { - eexpr = TIf( - { eexpr = TBinop(Ast.OpEq, mk_local vd pos, undefined pos); etype = basic.tbool; epos = pos }, - mk_cast v.v_type (mk_local vf pos), - Some ( mk_const const (mk_local vd pos) v.v_type ) - ); - etype = v.v_type; - epos = pos - } ) ]); etype = basic.tvoid; epos = pos } :: acc in - loop acc args fargs dargs - | _ -> assert false - in - - loop [] args float_args dyn_args - end - in - - let closure_to_classfield tfunc old_sig pos = - (* change function signature *) - let old_args = tfunc.tf_args in - let changed_args = args_real_to_func old_args in - - (* - FIXME properly handle int64 cases, which will break here (because of inference to int) - UPDATE: the fix will be that Int64 won't be a typedef to Float/Int - *) - let changed_sig, arity, type_number, changed_sig_ret, is_void, is_dynamic_func = match follow old_sig with - | TFun(_sig, ret) -> - let type_n, ret_t = rettype_real_to_func ret in - let arity = List.length _sig in - let is_dynamic_func = arity >= max_arity in - 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, is_void ret, is_dynamic_func) - | _ -> (trace (s_type (print_context()) (follow old_sig) )); assert false - in - - let tf_expr = if is_void then begin - let rec map e = - match e.eexpr with - | TReturn None -> { e with eexpr = TReturn (Some (null t_dynamic e.epos)) } - | _ -> Type.map_expr map e - in - let e = mk_block (map tfunc.tf_expr) in - match e.eexpr with - | TBlock(bl) -> - { e with eexpr = TBlock(bl @ [{ eexpr = TReturn (Some (null t_dynamic e.epos)); etype = t_dynamic; epos = e.epos }]) } - | _ -> assert false - end else tfunc.tf_expr in - - let changed_sig_ret = if is_dynamic_func then t_dynamic else changed_sig_ret in - - (* get real arguments on top of function body *) - let get_args = get_args_func tfunc.tf_args changed_args pos in - (* - FIXME HACK: in order to be able to run the filters that have already ran for this piece of code, - we will cheat and run it as if it was the whole code - We could just make ClosuresToClass run before TArrayTransform, but we cannot because of the - dependency between ClosuresToClass (after DynamicFieldAccess, and before TArrayTransform) - - maybe a way to solve this would be to add an "until" field to run_from - *) - let real_get_args = gen.gexpr_filters#run_f { eexpr = TBlock(get_args); etype = basic.tvoid; epos = pos } in - - let func_expr = Codegen.concat real_get_args tf_expr in - - (* set invoke function *) - (* todo properly abstract how naming for invoke is made *) - let invoke_name = if is_dynamic_func then "invokeDynamic" else ("invoke" ^ (string_of_int arity) ^ (if type_number = 0 then "_o" else "_f")) in - let invoke_name = gen.gmk_internal_name "hx" invoke_name in - let invoke_field = mk_class_field invoke_name changed_sig false func_expr.epos (Method(MethNormal)) [] in - let invoke_fun = - { - eexpr = TFunction( - { - tf_args = changed_args; - tf_type = changed_sig_ret; - tf_expr = func_expr; - }); - etype = changed_sig; - epos = func_expr.epos; - } in - invoke_field.cf_expr <- Some(invoke_fun); - - (invoke_field, [ - { eexpr = TConst(TInt( Int32.of_int arity )); etype = gen.gcon.basic.tint; epos = pos }; - { eexpr = TConst(TInt( Int32.of_int type_number )); etype = gen.gcon.basic.tint; epos = pos }; - ]) - in - - let dynamic_fun_call call_expr = - let tc, params = match call_expr.eexpr with - | TCall(tc, params) -> (tc, params) - | _ -> assert false - in - let postfix, ret_t = - if like_float (gen.greal_type call_expr.etype) then - "_f", gen.gcon.basic.tfloat - else - "_o", t_dynamic - in - let params_len = List.length params in - let ret_t = if params_len >= max_arity then t_dynamic else ret_t in - - let invoke_fun = if params_len >= max_arity then "invokeDynamic" else "invoke" ^ (string_of_int params_len) ^ postfix in - let invoke_fun = gen.gmk_internal_name "hx" invoke_fun in - let fun_t = match follow tc.etype with - | TFun(_sig, _) -> - TFun(args_real_to_func_sig _sig, ret_t) - | _ -> - let i = ref 0 in - let _sig = List.map (fun p -> let name = "arg" ^ (string_of_int !i) in incr i; (name,false,p.etype) ) params in - TFun(args_real_to_func_sig _sig, ret_t) - in - - let may_cast = match follow call_expr.etype with - | TEnum({ e_path = ([], "Void")}, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> (fun e -> e) - | _ -> mk_cast call_expr.etype - in - - may_cast - { - eexpr = TCall( - { (mk_field_access gen { tc with etype = gen.greal_type tc.etype } invoke_fun tc.epos) with etype = fun_t }, - args_real_to_func_call params call_expr.epos - ); - etype = ret_t; - epos = call_expr.epos - } - in - - let iname is_function i is_float = - let postfix = if is_float then "_f" else "_o" in - gen.gmk_internal_name "hx" ("invoke" ^ (if not is_function then "Field" else "") ^ string_of_int i) ^ postfix - in - - let map_base_classfields cl is_function map_fn = - - let pos = cl.cl_pos in - let this_t = TInst(cl,List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - - let mk_invoke_i i is_float = - let cf = mk_class_field (iname is_function i is_float) (TFun(func_sig_i i, if is_float then basic.tfloat else t_dynamic)) false pos (Method MethNormal) [] in - cf - in - - let type_name = gen.gmk_internal_name "fn" "type" in - - let dynamic_arg = alloc_var (gen.gmk_internal_name "fn" "dynargs") (basic.tarray t_dynamic) in - - let mk_invoke_complete_i i is_float = - - let arity = i in - let args = func_args_i i in - - (* api fn *) - - (* only cast if needed *) - let mk_cast tto efrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type efrom.etype) efrom in - let api i t const = - let vf, _ = List.nth args i in - let vo, _ = List.nth args (i + arity) in - - let needs_cast, is_float = match t, like_float t with - | TInst({ cl_path = ([], "Float") }, []), _ - | TAbstract({ a_path = ([], "Float") },[]), _ -> false, true - | _, true -> true, true - | _ -> false,false - in - - let olocal = mk_local vo pos in - let flocal = mk_local vf pos in - - let get_from_obj e = match const with - | None -> mk_cast t e - | Some tc -> - { - eexpr = TIf( - { eexpr = TBinop(Ast.OpEq, olocal, null t_dynamic pos); etype = basic.tbool; epos = pos } , - { eexpr = TConst(tc); etype = t; epos = pos }, - Some (mk_cast t e) - ); - etype = t; - epos = pos; - } - in - - { - eexpr = TIf( - { eexpr = TBinop(Ast.OpEq, olocal, undefined pos); etype = basic.tbool; epos = pos }, - (if needs_cast then mk_cast t flocal else flocal), - Some ( get_from_obj olocal ) - ); - etype = t; - epos = pos - } - in - (* end of api fn *) - - let ret = if is_float then basic.tfloat else t_dynamic in - - let added_args, fn_expr = map_fn i ret (List.map fst args) api in - let args = added_args @ args in - - let t = TFun(fun_args args, ret) in - - let tfunction = - { - eexpr = TFunction({ - tf_args = args; - tf_type = ret; - tf_expr = - mk_block fn_expr - }); - etype = t; - epos = pos; - } - in - - let cf = mk_invoke_i i is_float in - cf.cf_expr <- Some tfunction; - cf - in - - let rec loop i cfs = - if i < 0 then cfs else begin - (*let mk_invoke_complete_i i is_float =*) - (mk_invoke_complete_i i false) :: (mk_invoke_complete_i i true) :: (loop (i-1) cfs) - end - in - - let cfs = loop max_arity [] in - - let added_s_args, switch = - let api i t const = - match i with - | -1 -> - mk_local dynamic_arg pos - | _ -> - mk_cast t { - eexpr = TArray( - mk_local dynamic_arg pos, - { eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }); - etype = t; - epos = pos; - } - in - map_fn (-1) t_dynamic [dynamic_arg] api - in - - let args = added_s_args @ [dynamic_arg, None] in - let dyn_t = TFun(fun_args args, t_dynamic) in - let dyn_cf = mk_class_field (gen.gmk_internal_name "hx" "invokeDynamic") dyn_t false pos (Method MethNormal) [] in - - dyn_cf.cf_expr <- - Some { - eexpr = TFunction({ - tf_args = args; - tf_type = t_dynamic; - tf_expr = mk_block switch - }); - etype = dyn_t; - epos = pos; - }; - - let additional_cfs = if is_function then begin - let new_t = TFun(["arity", false, basic.tint; "type", false, basic.tint],basic.tvoid) in - let new_cf = mk_class_field "new" (new_t) true pos (Method MethNormal) [] in - let v_arity, v_type = alloc_var "arity" basic.tint, alloc_var "type" basic.tint in - let mk_assign v field = { eexpr = TBinop(Ast.OpAssign, mk_this field v.v_type, mk_local v pos); etype = v.v_type; epos = pos } in - - let arity_name = gen.gmk_internal_name "hx" "arity" in - new_cf.cf_expr <- - Some { - eexpr = TFunction({ - tf_args = [v_arity, None; v_type, None]; - tf_type = basic.tvoid; - tf_expr = - { - eexpr = TBlock([ - mk_assign v_type type_name; - mk_assign v_arity arity_name - ]); - etype = basic.tvoid; - epos = pos; - } - }); - etype = new_t; - epos = pos; - } - ; - - [ - new_cf; - mk_class_field type_name basic.tint true pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - mk_class_field arity_name basic.tint true pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - ] - end else [] in - - dyn_cf :: (additional_cfs @ cfs) - in - - (* maybe another param for prefix *) - let get_base_classfields_for cl is_function mk_additional_args = - let pos = cl.cl_pos in - - let this_t = TInst(cl,List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - - let rec mk_dyn_call arity api = - let zero = { eexpr = TConst(TFloat("0.0")); etype = basic.tfloat; epos = pos } in - let rec loop i (acc1,acc2) = - if i = 0 then (acc1,acc2) else begin - let arr = api (i-1) t_dynamic None in - loop (i - 1) (zero :: acc1, arr :: acc2) - end - in - let acc1, acc2 = loop arity ([],[]) in - acc1 @ acc2 - in - - let mk_invoke_switch i (api:(int->t->tconstant option->texpr)) = - - let t = TFun(func_sig_i i,t_dynamic) in - - (* case i: return this.invokeX_o(0, 0, 0, 0, 0, ... arg[0], args[1]....); *) - ( [{ eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }], - { - eexpr = TReturn(Some( { - eexpr = TCall(mk_this (iname is_function i false) t, mk_dyn_call i api); - etype = t_dynamic; - epos = pos; - } )); - etype = t_dynamic; - epos = pos; - } ) - in - - let cl_t = TInst(cl,List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = cl_t; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - let mk_int i = { eexpr = TConst(TInt ( Int32.of_int i)); etype = basic.tint; epos = pos } in - let mk_string s = { eexpr = TConst(TString s); etype = basic.tstring; epos = pos } in - - (* - if it is the Function class, the base class fields will be - * hx::invokeX_d|o (where X is from 0 to max_arity) (args) - { - if (this.type == 0|1) return invokeX_o|d(args); else throw "Invalid number of arguments." - } - - hx::invokeDynamic, which will work in the same way - - new(arity, type) - { - if (type != 0 && type != 1) throw "Invalid type"; - this.arity = arity; - this.type = type; - } - *) - let type_name = gen.gmk_internal_name "fn" "type" in - - let mk_expr i is_float vars = - - let name = if is_function then "invoke" else "invokeField" in - - let look_ahead = alloc_var "lookAhead" basic.tbool in - let add_args = if not is_function then mk_additional_args() else [] in - let vars = if not is_function then (List.map fst add_args) @ (look_ahead :: vars) else vars in - - let call_expr = - - let call_t = TFun(List.map (fun v -> (v.v_name, false, v.v_type)) vars, if is_float then t_dynamic else basic.tfloat) in - { - eexpr = TCall(mk_this (gen.gmk_internal_name "hx" (name ^ (string_of_int i) ^ (if is_float then "_o" else "_f"))) call_t, List.map (fun v -> if v.v_id = look_ahead.v_id then ( { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } ) else mk_local v pos) vars ); - etype = if is_float then t_dynamic else basic.tfloat; - epos = pos - } - in - (*let call_expr = if is_float then mk_cast basic.tfloat call_expr else call_expr in*) - - let if_cond = if is_function then - { eexpr=TBinop(Ast.OpNotEq, mk_this type_name basic.tint, mk_int (if is_float then 0 else 1) ); etype = basic.tbool; epos = pos } - else - mk_local look_ahead pos - in - - let if_expr = if is_function then - { - eexpr = TIf(if_cond, - { eexpr = TThrow(mk_string "Wrong number of arguments"); etype = basic.tstring; epos = pos }, - Some( { eexpr = TReturn( Some( call_expr ) ); etype = call_expr.etype; epos = pos } ) - ); - etype = t_dynamic; - epos = pos; - } - else - { - eexpr = TIf(if_cond, - { eexpr = TReturn( Some( call_expr ) ); etype = call_expr.etype; epos = pos }, - Some( { eexpr = TThrow(mk_string "Field not found or wrong number of arguments"); etype = basic.tstring; epos = pos } ) - ); - etype = t_dynamic; - epos = pos; - } - in - - let args = if not is_function then (mk_additional_args()) @ [look_ahead, None] else [] in - (args, if_expr) - in - - let arities_processed = Hashtbl.create 10 in - let max_arity = ref 0 in - - let rec loop_cases api arity acc = - if arity < 0 then acc else - loop_cases api (arity - 1) (mk_invoke_switch arity api :: acc) - in - (* let rec loop goes here *) - let map_fn cur_arity fun_ret_type vars (api:(int->t->tconstant option->texpr)) = - let is_float = like_float fun_ret_type in - match cur_arity with - | -1 -> - let dynargs = api (-1) (t_dynamic) None in - let switch_cond = mk_field_access gen dynargs "length" pos in - let switch_cond = { - eexpr = TIf( - { eexpr = TBinop(Ast.OpEq, dynargs, null dynargs.etype pos); etype = basic.tbool; epos = pos; }, - { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }, - Some switch_cond); - etype = basic.tint; - epos = pos; - } in - - let switch = - { - eexpr = TSwitch( switch_cond, - loop_cases api !max_arity [], - Some({ eexpr = TThrow(mk_string "Too many arguments"); etype = basic.tvoid; epos = pos; }) ); - etype = basic.tvoid; - epos = pos; - } in - - ( (if not is_function then mk_additional_args () else []), switch ) - | _ -> - if not (Hashtbl.mem arities_processed cur_arity) then begin - Hashtbl.add arities_processed cur_arity true; - if cur_arity > !max_arity then max_arity := cur_arity - end; - - mk_expr cur_arity is_float vars - in - - map_base_classfields cl is_function map_fn - in - - let initialize_base_class cl = - () - in - - { - fgen = gen; - - func_class = null_class; - - closure_to_classfield = closure_to_classfield; - - dynamic_fun_call = dynamic_fun_call; - - (* - called once so the implementation can make one of a time initializations in the base class - for all functions - *) - initialize_base_class = initialize_base_class; - - (* - Base classfields are the class fields for the abstract implementation of either the Function implementation, - or the invokeField implementation for the classes - They will either try to call the right function or will fail with - - (tclass - subject (so we know the type of this)) -> is_function_base -> list of the abstract implementation class fields - *) - get_base_classfields_for = get_base_classfields_for; - - map_base_classfields = map_base_classfields; - - (* - for now we won't deal with the closures. - They can be dealt with the module ReflectionCFs, - or a custom implementation - *) - transform_closure = (fun tclosure texpr str -> tclosure); - - } - - end;; + let name = "closures_to_class" + + let priority = solve_deps name [ DAfter DynamicFieldAccess.priority ] + + let priority_as_synf = solve_deps name [ DAfter DynamicFieldAccess.priority_as_synf ] + + type closures_ctx = + { + fgen : generator_ctx; + + mutable func_class : tclass; + + (* + this is what will actually turn the function into class field. + The standard implementation by default will already take care of creating the class, and setting the captured variables. + + It will also return the super arguments to be called + *) + mutable closure_to_classfield : tfunc->t->pos->tclass_field * (texpr list); + + (* + when a dynamic function call is made, we need to convert it as if it were calling the dynamic function interface. + + TCall expr -> new TCall expr + *) + mutable dynamic_fun_call : texpr->texpr; + + (* + called once so the implementation can make one of a time initializations in the base class + for all functions + *) + mutable initialize_base_class : tclass->unit; + + (* + Base classfields are the class fields for the abstract implementation of either the Function implementation, + or the invokeField implementation for the classes + They will either try to call the right function or will fail with + + (tclass - subject (so we know the type of this)) -> is_function_base -> additional arguments for each function (at the beginning) -> list of the abstract implementation class fields + *) + mutable get_base_classfields_for : tclass->bool->(unit->(tvar * tconstant option) list)->tclass_field list; + + (* + This is a more complex version of get_base_classfields_for. + It's meant to provide a toolchain so we can easily create classes that extend Function + and add more functionality on top of it. + + arguments: + tclass -> subject (so we know the type of this) + bool -> is it a function type + ( int -> (int->t->tconstant option->texpr) -> ( (tvar * tconstant option) list * texpr) ) + int -> current arity of the function whose member will be mapped; -1 for dynamic function. It is guaranteed that dynamic function will be called last + t -> the return type of the function + (int->t->tconstant option->texpr) -> api to get exprs that unwrap arguments correctly + int -> argument wanted to unwrap + t -> solicited type + tconstant option -> map to this default value if null + returns a texpr that tells how the default + should return a list with additional arguments (only works if is_function_base = true) + and the underlying function expression + *) + mutable map_base_classfields : tclass->bool->( int -> t -> (tvar list) -> (int->t->tconstant option->texpr) -> ( (tvar * tconstant option) list * texpr) )->tclass_field list; + + mutable transform_closure : texpr->texpr->string->texpr; + + } + + type map_info = { + in_unsafe : bool; + in_unused : bool; + } + + let null_map_info = { in_unsafe = false; in_unused = false; } + + (* + the default implementation will take 3 transformation functions: + * one that will transform closures that are not called immediately (instance.myFunc). + normally on this case it's best to have a runtime handler that will take the instance, the function and call its invokeField when invoked + * one that will actually handle the anonymous functions themselves. + * one that will transform calling a dynamic function. So for example, dynFunc(arg1, arg2) might turn into dynFunc.apply2(arg1, arg2); + ( suspended ) * an option to match papplied functions + * handling parameterized anonymous function declaration (optional - tparam_anon_decl and tparam_anon_acc) + *) + + let rec cleanup_delegate e = match e.eexpr with + | TParenthesis e | TMeta(_,e) + | TCast(e,_) -> cleanup_delegate e + | _ -> e + + let funct gen t = match follow (run_follow gen t) with + | TFun(args,ret) -> args,ret + | _ -> raise Not_found + + let mk_conversion_fun gen e = + let args, ret = funct gen e.etype in + let tf_args = List.map (fun (n,o,t) -> alloc_var n t,None) args in + let block, local = match e.eexpr with + | TLocal v -> + v.v_capture <- true; + [],e + | _ -> + let tmp = mk_temp gen "delegate_conv" e.etype in + tmp.v_capture <- true; + [{ eexpr = TVar(tmp,Some e); etype = gen.gcon.basic.tvoid; epos = e.epos }], mk_local tmp e.epos + in + let body = { + eexpr = TCall(local, List.map (fun (v,_) -> mk_local v e.epos) tf_args); + etype = ret; + epos = e.epos; + } in + let body = if not (is_void ret) then + { body with eexpr = TReturn( Some body ) } + else + body + in + let body = { + eexpr = TBlock(block @ [body]); + etype = body.etype; + epos = body.epos; + } in + { + tf_args = tf_args; + tf_expr = body; + tf_type = ret; + } + + let traverse gen ?tparam_anon_decl ?tparam_anon_acc (transform_closure:texpr->texpr->string->texpr) (handle_anon_func:texpr->tfunc->map_info->t option->texpr) (dynamic_func_call:texpr->texpr) e = + let info = ref null_map_info in + let rec run e = + match e.eexpr with + | TCast({ eexpr = TCall({ eexpr = TLocal{ v_name = "__delegate__" } } as local, [del] ) } as e2, _) -> + let e2 = { e2 with etype = e.etype } in + let replace_delegate ex = + { e with eexpr = TCast({ e2 with eexpr = TCall(local, [ex]) }, None) } + in + (* found a delegate; let's see if it's a closure or not *) + let clean = cleanup_delegate del in + (match clean.eexpr with + | TField( ef, (FClosure _ as f)) | TField( ef, (FStatic _ as f)) -> + (* a closure; let's leave this unchanged for FilterClosures to handle it *) + replace_delegate { clean with eexpr = TField( run ef, f ) } + | TFunction tf -> + (* handle like we'd handle a normal function, but create an unchanged closure field for it *) + let ret = handle_anon_func clean { tf with tf_expr = run tf.tf_expr } !info (Some e.etype) in + replace_delegate ret + | _ -> try + let tf = mk_conversion_fun gen del in + let ret = handle_anon_func del { tf with tf_expr = run tf.tf_expr } !info (Some e.etype) in + replace_delegate ret + with Not_found -> + gen.gcon.error "This delegate construct is unsupported" e.epos; + replace_delegate (run clean)) + + | TCall(({ eexpr = TLocal{ v_name = "__unsafe__" } } as local), [arg]) -> + let old = !info in + info := { !info with in_unsafe = true }; + let arg2 = run arg in + info := old; + { e with eexpr = TCall(local,[arg2]) } + (* parameterized functions handling *) + | TVar(vv, ve) -> (match tparam_anon_decl with + | None -> Type.map_expr run e + | Some tparam_anon_decl -> + (match (vv, ve) with + | ({ v_extra = Some( _ :: _, _) } as v), Some ({ eexpr = TFunction tf } as f) + | ({ v_extra = Some( _ :: _, _) } as v), Some { eexpr = TArrayDecl([{ eexpr = TFunction tf } as f]) | TCall({ eexpr = TLocal { v_name = "__array__" } }, [{ eexpr = TFunction tf } as f]) } -> (* captured transformation *) + ignore(tparam_anon_decl v f { tf with tf_expr = run tf.tf_expr }); + { e with eexpr = TBlock([]) } + | _ -> + Type.map_expr run { e with eexpr = TVar(vv, ve) }) + ) + | TLocal ({ v_extra = Some( _ :: _, _) } as v) + | TArray ({ eexpr = TLocal ({ v_extra = Some( _ :: _, _) } as v) }, _) -> (* captured transformation *) + (match tparam_anon_acc with + | None -> Type.map_expr run e + | Some tparam_anon_acc -> tparam_anon_acc v e) + | TCall( { eexpr = TField(_, FEnum _) }, _ ) -> + Type.map_expr run e + (* if a TClosure is being call immediately, there's no need to convert it to a TClosure *) + | TCall(( { eexpr = TField(ecl,f) } as e1), params) -> + (* check to see if called field is known and if it is a MethNormal (only MethNormal fields can be called directly) *) + (* let name = field_name f in *) + (match field_access_esp gen (gen.greal_type ecl.etype) f with + | FClassField(_,_,_,cf,_,_,_) -> + (match cf.cf_kind with + | Method MethNormal + | Method MethInline -> + { e with eexpr = TCall({ e1 with eexpr = TField(run ecl, f) }, List.map run params) } + | _ -> + match gen.gfollow#run_f e1.etype with + | TFun _ -> + dynamic_func_call { e with eexpr = TCall(run e1, List.map run params) } + | _ -> + let i = ref 0 in + let t = TFun(List.map (fun e -> incr i; "arg" ^ (string_of_int !i), false, e.etype) params, e.etype) in + dynamic_func_call { e with eexpr = TCall( mk_cast t (run e1), List.map run params ) } + ) + (* | FNotFound -> + { e with eexpr = TCall({ e1 with eexpr = TField(run ecl, f) }, List.map run params) } + (* expressions by now may have generated invalid expressions *) *) + | _ -> + match gen.gfollow#run_f e1.etype with + | TFun _ -> + dynamic_func_call { e with eexpr = TCall(run e1, List.map run params) } + | _ -> + let i = ref 0 in + let t = TFun(List.map (fun e -> incr i; "arg" ^ (string_of_int !i), false, e.etype) params, e.etype) in + dynamic_func_call { e with eexpr = TCall( mk_cast t (run e1), List.map run params ) } + ) + | TField(ecl, FClosure (_,cf)) -> + transform_closure e (run ecl) cf.cf_name + | TFunction tf -> + handle_anon_func e { tf with tf_expr = run tf.tf_expr } !info None + | TCall({ eexpr = TConst(TSuper) }, _) -> + Type.map_expr run e + | TCall({ eexpr = TLocal(v) }, args) when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> + Type.map_expr run e + | TCall(tc,params) -> + let i = ref 0 in + let may_cast = match gen.gfollow#run_f tc.etype with + | TFun _ -> fun e -> e + | _ -> + let t = TFun(List.map (fun e -> + incr i; + ("p" ^ (string_of_int !i), false, e.etype) + ) params, e.etype) + in + fun e -> mk_cast t e + in + dynamic_func_call { e with eexpr = TCall(run (may_cast tc), List.map run params) } + | _ -> Type.map_expr run e + in + + (match e.eexpr with + | TFunction(tf) -> Type.map_expr run e + | _ -> run e) + + let rec get_type_params acc t = + match t with + | TInst(( { cl_kind = KTypeParameter _ } as cl), []) -> + if List.memq cl acc then acc else cl :: acc + | TFun (params,tret) -> + List.fold_left get_type_params acc ( tret :: List.map (fun (_,_,t) -> t) params ) + | TDynamic t -> + (match t with | TDynamic _ -> acc | _ -> get_type_params acc t) + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + get_type_params acc ( Abstract.get_underlying_type a pl) + | TAnon a -> + PMap.fold (fun cf acc -> + let params = List.map (fun (_,t) -> match follow t with + | TInst(c,_) -> c + | _ -> assert false) cf.cf_params + in + List.filter (fun t -> not (List.memq t params)) (get_type_params acc cf.cf_type) + ) a.a_fields acc + | TType(_, []) + | TAbstract (_, []) + | TInst(_, []) + | TEnum(_, []) -> + acc + | TType(_, params) + | TAbstract(_, params) + | TEnum(_, params) + | TInst(_, params) -> + List.fold_left get_type_params acc params + | TMono r -> (match !r with + | Some t -> get_type_params acc t + | None -> acc) + | _ -> get_type_params acc (follow_once t) + + let get_captured expr = + let ret = Hashtbl.create 1 in + let ignored = Hashtbl.create 0 in + + let params = ref [] in + let check_params t = params := get_type_params !params t in + let rec traverse expr = + match expr.eexpr with + | TFor (v, _, _) -> + Hashtbl.add ignored v.v_id v; + check_params v.v_type; + Type.iter traverse expr + | TFunction(tf) -> + List.iter (fun (v,_) -> Hashtbl.add ignored v.v_id v) tf.tf_args; + (match follow expr.etype with + | TFun(args,ret) -> + List.iter (fun (_,_,t) -> + check_params t + ) args; + check_params ret + | _ -> ()); + Type.iter traverse expr + | TVar (v, opt) -> + (match v.v_extra with + | Some(_ :: _, _) -> () + | _ -> + check_params v.v_type); + Hashtbl.add ignored v.v_id v; + ignore(Option.map traverse opt) + | TLocal { v_extra = Some( (_ :: _ ),_) } -> + () + | TLocal(( { v_capture = true } ) as v) -> + (if not (Hashtbl.mem ignored v.v_id || Hashtbl.mem ret v.v_id) then begin check_params v.v_type; Hashtbl.replace ret v.v_id expr end); + | _ -> Type.iter traverse expr + in traverse expr; + ret, !params + + (* + OPTIMIZEME: + + Take off from Codegen the code that wraps captured variables, + + traverse through all variables, looking for their use (just like local_usage) + three possible outcomes for captured variables: + - become a function member variable <- best performance. + Will not work on functions that can be created more than once (functions inside a loop or functions inside functions) + The function will have to be created on top of the block, so its variables can be filled in instead of being declared + - single-element array - the most compatible way, though also creates a slight overhead. + - we'll have some labels for captured variables: + - used in loop + *) + + (* + The default implementation will impose a naming convention: + invoke(arity)_(o for returning object/d for returning double) when arity < max_arity + invoke_dynamic_(o/d) when arity > max_arity + + This means that it also imposes that the dynamic function return types may only be Dynamic or Float, and all other basic types must be converted to/from it. + *) + + let default_implementation ft parent_func_class (* e.g. new haxe.lang.ClassClosure *) = + let gen = ft.fgen in + ft.initialize_base_class parent_func_class; + let cfs = ft.get_base_classfields_for parent_func_class true (fun () -> []) in + List.iter (fun cf -> + (if cf.cf_name = "new" then parent_func_class.cl_constructor <- Some cf else + parent_func_class.cl_fields <- PMap.add cf.cf_name cf parent_func_class.cl_fields + ) + ) cfs; + + parent_func_class.cl_ordered_fields <- (List.filter (fun cf -> cf.cf_name <> "new") cfs) @ parent_func_class.cl_ordered_fields; + ft.func_class <- parent_func_class; + + let handle_anon_func fexpr tfunc mapinfo delegate_type : texpr * (tclass * texpr list) = + let gen = ft.fgen in + let in_unsafe = mapinfo.in_unsafe || match gen.gcurrent_class, gen.gcurrent_classfield with + | Some c, _ when Meta.has Meta.Unsafe c.cl_meta -> true + | _, Some cf when Meta.has Meta.Unsafe cf.cf_meta -> true + | _ -> false + in + (* get all captured variables it uses *) + let captured_ht, tparams = get_captured fexpr in + let captured = Hashtbl.fold (fun _ e acc -> e :: acc) captured_ht [] in + 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 + in + + (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*) + let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(cl, []) )) tparams in + + (* create a new class that extends abstract function class, with a ctor implementation that will setup all captured variables *) + let cfield = match ft.fgen.gcurrent_classfield with + | None -> "Anon" + | Some cf -> cf.cf_name + in + let cur_line = Lexer.get_error_line fexpr.epos in + let path = (fst ft.fgen.gcurrent_path, Printf.sprintf "%s_%s_%d__Fun" (snd ft.fgen.gcurrent_path) cfield cur_line) in + let cls = mk_class (get ft.fgen.gcurrent_class).cl_module path tfunc.tf_expr.epos in + if in_unsafe then cls.cl_meta <- (Meta.Unsafe,[],Ast.null_pos) :: cls.cl_meta; + + if Common.defined gen.gcon Define.EraseGenerics then begin + cls.cl_meta <- (Meta.HaxeGeneric,[],Ast.null_pos) :: cls.cl_meta + end; + cls.cl_module <- (get ft.fgen.gcurrent_class).cl_module; + cls.cl_params <- cltypes; + + let mk_this v pos = + { + (mk_field_access gen { eexpr = TConst TThis; etype = TInst(cls, List.map snd cls.cl_params); epos = pos } v.v_name pos) + with etype = v.v_type + } + in + + let mk_this_assign v pos = + { + eexpr = TBinop(OpAssign, mk_this v pos, { eexpr = TLocal(v); etype = v.v_type; epos = pos }); + etype = v.v_type; + epos = pos + } in + + (* mk_class_field name t public pos kind params *) + let ctor_args, ctor_sig, ctor_exprs = List.fold_left (fun (ctor_args, ctor_sig, ctor_exprs) lexpr -> + match lexpr.eexpr with + | TLocal(v) -> + let cf = mk_class_field v.v_name v.v_type false lexpr.epos (Var({ v_read = AccNormal; v_write = AccNormal; })) [] in + cls.cl_fields <- PMap.add v.v_name cf cls.cl_fields; + cls.cl_ordered_fields <- cf :: cls.cl_ordered_fields; + + 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 + ) ([],[],[]) captured in + + (* change all captured variables to this.capturedVariable *) + let rec change_captured e = + match e.eexpr with + | TLocal( ({ v_capture = true }) as v ) when Hashtbl.mem captured_ht v.v_id -> + mk_this v e.epos + | _ -> Type.map_expr change_captured e + in + let func_expr = change_captured tfunc.tf_expr in + + let invokecf, invoke_field, super_args = match delegate_type with + | None -> (* no delegate *) + let ifield, sa = ft.closure_to_classfield { tfunc with tf_expr = func_expr } fexpr.etype fexpr.epos in + ifield,ifield,sa + | Some _ -> + let pos = cls.cl_pos in + let cf = mk_class_field "Delegate" (TFun(fun_args tfunc.tf_args, tfunc.tf_type)) true pos (Method MethNormal) [] in + cf.cf_expr <- Some { fexpr with eexpr = TFunction { tfunc with tf_expr = func_expr }; }; + cf.cf_meta <- (Meta.Final,[],pos) :: cf.cf_meta; + cls.cl_ordered_fields <- cf :: cls.cl_ordered_fields; + cls.cl_fields <- PMap.add cf.cf_name cf cls.cl_fields; + (* invoke function body: call Delegate function *) + let ibody = { + eexpr = TCall({ + eexpr = TField({ + eexpr = TConst TThis; + etype = TInst(cls, List.map snd cls.cl_params); + epos = pos; + }, FInstance(cls, List.map snd cls.cl_params, cf)); + etype = cf.cf_type; + epos = pos; + }, List.map (fun (v,_) -> mk_local v pos) tfunc.tf_args); + etype = tfunc.tf_type; + epos = pos + } in + let ibody = if not (is_void tfunc.tf_type) then + { ibody with eexpr = TReturn( Some ibody ) } + else + ibody + in + let ifield, sa = ft.closure_to_classfield { tfunc with tf_expr = ibody } fexpr.etype fexpr.epos in + cf,ifield,sa + in + + (* create the constructor *) + (* todo properly abstract how type var is set *) + + cls.cl_super <- Some(parent_func_class, []); + let pos = cls.cl_pos in + let super_call = + { + eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(parent_func_class,[]); epos = pos }, super_args); + etype = ft.fgen.gcon.basic.tvoid; + epos = pos; + } in + + let ctor_type = (TFun(ctor_sig, ft.fgen.gcon.basic.tvoid)) in + let ctor = mk_class_field "new" ctor_type true cls.cl_pos (Method(MethNormal)) [] in + ctor.cf_expr <- Some( + { + eexpr = TFunction( + { + tf_args = ctor_args; + tf_type = ft.fgen.gcon.basic.tvoid; + tf_expr = { eexpr = TBlock(super_call :: ctor_exprs); etype = ft.fgen.gcon.basic.tvoid; epos = cls.cl_pos } + }); + etype = ctor_type; + epos = cls.cl_pos; + }); + cls.cl_constructor <- Some(ctor); + + (* add invoke function to the class *) + cls.cl_ordered_fields <- invoke_field :: cls.cl_ordered_fields; + cls.cl_fields <- PMap.add invoke_field.cf_name invoke_field cls.cl_fields; + cls.cl_overrides <- invoke_field :: cls.cl_overrides; + + (* add this class to the module with gadd_to_module *) + ft.fgen.gadd_to_module (TClassDecl(cls)) priority; + + (* if there are no captured variables, we can create a cache so subsequent calls don't need to create a new function *) + let expr, clscapt = + match captured, tparams with + | [], [] -> + let cache_var = ft.fgen.gmk_internal_name "hx" "current" in + let cache_cf = mk_class_field cache_var (TInst(cls,[])) false func_expr.epos (Var({ v_read = AccNormal; v_write = AccNormal })) [] in + cls.cl_ordered_statics <- cache_cf :: cls.cl_ordered_statics; + cls.cl_statics <- PMap.add cache_var cache_cf cls.cl_statics; + + (* if (FuncClass.hx_current != null) FuncClass.hx_current; else (FuncClass.hx_current = new FuncClass()); *) + + (* let mk_static_field_access cl field fieldt pos = *) + let hx_current = mk_static_field_access cls cache_var (TInst(cls,[])) func_expr.epos in + + let pos = func_expr.epos in + { fexpr with + eexpr = TIf( + { + eexpr = TBinop(OpNotEq, hx_current, null (TInst(cls,[])) pos); + etype = ft.fgen.gcon.basic.tbool; + epos = pos; + }, + hx_current, + Some( + { + eexpr = TBinop(OpAssign, hx_current, { fexpr with eexpr = TNew(cls, [], captured) }); + etype = (TInst(cls,[])); + epos = pos; + })) + }, (cls,captured) + | _ -> + (* change the expression so it will be a new "added class" ( captured variables arguments ) *) + { fexpr with eexpr = TNew(cls, List.map (fun cl -> TInst(cl,[])) tparams, List.rev captured) }, (cls,captured) + in + match delegate_type with + | None -> + expr,clscapt + | Some _ -> + { + eexpr = TField(expr, FClosure(Some (cls,[]),invokecf)); (* TODO: FClosure change *) + etype = invokecf.cf_type; + epos = cls.cl_pos + }, clscapt + in + + let tvar_to_cdecl = Hashtbl.create 0 in + + traverse + ft.fgen + ~tparam_anon_decl:(fun v e fn -> + let _, info = handle_anon_func e fn null_map_info None in + Hashtbl.add tvar_to_cdecl v.v_id info + ) + ~tparam_anon_acc:(fun v e -> try + let cls, captured = Hashtbl.find tvar_to_cdecl v.v_id in + let types = match v.v_extra with + | Some(t,_) -> t + | _ -> assert false + in + let monos = List.map (fun _ -> mk_mono()) types in + let vt = match follow v.v_type with + | TInst(_, [v]) -> v + | v -> v + in + let et = match follow e.etype with + | TInst(_, [v]) -> v + | v -> v + in + let original = apply_params types monos vt in + unify et original; + + let monos = List.map (fun t -> apply_params types (List.map (fun _ -> t_dynamic) types) t) monos in + + let same_cl t1 t2 = match follow t1, follow t2 with + | TInst(c,_), TInst(c2,_) -> c == c2 + | _ -> false + in + let passoc = List.map2 (fun (_,t) m -> t,m) types monos in + let cltparams = List.map (fun (_,t) -> + try + snd (List.find (fun (t2,_) -> same_cl t t2) passoc) + with | Not_found -> t) cls.cl_params + in + { e with eexpr = TNew(cls, cltparams, captured) } + with + | Not_found -> + gen.gcon.warning "This expression may be invalid" e.epos; + e + | Unify_error el -> + List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) e.epos) el; + gen.gcon.warning "This expression may be invalid" e.epos; + e + ) + (* (transform_closure:texpr->texpr->string->texpr) (handle_anon_func:texpr->tfunc->texpr) (dynamic_func_call:texpr->texpr->texpr list->texpr) *) + ft.transform_closure + (fun e f info delegate_type -> fst (handle_anon_func e f info delegate_type)) + ft.dynamic_fun_call + (* (dynamic_func_call:texpr->texpr->texpr list->texpr) *) + + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map + + let configure_as_synf gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority_as_synf) map + + + (* + this submodule will provide the default implementation for the C# and Java targets. + + it will have two return types: double and dynamic, and + *) + module DoubleAndDynamicClosureImpl = + struct + + let get_ctx gen max_arity = + + let basic = gen.gcon.basic in + + let func_args_i i = + + let rec loop i (acc) = + if i = 0 then (acc) else begin + let vfloat = alloc_var (gen.gmk_internal_name "fn" ("float" ^ string_of_int i)) basic.tfloat in + let vdyn = alloc_var (gen.gmk_internal_name "fn" ("dyn" ^ string_of_int i)) t_dynamic in + + loop (i - 1) ((vfloat, None) :: (vdyn, None) :: acc) + end + in + loop i [] + + in + + let args_real_to_func args = + + let arity = List.length args in + if arity >= max_arity then + [ alloc_var (gen.gmk_internal_name "fn" "dynargs") (basic.tarray t_dynamic), None ] + else func_args_i arity + in + + let func_sig_i i = + + let rec loop i acc = + if i = 0 then acc else begin + let vfloat = gen.gmk_internal_name "fn" ("float" ^ string_of_int i) in + let vdyn = gen.gmk_internal_name "fn" ("dyn" ^ string_of_int i) in + + loop (i - 1) ( (vfloat,false,basic.tfloat) :: (vdyn,false,t_dynamic) :: acc ) + end + in + loop i [] + + in + + let args_real_to_func_sig args = + + let arity = List.length args in + if arity >= max_arity then + [gen.gmk_internal_name "fn" "dynargs", false, basic.tarray t_dynamic] + else begin + func_sig_i arity + end + + in + + let rettype_real_to_func t = match run_follow gen t with + | TType({ t_path = [],"Null" }, _) -> + 0,t_dynamic + | _ when like_float t && not (like_i64 t) -> + (1, basic.tfloat) + | _ -> + (0, t_dynamic) + in + + let args_real_to_func_call el (pos:Ast.pos) = + if List.length el >= max_arity then + [{ eexpr = TArrayDecl el; etype = basic.tarray t_dynamic; epos = pos }] + else begin + List.fold_left (fun acc e -> + if like_float (gen.greal_type e.etype) && not (like_i64 (gen.greal_type e.etype)) then + ( e :: undefined e.epos :: acc ) + else + ( null basic.tfloat e.epos :: e :: acc ) + ) ([]) (List.rev el) + end + in + + let const_type c def = + match c with + | TString _ -> basic.tstring | TInt _ -> basic.tint + | TFloat _ -> basic.tfloat | TBool _ -> basic.tbool + | _ -> def + in + + let get_args_func args changed_args pos = + let arity = List.length args in + let mk_const const elocal t = + match const with + | None -> mk_cast t elocal + | Some const -> + { eexpr = TIf( + { elocal with eexpr = TBinop(Ast.OpEq, elocal, null elocal.etype elocal.epos); etype = basic.tbool }, + { elocal with eexpr = TConst(const); etype = const_type const t }, + Some ( mk_cast t elocal ) + ); etype = t; epos = elocal.epos } + in + + if arity >= max_arity then begin + let varray = match changed_args with | [v,_] -> v | _ -> assert false in + let varray_local = mk_local varray pos in + let mk_varray i = { eexpr = TArray(varray_local, { eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }); etype = t_dynamic; epos = pos } in + + snd (List.fold_left (fun (count,acc) (v,const) -> + (count + 1, + { + eexpr = TVar(v, Some(mk_const const ( mk_varray count ) v.v_type)); + etype = basic.tvoid; + epos = pos; + } :: acc) + ) (0,[]) args) + end else begin + let _, dyn_args, float_args = List.fold_left (fun (count,fargs, dargs) arg -> + if count land 1 = 0 then + (count + 1, fargs, arg :: dargs) + else + (count + 1, arg :: fargs, dargs) + ) (1,[],[]) (List.rev changed_args) in + + let rec loop acc args fargs dargs = + match args, fargs, dargs with + | [], [], [] -> acc + | (v,const) :: args, (vf,_) :: fargs, (vd,_) :: dargs -> + let acc = { eexpr = TVar(v, Some( + { + eexpr = TIf( + { eexpr = TBinop(Ast.OpEq, mk_local vd pos, undefined pos); etype = basic.tbool; epos = pos }, + mk_cast v.v_type (mk_local vf pos), + Some ( mk_const const (mk_local vd pos) v.v_type ) + ); + etype = v.v_type; + epos = pos + } )); etype = basic.tvoid; epos = pos } :: acc in + loop acc args fargs dargs + | _ -> assert false + in + + loop [] args float_args dyn_args + end + in + + let closure_to_classfield tfunc old_sig pos = + (* change function signature *) + let old_args = tfunc.tf_args in + let changed_args = args_real_to_func old_args in + + (* + FIXME properly handle int64 cases, which will break here (because of inference to int) + UPDATE: the fix will be that Int64 won't be a typedef to Float/Int + *) + let changed_sig, arity, type_number, changed_sig_ret, is_void, is_dynamic_func = match follow old_sig with + | TFun(_sig, ret) -> + let type_n, ret_t = rettype_real_to_func ret in + let arity = List.length _sig in + let is_dynamic_func = arity >= max_arity in + 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, is_void ret, is_dynamic_func) + | _ -> (print_endline (s_type (print_context()) (follow old_sig) )); assert false + in + + let tf_expr = if is_void then begin + let rec map e = + match e.eexpr with + | TReturn None -> { e with eexpr = TReturn (Some (null t_dynamic e.epos)) } + | _ -> Type.map_expr map e + in + let e = mk_block (map tfunc.tf_expr) in + match e.eexpr with + | TBlock(bl) -> + { e with eexpr = TBlock(bl @ [{ eexpr = TReturn (Some (null t_dynamic e.epos)); etype = t_dynamic; epos = e.epos }]) } + | _ -> assert false + end else tfunc.tf_expr in + + let changed_sig_ret = if is_dynamic_func then t_dynamic else changed_sig_ret in + + (* get real arguments on top of function body *) + let get_args = get_args_func tfunc.tf_args changed_args pos in + (* + FIXME HACK: in order to be able to run the filters that have already ran for this piece of code, + we will cheat and run it as if it was the whole code + We could just make ClosuresToClass run before TArrayTransform, but we cannot because of the + dependency between ClosuresToClass (after DynamicFieldAccess, and before TArrayTransform) + + maybe a way to solve this would be to add an "until" field to run_from + *) + let real_get_args = gen.gexpr_filters#run_f { eexpr = TBlock(get_args); etype = basic.tvoid; epos = pos } in + + let func_expr = Type.concat real_get_args tf_expr in + + (* set invoke function *) + (* todo properly abstract how naming for invoke is made *) + let invoke_name = if is_dynamic_func then "invokeDynamic" else ("invoke" ^ (string_of_int arity) ^ (if type_number = 0 then "_o" else "_f")) in + let invoke_name = gen.gmk_internal_name "hx" invoke_name in + let invoke_field = mk_class_field invoke_name changed_sig false func_expr.epos (Method(MethNormal)) [] in + let invoke_fun = + { + eexpr = TFunction( + { + tf_args = changed_args; + tf_type = changed_sig_ret; + tf_expr = func_expr; + }); + etype = changed_sig; + epos = func_expr.epos; + } in + invoke_field.cf_expr <- Some(invoke_fun); + + (invoke_field, [ + { eexpr = TConst(TInt( Int32.of_int arity )); etype = gen.gcon.basic.tint; epos = pos }; + { eexpr = TConst(TInt( Int32.of_int type_number )); etype = gen.gcon.basic.tint; epos = pos }; + ]) + in + + let dynamic_fun_call call_expr = + let tc, params = match call_expr.eexpr with + | TCall(tc, params) -> (tc, params) + | _ -> assert false + in + let ct = gen.greal_type call_expr.etype in + let postfix, ret_t = + if like_float ct && not (like_i64 ct) then + "_f", gen.gcon.basic.tfloat + else + "_o", t_dynamic + in + let params_len = List.length params in + let ret_t = if params_len >= max_arity then t_dynamic else ret_t in + + let invoke_fun = if params_len >= max_arity then "invokeDynamic" else "invoke" ^ (string_of_int params_len) ^ postfix in + let invoke_fun = gen.gmk_internal_name "hx" invoke_fun in + let fun_t = match follow tc.etype with + | TFun(_sig, _) -> + TFun(args_real_to_func_sig _sig, ret_t) + | _ -> + let i = ref 0 in + let _sig = List.map (fun p -> let name = "arg" ^ (string_of_int !i) in incr i; (name,false,p.etype) ) params in + TFun(args_real_to_func_sig _sig, ret_t) + in + + let may_cast = match follow call_expr.etype with + | TAbstract ({ a_path = ([], "Void") },[]) -> (fun e -> e) + | _ -> mk_cast call_expr.etype + in + + may_cast + { + eexpr = TCall( + { (mk_field_access gen { tc with etype = gen.greal_type tc.etype } invoke_fun tc.epos) with etype = fun_t }, + args_real_to_func_call params call_expr.epos + ); + etype = ret_t; + epos = call_expr.epos + } + in + + let iname is_function i is_float = + let postfix = if is_float then "_f" else "_o" in + gen.gmk_internal_name "hx" ("invoke" ^ (if not is_function then "Field" else "") ^ string_of_int i) ^ postfix + in + + let map_base_classfields cl is_function map_fn = + + let pos = cl.cl_pos in + let this_t = TInst(cl,List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + + let mk_invoke_i i is_float = + let cf = mk_class_field (iname is_function i is_float) (TFun(func_sig_i i, if is_float then basic.tfloat else t_dynamic)) false pos (Method MethNormal) [] in + cf + in + + let type_name = gen.gmk_internal_name "fn" "type" in + + let dynamic_arg = alloc_var (gen.gmk_internal_name "fn" "dynargs") (basic.tarray t_dynamic) in + + let mk_invoke_complete_i i is_float = + + (* let arity = i in *) + let args = func_args_i i in + + (* api fn *) + + (* only cast if needed *) + let mk_cast tto efrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type efrom.etype) efrom in + let api i t const = + let vf, _ = List.nth args (i * 2) in + let vo, _ = List.nth args (i * 2 + 1) in + + let needs_cast, is_float = match t, like_float t && not (like_i64 t) with + | TAbstract({ a_path = ([], "Float") },[]), _ -> false, true + | _, true -> true, true + | _ -> false,false + in + + let olocal = mk_local vo pos in + let flocal = mk_local vf pos in + + let get_from_obj e = match const with + | None -> mk_cast t e + | Some tc -> + { + eexpr = TIf( + { eexpr = TBinop(Ast.OpEq, olocal, null t_dynamic pos); etype = basic.tbool; epos = pos } , + { eexpr = TConst(tc); etype = t; epos = pos }, + Some (mk_cast t e) + ); + etype = t; + epos = pos; + } + in + + { + eexpr = TIf( + { eexpr = TBinop(Ast.OpEq, olocal, undefined pos); etype = basic.tbool; epos = pos }, + (if needs_cast then mk_cast t flocal else flocal), + Some ( get_from_obj olocal ) + ); + etype = t; + epos = pos + } + in + (* end of api fn *) + + let ret = if is_float then basic.tfloat else t_dynamic in + + let added_args, fn_expr = map_fn i ret (List.map fst args) api in + let args = added_args @ args in + + let t = TFun(fun_args args, ret) in + + let tfunction = + { + eexpr = TFunction({ + tf_args = args; + tf_type = ret; + tf_expr = + mk_block fn_expr + }); + etype = t; + epos = pos; + } + in + + let cf = mk_invoke_i i is_float in + cf.cf_expr <- Some tfunction; + cf + in + + let rec loop i cfs = + if i < 0 then cfs else begin + (*let mk_invoke_complete_i i is_float =*) + (mk_invoke_complete_i i false) :: (mk_invoke_complete_i i true) :: (loop (i-1) cfs) + end + in + + let cfs = loop max_arity [] in + + let added_s_args, switch = + let api i t const = + match i with + | -1 -> + mk_local dynamic_arg pos + | _ -> + mk_cast t { + eexpr = TArray( + mk_local dynamic_arg pos, + { eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }); + etype = t; + epos = pos; + } + in + map_fn (-1) t_dynamic [dynamic_arg] api + in + + let args = added_s_args @ [dynamic_arg, None] in + let dyn_t = TFun(fun_args args, t_dynamic) in + let dyn_cf = mk_class_field (gen.gmk_internal_name "hx" "invokeDynamic") dyn_t false pos (Method MethNormal) [] in + + dyn_cf.cf_expr <- + Some { + eexpr = TFunction({ + tf_args = args; + tf_type = t_dynamic; + tf_expr = mk_block switch + }); + etype = dyn_t; + epos = pos; + }; + + let additional_cfs = if is_function then begin + let new_t = TFun(["arity", false, basic.tint; "type", false, basic.tint],basic.tvoid) in + let new_cf = mk_class_field "new" (new_t) true pos (Method MethNormal) [] in + let v_arity, v_type = alloc_var "arity" basic.tint, alloc_var "type" basic.tint in + let mk_assign v field = { eexpr = TBinop(Ast.OpAssign, mk_this field v.v_type, mk_local v pos); etype = v.v_type; epos = pos } in + + let arity_name = gen.gmk_internal_name "hx" "arity" in + new_cf.cf_expr <- + Some { + eexpr = TFunction({ + tf_args = [v_arity, None; v_type, None]; + tf_type = basic.tvoid; + tf_expr = + { + eexpr = TBlock([ + mk_assign v_type type_name; + mk_assign v_arity arity_name + ]); + etype = basic.tvoid; + epos = pos; + } + }); + etype = new_t; + epos = pos; + } + ; + + [ + new_cf; + mk_class_field type_name basic.tint true pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + mk_class_field arity_name basic.tint true pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + ] + end else [] in + + dyn_cf :: (additional_cfs @ cfs) + in + + (* maybe another param for prefix *) + let get_base_classfields_for cl is_function mk_additional_args = + let pos = cl.cl_pos in + + let this_t = TInst(cl,List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + + let rec mk_dyn_call arity api = + let zero = { eexpr = TConst(TFloat("0.0")); etype = basic.tfloat; epos = pos } in + let rec loop i acc = + if i = 0 then acc else begin + let arr = api (i-1) t_dynamic None in + loop (i - 1) (zero :: arr :: acc) + end + in + loop arity ([]) + in + + let mk_invoke_switch i (api:(int->t->tconstant option->texpr)) = + + let t = TFun(func_sig_i i,t_dynamic) in + + (* case i: return this.invokeX_o(0, 0, 0, 0, 0, ... arg[0], args[1]....); *) + ( [{ eexpr = TConst(TInt(Int32.of_int i)); etype = basic.tint; epos = pos }], + { + eexpr = TReturn(Some( { + eexpr = TCall(mk_this (iname is_function i false) t, mk_dyn_call i api); + etype = t_dynamic; + epos = pos; + } )); + etype = t_dynamic; + epos = pos; + } ) + in + + let cl_t = TInst(cl,List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = cl_t; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + let mk_int i = { eexpr = TConst(TInt ( Int32.of_int i)); etype = basic.tint; epos = pos } in + let mk_string s = { eexpr = TConst(TString s); etype = basic.tstring; epos = pos } in + + (* + if it is the Function class, the base class fields will be + * hx::invokeX_d|o (where X is from 0 to max_arity) (args) + { + if (this.type == 0|1) return invokeX_o|d(args); else throw "Invalid number of arguments." + } + + hx::invokeDynamic, which will work in the same way + + new(arity, type) + { + if (type != 0 && type != 1) throw "Invalid type"; + this.arity = arity; + this.type = type; + } + *) + let type_name = gen.gmk_internal_name "fn" "type" in + + let mk_expr i is_float vars = + + let name = if is_function then "invoke" else "invokeField" in + + let look_ahead = alloc_var "lookAhead" basic.tbool in + let add_args = if not is_function then mk_additional_args() else [] in + let vars = if not is_function then (List.map fst add_args) @ (look_ahead :: vars) else vars in + + let call_expr = + + let call_t = TFun(List.map (fun v -> (v.v_name, false, v.v_type)) vars, if is_float then t_dynamic else basic.tfloat) in + { + eexpr = TCall(mk_this (gen.gmk_internal_name "hx" (name ^ (string_of_int i) ^ (if is_float then "_o" else "_f"))) call_t, List.map (fun v -> if v.v_id = look_ahead.v_id then ( { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } ) else mk_local v pos) vars ); + etype = if is_float then t_dynamic else basic.tfloat; + epos = pos + } + in + (*let call_expr = if is_float then mk_cast basic.tfloat call_expr else call_expr in*) + + let if_cond = if is_function then + { eexpr=TBinop(Ast.OpNotEq, mk_this type_name basic.tint, mk_int (if is_float then 0 else 1) ); etype = basic.tbool; epos = pos } + else + mk_local look_ahead pos + in + + let if_expr = if is_function then + { + eexpr = TIf(if_cond, + { eexpr = TThrow(mk_string "Wrong number of arguments"); etype = basic.tstring; epos = pos }, + Some( { eexpr = TReturn( Some( call_expr ) ); etype = call_expr.etype; epos = pos } ) + ); + etype = t_dynamic; + epos = pos; + } + else + { + eexpr = TIf(if_cond, + { eexpr = TReturn( Some( call_expr ) ); etype = call_expr.etype; epos = pos }, + Some( { eexpr = TThrow(mk_string "Field not found or wrong number of arguments"); etype = basic.tstring; epos = pos } ) + ); + etype = t_dynamic; + epos = pos; + } + in + + let args = if not is_function then (mk_additional_args()) @ [look_ahead, None] else [] in + (args, if_expr) + in + + let arities_processed = Hashtbl.create 10 in + let max_arity = ref 0 in + + let rec loop_cases api arity acc = + if arity < 0 then acc else + loop_cases api (arity - 1) (mk_invoke_switch arity api :: acc) + in + (* let rec loop goes here *) + let map_fn cur_arity fun_ret_type vars (api:(int->t->tconstant option->texpr)) = + let is_float = like_float fun_ret_type && not (like_i64 fun_ret_type) in + match cur_arity with + | -1 -> + let dynargs = api (-1) (t_dynamic) None in + let switch_cond = mk_field_access gen dynargs "length" pos in + let switch_cond = { + eexpr = TIf( + { eexpr = TBinop(Ast.OpEq, dynargs, null dynargs.etype pos); etype = basic.tbool; epos = pos; }, + { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }, + Some switch_cond); + etype = basic.tint; + epos = pos; + } in + + let switch = + { + eexpr = TSwitch( switch_cond, + loop_cases api !max_arity [], + Some({ eexpr = TThrow(mk_string "Too many arguments"); etype = basic.tvoid; epos = pos; }) ); + etype = basic.tvoid; + epos = pos; + } in + + ( (if not is_function then mk_additional_args () else []), switch ) + | _ -> + if not (Hashtbl.mem arities_processed cur_arity) then begin + Hashtbl.add arities_processed cur_arity true; + if cur_arity > !max_arity then max_arity := cur_arity + end; + + mk_expr cur_arity is_float vars + in + + map_base_classfields cl is_function map_fn + in + + let initialize_base_class cl = + () + in + + { + fgen = gen; + + func_class = null_class; + + closure_to_classfield = closure_to_classfield; + + dynamic_fun_call = dynamic_fun_call; + + (* + called once so the implementation can make one of a time initializations in the base class + for all functions + *) + initialize_base_class = initialize_base_class; + + (* + Base classfields are the class fields for the abstract implementation of either the Function implementation, + or the invokeField implementation for the classes + They will either try to call the right function or will fail with + + (tclass - subject (so we know the type of this)) -> is_function_base -> list of the abstract implementation class fields + *) + get_base_classfields_for = get_base_classfields_for; + + map_base_classfields = map_base_classfields; + + (* + for now we won't deal with the closures. + They can be dealt with the module ReflectionCFs, + or a custom implementation + *) + transform_closure = (fun tclosure texpr str -> tclosure); + + } + + end;; end;; @@ -3680,765 +4114,954 @@ end;; (* - This module will handle type parameters. There are lots of changes we need to do to correctly support type parameters: + This module will handle type parameters. There are lots of changes we need to do to correctly support type parameters: - traverse will: - V Detect when parameterized function calls are made - * Detect when a parameterized class instance is being cast to another parameter - * Change new<> parameterized function calls - * + traverse will: + V Detect when parameterized function calls are made + * Detect when a parameterized class instance is being cast to another parameter + * Change new<> parameterized function calls + * - extras: - * On languages that support "real" type parameters, a Cast function is provided that will convert from a to the requested type. - This cast will call createEmpty with the correct type, and then set each variable to the new form. Some types will be handled specially, namely the Native Array. - Other implementations may be delegated to the runtime. - * parameterized classes will implement a new interface (with only a Cast<> function added to it), so we can access the type parameter for them. Also any reference to will be replaced by a reference to this interface. (also on TTypeExpr - Std.is()) - * Type parameter renaming to avoid name clash - * Detect type parameter casting and call Cast<> instead + extras: + * On languages that support "real" type parameters, a Cast function is provided that will convert from a to the requested type. + This cast will call createEmpty with the correct type, and then set each variable to the new form. Some types will be handled specially, namely the Native Array. + Other implementations may be delegated to the runtime. + * parameterized classes will implement a new interface (with only a Cast<> function added to it), so we can access the type parameter for them. Also any reference to will be replaced by a reference to this interface. (also on TTypeExpr - Std.is()) + * Type parameter renaming to avoid name clash + * Detect type parameter casting and call Cast<> instead - for java: - * for specially assigned classes, parameters will be replaced by _d and _i versions of parameterized functions. This will only work for parameterized classes, not functions. + for java: + * for specially assigned classes, parameters will be replaced by _d and _i versions of parameterized functions. This will only work for parameterized classes, not functions. - dependencies: - must run after casts are detected. This will be ensured at CastDetect module. + dependencies: + must run after casts are detected. This will be ensured at CastDetect module. *) module TypeParams = struct - let name = "type_params" - - let priority = max_dep -. 20. - - (* this function will receive the original function argument, the applied function argument and the original function parameters. *) - (* from this info, it will infer the applied tparams for the function *) - (* this function is used by CastDetection module *) - let infer_params gen pos (original_args:((string * bool * t) list * t)) (applied_args:((string * bool * t) list * t)) (params:(string * t) list) calls_parameters_explicitly : tparams = - match params with - | [] -> [] - | _ -> - let args_list args = (if not calls_parameters_explicitly then t_dynamic else snd args) :: (List.map (fun (n,o,t) -> t) (fst args)) in - - let monos = List.map (fun _ -> mk_mono()) params in - let original = args_list (get_fun (apply_params params monos (TFun(fst original_args,snd original_args)))) in - let applied = args_list applied_args in - - (try - List.iter2 (fun a o -> - unify a o - (* type_eq EqStrict a o *) - ) applied original - (* unify applied original *) - with | Unify_error el -> - (* List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) pos) el; *) - gen.gcon.warning ("This expression may be invalid") pos - | Invalid_argument("List.map2") -> - gen.gcon.warning ("This expression may be invalid") pos - ); - - List.map (fun t -> - match follow t with - | TMono _ -> t_empty - | t -> t - ) monos - - (* ******************************************* *) - (* Real Type Parameters Module *) - (* ******************************************* *) - - (* - This submodule is by now specially made for the .NET platform. There might be other targets that will - make use of this, but it IS very specific. - - On the .NET platform, generics are real specialized classes that are JIT compiled. For this reason, we cannot - cast from one type parameter to another. Also there is no common type for the type parameters, so for example - an instance of type Array will return false for instance is Array . - - So we need to: - 1. create a common interface (without type parameters) (e.g. "Array") which will only contain a __Cast<> function, which will cast from one type into another - 2. Implement the __Cast function. This part is a little hard, as we must identify all type parameter-dependent fields contained in the class and convert them. - In most cases the conversion will just be to call .__Cast<>() on the instances, or just a simple cast. But when the instance is a @:nativegen type, there will be no .__Cast - function, and we will need to deal with this case either at compile-time (added handlers - specially for NativeArray), or at runtime (adding new runtime handlers) - 3. traverse the AST looking for casts involving type parameters, and replace them with .__Cast<>() calls. If type is @:nativegen, throw a warning. If really casting from one type parameter to another on a @:nativegen context, throw an error. - - - special literals: - it will use the special literal __typehandle__ that the target must implement in order to run this. This literal is a way to get the typehandle of e.g. the type parameters, - so we can compare them. In C# it's the equivalent of typeof(T).TypeHandle (TypeHandle compare is faster than System.Type.Equals()) - - dependencies: - (module filter) Interface creation must run AFTER enums are converted into classes, otherwise there is no way to tell parameterized enums to implement an interface - Must run AFTER CastDetect. This will be ensured per CastDetect - - *) - - module RealTypeParams = - struct - - let name = "real_type_params" - - let priority = priority - - let cast_field_name = "cast" - - let rec has_type_params t = - match follow t with - | TInst( { cl_kind = KTypeParameter _ }, _) -> true - | TAbstract(_, params) - | TEnum(_, params) - | TInst(_, params) -> List.fold_left (fun acc t -> acc || has_type_params t) false params - | _ -> false - - let is_hxgeneric = function - | TClassDecl(cl) -> - not (Meta.has Meta.NativeGeneric cl.cl_meta) - | TEnumDecl(e) -> - not (Meta.has Meta.NativeGeneric e.e_meta) - | TTypeDecl(t) -> - not (Meta.has Meta.NativeGeneric t.t_meta) - | TAbstractDecl a -> - not (Meta.has Meta.NativeGeneric a.a_meta) - - let rec set_hxgeneric gen mds isfirst md = - let path = t_path md in - if List.exists (fun m -> path = t_path m) mds then begin - if isfirst then - None (* we still can't determine *) - else - Some true (* if we're in second pass and still can't determine, it's because it can be hxgeneric *) - end else begin - let has_unresolved = ref false in - let is_false v = - match v with - | Some false -> true - | None -> has_unresolved := true; false - | Some true -> false - in - - let mds = md :: mds in - match md with - | TClassDecl(cl) -> - (* first see if any meta is present (already processed) *) - if Meta.has Meta.NativeGeneric cl.cl_meta then - Some false - else if Meta.has Meta.HaxeGeneric cl.cl_meta then - Some true - else if not (is_hxgen md) then - (cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; - Some false) - else begin - (* - if it's not present, see if any superclass is nativegeneric. - nativegeneric is inherited, while hxgeneric can be later changed to nativegeneric - *) - (* on the first pass, our job is to find any evidence that makes it not be hxgeneric. Otherwise it will be hxgeneric *) - match cl.cl_super with - | Some (c,_) when is_false (set_hxgeneric gen mds isfirst (TClassDecl c)) -> - cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; - Some false - | _ -> - (* see if it's a generic class *) - match cl.cl_types with - | [] -> - (* if it's not, then it will be hxgeneric *) - cl.cl_meta <- (Meta.HaxeGeneric, [], cl.cl_pos) :: cl.cl_meta; - Some true - | _ -> - (* if it is, loop through all fields + statics and look for non-hxgeneric - generic classes that have KTypeParameter as params *) - let rec loop cfs = - match cfs with - | [] -> false - | cf :: cfs -> - let t = follow (gen.greal_type cf.cf_type) in - match t with - | TInst( { cl_kind = KTypeParameter _ }, _ ) -> loop cfs - | TInst(cl,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TClassDecl cl)) -> - if not (Hashtbl.mem gen.gtparam_cast cl.cl_path) then true else loop cfs - | TEnum(e,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TEnumDecl e)) -> - if not (Hashtbl.mem gen.gtparam_cast e.e_path) then true else loop cfs - | _ -> loop cfs (* TAbstracts / Dynamics can't be generic *) - in - if loop cl.cl_ordered_fields then begin - cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; - Some false - end else if isfirst && !has_unresolved then - None - else begin - cl.cl_meta <- (Meta.HaxeGeneric, [], cl.cl_pos) :: cl.cl_meta; - Some true - end - end - | TEnumDecl e -> - if Meta.has Meta.NativeGeneric e.e_meta then - Some false - else if Meta.has Meta.HaxeGeneric e.e_meta then - Some true - else if not (is_hxgen (TEnumDecl e)) then begin - e.e_meta <- (Meta.NativeGeneric, [], e.e_pos) :: e.e_meta; - Some false - end else begin - (* if enum is not generic, then it's hxgeneric *) - match e.e_types with - | [] -> - e.e_meta <- (Meta.HaxeGeneric, [], e.e_pos) :: e.e_meta; - Some true - | _ -> - let rec loop efs = - match efs with - | [] -> false - | ef :: efs -> - let t = follow (gen.greal_type ef.ef_type) in - match t with - | TFun(args, _) -> - if List.exists (fun (n,o,t) -> - let t = follow t in - match t with - | TInst( { cl_kind = KTypeParameter _ }, _ ) -> - false - | TInst(cl,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TClassDecl cl)) -> - not (Hashtbl.mem gen.gtparam_cast cl.cl_path) - | TEnum(e,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TEnumDecl e)) -> - not (Hashtbl.mem gen.gtparam_cast e.e_path) - | _ -> false - ) args then - true - else - loop efs - | _ -> loop efs - in - let efs = PMap.fold (fun ef acc -> ef :: acc) e.e_constrs [] in - if loop efs then begin - e.e_meta <- (Meta.NativeGeneric, [], e.e_pos) :: e.e_meta; - Some false - end else if isfirst && !has_unresolved then - None - else begin - e.e_meta <- (Meta.HaxeGeneric, [], e.e_pos) :: e.e_meta; - Some true - end - end - | _ -> assert false - end - - let set_hxgeneric gen md = - match set_hxgeneric gen [] true md with - | None -> - get (set_hxgeneric gen [] false md) - | Some v -> v - - let params_has_tparams params = - List.fold_left (fun acc t -> acc || has_type_params t) false params - - (* ******************************************* *) - (* RealTypeParamsModf *) - (* ******************************************* *) - - (* - - This is the module filter of Real Type Parameters. It will traverse through all types and look for hxgeneric classes (only classes). - When found, a parameterless interface will be created and associated via the "ifaces" Hashtbl to the original class. - Also a "cast" function will be automatically generated which will handle unsafe downcasts to more specific type parameters (necessary for serialization) - - dependencies: - Anything that may create hxgeneric classes must run before it. - Should run before ReflectionCFs (this dependency will be added to ReflectionCFs), so the added interfaces also get to be real IHxObject's - - *) - - module RealTypeParamsModf = - struct - - let name = "real_type_params_modf" - - let priority = solve_deps name [] - - let rec get_fields gen cl params_cl params_cf acc = - let fields = List.fold_left (fun acc cf -> - match follow (gen.greal_type (gen.gfollow#run_f (cf.cf_type))) with - | TInst(cli, ((_ :: _) as p)) when (not (is_hxgeneric (TClassDecl cli))) && params_has_tparams p -> - (cf, apply_params cl.cl_types params_cl cf.cf_type, apply_params cl.cl_types params_cf cf.cf_type) :: acc - | TEnum(e, ((_ :: _) as p)) when not (is_hxgeneric (TEnumDecl e)) && params_has_tparams p -> - (cf, apply_params cl.cl_types params_cl cf.cf_type, apply_params cl.cl_types params_cf cf.cf_type) :: acc - | _ -> acc - ) [] cl.cl_ordered_fields in - match cl.cl_super with - | Some(cs, tls) -> - get_fields gen cs (List.map (apply_params cl.cl_types params_cl) tls) (List.map (apply_params cl.cl_types params_cf) tls) (fields @ acc) - | None -> (fields @ acc) - - (* overrides all needed cast functions from super classes / interfaces to call the new cast function *) - let create_stub_casts gen cl cast_cfield = - (* go through superclasses and interfaces *) - let p = cl.cl_pos in - let this = { eexpr = TConst TThis; etype = (TInst(cl, List.map snd cl.cl_types)); epos = p } in - - let rec loop cls tls level reverse_params = - if (level <> 0 || cls.cl_interface) && tls <> [] && is_hxgeneric (TClassDecl cls) then begin - let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) cls.cl_types in - let name = String.concat "_" ((fst cls.cl_path) @ [snd cls.cl_path; cast_field_name]) in - if not (PMap.mem name cl.cl_fields) then begin - let reverse_params = List.map (apply_params cls.cl_types (List.map snd cparams)) reverse_params in - let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in - let field = { eexpr = TField(this, FInstance(cl,cast_cfield)); etype = apply_params cast_cfield.cf_params reverse_params cast_cfield.cf_type; epos = p } in - let call = - { - eexpr = TCall(field, []); - etype = t_dynamic; - epos = p; - } in - let call = gen.gparam_func_call call field reverse_params [] in - let delay () = - cfield.cf_expr <- - Some { - eexpr = TFunction( - { - tf_args = []; - tf_type = t_dynamic; - tf_expr = - { - eexpr = TReturn( Some call ); - etype = t_dynamic; - epos = p; - } - }); - etype = cfield.cf_type; - epos = p; - } - in - gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended; (* do not let filters alter this expression content *) - cl.cl_ordered_fields <- cfield :: cl.cl_ordered_fields; - cl.cl_fields <- PMap.add cfield.cf_name cfield cl.cl_fields; - if level <> 0 then cl.cl_overrides <- cfield :: cl.cl_overrides - end - end; - let get_reverse super supertl = - let kv = List.map2 (fun (_,tparam) applied -> (follow applied, follow tparam)) super.cl_types supertl in - List.map (fun t -> - try - List.assq (follow t) kv - with | Not_found -> t - ) reverse_params - in - (match cls.cl_super with - | None -> () - | Some(super, supertl) -> - loop super supertl (level + 1) (get_reverse super supertl)); - List.iter (fun (iface, ifacetl) -> - loop iface ifacetl level (get_reverse iface ifacetl) - ) cls.cl_implements - in - loop cl (List.map snd cl.cl_types) 0 (List.map snd cl.cl_types) - - (* - Creates a cast classfield, with the desired name - - Will also look for previous cast() definitions and override them, to reflect the current type and fields - - FIXME: this function still doesn't support generics that extend generics, and are cast as one of its subclasses. This needs to be taken care, by - looking at previous superclasses and whenever a generic class is found, its cast argument must be overriden. the toughest part is to know how to type - the current type correctly. - *) - let create_cast_cfield gen cl name = - let basic = gen.gcon.basic in - let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) cl.cl_types in - let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in - let params = List.map snd cparams in - - let fields = get_fields gen cl (List.map snd cl.cl_types) params [] in - - (* now create the contents of the function *) - (* - it will look something like: - if (typeof(T) == typeof(T2)) return this; - - var new_me = new CurrentClass(EmptyInstnace); - - for (field in Reflect.fields(this)) - { - switch(field) - { - case "aNativeArray": - var newArray = new NativeArray(this.aNativeArray.Length); - - default: - Reflect.setField(new_me, field, Reflect.field(this, field)); - } - } - *) - - let new_t = TInst(cl, params) in - let pos = cl.cl_pos in - - let new_me_var = alloc_var "new_me" new_t in - let local_new_me = { eexpr = TLocal(new_me_var); etype = new_t; epos = pos } in - let this = { eexpr = TConst(TThis); etype = (TInst(cl, List.map snd cl.cl_types)); epos = pos } in - let field_var = alloc_var "field" gen.gcon.basic.tstring in - let local_field = { eexpr = TLocal(field_var); etype = field_var.v_type; epos = pos } in - - let get_path t = - match follow t with - | TInst(cl,_) -> cl.cl_path - | TEnum(e,_) -> e.e_path - | TAbstract(a,_) -> a.a_path - | TMono _ - | TDynamic _ -> ([], "Dynamic") - | _ -> assert false - in - - (* this will take all fields that were *) - let fields_to_cases fields = - List.map (fun (cf, t_cl, t_cf) -> - let this_field = { eexpr = TField(this, FInstance(cl, cf)); etype = t_cl; epos = pos } in - let expr = - { - eexpr = TBinop(OpAssign, { eexpr = TField(local_new_me, FInstance(cl, cf) ); etype = t_cf; epos = pos }, - 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 *) assert false - ); - etype = t_cf; - epos = pos; - } in - - ([{ eexpr = TConst(TString(cf.cf_name)); etype = gen.gcon.basic.tstring; epos = pos }], expr) - ) fields - in - - let mk_typehandle = - let thandle = alloc_var "__typeof__" t_dynamic in - (fun cl -> { eexpr = TCall(mk_local thandle pos, [ mk_classtype_access cl pos ]); etype = t_dynamic; epos = pos }) - in - let mk_eq cl1 cl2 = - { eexpr = TBinop(Ast.OpEq, mk_typehandle cl1, mk_typehandle cl2); etype = basic.tbool; epos = pos } - in - - let rec mk_typehandle_cond thisparams cfparams = - match thisparams, cfparams with - | TInst(cl_this,[]) :: [], TInst(cl_cf,[]) :: [] -> - mk_eq cl_this cl_cf - | TInst(cl_this,[]) :: hd, TInst(cl_cf,[]) :: hd2 -> - { eexpr = TBinop(Ast.OpBoolAnd, mk_eq cl_this cl_cf, mk_typehandle_cond hd hd2); etype = basic.tbool; epos = pos } - | v :: hd, v2 :: hd2 -> - (match follow v, follow v2 with - | (TInst(cl1,[]) as v), (TInst(cl2,[]) as v2) -> - mk_typehandle_cond (v :: hd) (v2 :: hd2) - | _ -> - assert false - ) - | _ -> assert false - in - - let ref_fields = gen.gtools.r_fields true this in - let fn = - { - tf_args = []; - tf_type = t_dynamic; - tf_expr = - { - eexpr = TBlock([ - (* if (typeof(T) == typeof(T2)) return this *) - { - eexpr = TIf( - mk_typehandle_cond (List.map snd cl.cl_types) params, - mk_return this, - None); - etype = basic.tvoid; - epos = pos; - }; - (* var new_me = /*special create empty with tparams construct*/ *) - { eexpr = TVars([new_me_var, Some( - gen.gtools.rf_create_empty cl params pos - )]); etype = gen.gcon.basic.tvoid; epos = pos }; - { eexpr = TFor( (* for (field in Reflect.fields(this)) *) - field_var, - mk_iterator_access gen gen.gcon.basic.tstring ref_fields, - (* { *) - (* switch(field) *) - { - eexpr = TSwitch(local_field, fields_to_cases fields, Some( - (* default: Reflect.setField(new_me, field, Reflect.field(this, field)) *) - gen.gtools.r_set_field (gen.gcon.basic.tvoid) local_new_me local_field (gen.gtools.r_field false t_dynamic this local_field) - )); - etype = t_dynamic; - epos = pos; - } - (* } *) - ); etype = t_dynamic; epos = pos }; - (* return new_me *) - mk_return (mk_local new_me_var pos) - ]); - etype = t_dynamic; - epos = pos; - }; - } - in - - cfield.cf_expr <- Some( { eexpr = TFunction(fn); etype = cfield.cf_type; epos = pos } ); - - cfield - - let create_static_cast_cf gen iface cf = - let p = iface.cl_pos in - let basic = gen.gcon.basic in - let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst (map_param (get_cl_t t), []))) cf.cf_params in - let me_type = TInst(iface,[]) in - let cfield = mk_class_field "__hx_cast" (TFun(["me",false,me_type], t_dynamic)) false iface.cl_pos (Method MethNormal) (cparams) in - let params = List.map snd cparams in - - let me = alloc_var "me" me_type in - let field = { eexpr = TField(mk_local me p, FInstance(iface,cf)); etype = apply_params cf.cf_params params cf.cf_type; epos = p } in - let call = - { - eexpr = TCall(field, []); - etype = t_dynamic; - epos = p; - } in - let call = gen.gparam_func_call call field params [] in - - (* since object.someCall() isn't allowed on Haxe, we need to directly apply the params and delay this call *) - let delay () = - cfield.cf_expr <- - Some { - eexpr = TFunction( - { - tf_args = [me,None]; - tf_type = t_dynamic; - tf_expr = - { - eexpr = TReturn( Some - { - eexpr = TIf( - { eexpr = TBinop(Ast.OpNotEq, mk_local me p, null me.v_type p); etype = basic.tbool; epos = p }, - call, - Some( null me.v_type p ) - ); - etype = t_dynamic; - epos = p; - }); - etype = basic.tvoid; - epos = p; - } - }); - etype = cfield.cf_type; - epos = p; - } - in - cfield, delay - - let get_cast_name cl = String.concat "_" ((fst cl.cl_path) @ [snd cl.cl_path; cast_field_name]) (* explicitly define it *) - - let default_implementation gen ifaces base_generic = - let add_iface cl = - gen.gadd_to_module (TClassDecl cl) (max_dep); - in - - let implement_stub_cast cthis iface tl = - let name = get_cast_name iface in - if not (PMap.mem name cthis.cl_fields) then begin - let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst(map_param (get_cl_t t), []))) iface.cl_types in - let field = mk_class_field name (TFun([],t_dynamic)) false iface.cl_pos (Method MethNormal) cparams in - let this = { eexpr = TConst TThis; etype = TInst(cthis, List.map snd cthis.cl_types); epos = cthis.cl_pos } in - field.cf_expr <- Some { - etype = TFun([],t_dynamic); - epos = this.epos; - eexpr = TFunction { - tf_type = t_dynamic; - tf_args = []; - tf_expr = mk_block { this with - eexpr = TReturn (Some this) - } - } - }; - cthis.cl_ordered_fields <- field :: cthis.cl_ordered_fields; - cthis.cl_fields <- PMap.add name field cthis.cl_fields - end - in - - let rec run md = - match md with - | TClassDecl ({ cl_extern = false; cl_types = [] } as cl) -> - (* see if we're implementing any generic interface *) - let rec check (iface,tl) = - if tl <> [] && set_hxgeneric gen (TClassDecl iface) then - (* implement cast stub *) - implement_stub_cast cl iface tl; - List.iter (fun (s,stl) -> check (s, List.map (apply_params iface.cl_types tl) stl)) iface.cl_implements; - in - List.iter (check) cl.cl_implements; - md - | TClassDecl ({ cl_extern = false; cl_types = hd :: tl } as cl) when set_hxgeneric gen md -> - let iface = mk_class cl.cl_module cl.cl_path cl.cl_pos in - iface.cl_array_access <- Option.map (apply_params (cl.cl_types) (List.map (fun _ -> t_dynamic) cl.cl_types)) cl.cl_array_access; - iface.cl_module <- cl.cl_module; - iface.cl_meta <- (Meta.HxGen, [], cl.cl_pos) :: iface.cl_meta; - Hashtbl.add ifaces cl.cl_path iface; - - iface.cl_implements <- (base_generic, []) :: iface.cl_implements; - iface.cl_interface <- true; - cl.cl_implements <- (iface, []) :: cl.cl_implements; - - let name = get_cast_name cl in - let cast_cf = create_cast_cfield gen cl name in - if not cl.cl_interface then create_stub_casts gen cl cast_cf; - - let rec loop c = match c.cl_super with - | None -> () - | Some(sup,_) -> try - let siface = Hashtbl.find ifaces sup.cl_path in - iface.cl_implements <- (siface,[]) :: iface.cl_implements; - () - with | Not_found -> loop sup - in - loop cl; - - (if not cl.cl_interface then cl.cl_ordered_fields <- cast_cf :: cl.cl_ordered_fields); - let iface_cf = mk_class_field name cast_cf.cf_type false cast_cf.cf_pos (Method MethNormal) cast_cf.cf_params in - let cast_static_cf, delay = create_static_cast_cf gen iface iface_cf in - - cl.cl_ordered_statics <- cast_static_cf :: cl.cl_ordered_statics; - cl.cl_statics <- PMap.add cast_static_cf.cf_name cast_static_cf cl.cl_statics; - gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended; (* do not let filters alter this expression content *) - - iface_cf.cf_type <- cast_cf.cf_type; - iface.cl_fields <- PMap.add name iface_cf iface.cl_fields; - iface.cl_ordered_fields <- [iface_cf]; - - add_iface iface; - md - | TTypeDecl _ | TAbstractDecl _ -> md - | TEnumDecl _ -> - ignore (set_hxgeneric gen md); - md - | _ -> ignore (set_hxgeneric gen md); md - in - run - - let configure gen mapping_func = - let map e = Some(mapping_func e) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map - - end;; - - (* create a common interface without type parameters and only a __Cast<> function *) - let default_implementation gen (dyn_tparam_cast:texpr->t->texpr) ifaces = - let change_expr e cl iface params = - let field = mk_static_field_access_infer cl "__hx_cast" e.epos params in - let elist = [mk_cast (TInst(iface,[])) e] in - let call = { eexpr = TCall(field, elist); etype = t_dynamic; epos = e.epos } in - - gen.gparam_func_call call field params elist - in - - let rec run e = - match e.eexpr with - | TCast(cast_expr, _) -> - (* see if casting to a native generic class *) - let t = follow (gen.greal_type e.etype) in - (match t with - | TInst(cl, p1 :: pl) when is_hxgeneric (TClassDecl cl) -> - let iface = Hashtbl.find ifaces cl.cl_path in - mk_cast e.etype (change_expr (Type.map_expr run cast_expr) cl iface (p1 :: pl)) - | _ -> Type.map_expr run e - ) - | _ -> Type.map_expr run e - in - run - - let configure gen traverse = - gen.ghas_tparam_cast_handler <- true; - let map e = Some(traverse e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map - - let default_config gen (dyn_tparam_cast:texpr->t->texpr) ifaces base_generic = - configure gen (default_implementation gen dyn_tparam_cast ifaces); - RealTypeParamsModf.configure gen (RealTypeParamsModf.default_implementation gen ifaces base_generic) - - end;; - - (* ******************************************* *) - (* Rename Type Parameters *) - (* ******************************************* *) - - (* - - This module should run after everything is already applied, - it will look for possible type parameter name clashing and change the classes names to a - - dependencies: - should run after everything is already applied. There's no configure on this module, only 'run'. - - *) - - module RenameTypeParameters = - struct - - let name = "rename_type_parameters" - - let run gen = - let i = ref 0 in - let found_types = ref PMap.empty in - let check_type name on_changed = - let rec loop name = - incr i; - let changed_name = (name ^ (string_of_int !i)) in - if PMap.mem changed_name !found_types then loop name else changed_name - in - if PMap.mem name !found_types then begin - let new_name = loop name in - found_types := PMap.add new_name true !found_types; - on_changed new_name - end else found_types := PMap.add name true !found_types - in - - let get_cls t = - match follow t with - | TInst(cl,_) -> cl - | _ -> assert false - in - - let iter_types (_,t) = - let cls = get_cls t in - check_type (snd cls.cl_path) (fun name -> cls.cl_path <- (fst cls.cl_path, name)) - in - - List.iter (function - | TClassDecl cl -> - i := 0; - - found_types := PMap.empty; - List.iter iter_types cl.cl_types; - let cur_found_types = !found_types in - List.iter (fun cf -> - found_types := cur_found_types; - List.iter iter_types cf.cf_params - ) (cl.cl_ordered_fields @ cl.cl_ordered_statics) - - | TEnumDecl ( ({ e_types = hd :: tl }) ) -> - i := 0; - found_types := PMap.empty; - List.iter iter_types (hd :: tl) - - | TAbstractDecl { a_types = hd :: tl } -> - i := 0; - found_types := PMap.empty; - List.iter iter_types (hd :: tl) - - | _ -> () - - ) gen.gcon.types - - end;; - - - let configure gen (param_func_call:texpr->texpr->tparams->texpr list->texpr) = - (*let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map*) - gen.gparam_func_call <- param_func_call + let name = "type_params" + + let priority = max_dep -. 20. + + let rec deep_follow gen t = match run_follow gen t with + | TInst(c,tl) -> + TInst(c,List.map (deep_follow gen) tl) + | TEnum(e,tl) -> + TEnum(e,List.map (deep_follow gen) tl) + | TAbstract(a,tl) -> + TAbstract(a,List.map (deep_follow gen) tl) + | TType(t,tl) -> + TType(t,List.map (deep_follow gen) tl) + | TFun(args,ret) -> + TFun(List.map (fun (n,o,t) -> n,o,deep_follow gen t) args, deep_follow gen ret) + | t -> t + + (* this function will receive the original function argument, the applied function argument and the original function parameters. *) + (* from this info, it will infer the applied tparams for the function *) + (* this function is used by CastDetection module *) + let infer_params gen pos (original_args:((string * bool * t) list * t)) (applied_args:((string * bool * t) list * t)) (params:(string * t) list) calls_parameters_explicitly : tparams = + match params with + | [] -> [] + | _ -> + let args_list args = (if not calls_parameters_explicitly then t_dynamic else snd args) :: (List.map (fun (n,o,t) -> t) (fst args)) in + + let monos = List.map (fun _ -> mk_mono()) params in + let original = args_list (get_fun (apply_params params monos (TFun(fst original_args,snd original_args)))) in + let applied = args_list applied_args in + + (try + List.iter2 (fun a o -> + let o = deep_follow gen o in + let a = deep_follow gen a in + unify a o + (* type_eq EqStrict a o *) + ) applied original + (* unify applied original *) + with | Unify_error el -> + (* List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) pos) el; *) + gen.gcon.warning ("This expression may be invalid") pos + | Invalid_argument("List.map2") -> + gen.gcon.warning ("This expression may be invalid") pos + ); + + List.map (fun t -> + match follow t with + | TMono _ -> t_empty + | t -> t + ) monos + + (* ******************************************* *) + (* Real Type Parameters Module *) + (* ******************************************* *) + + (* + This submodule is by now specially made for the .NET platform. There might be other targets that will + make use of this, but it IS very specific. + + On the .NET platform, generics are real specialized classes that are JIT compiled. For this reason, we cannot + cast from one type parameter to another. Also there is no common type for the type parameters, so for example + an instance of type Array will return false for instance is Array . + + So we need to: + 1. create a common interface (without type parameters) (e.g. "Array") which will only contain a __Cast<> function, which will cast from one type into another + 2. Implement the __Cast function. This part is a little hard, as we must identify all type parameter-dependent fields contained in the class and convert them. + In most cases the conversion will just be to call .__Cast<>() on the instances, or just a simple cast. But when the instance is a @:nativegen type, there will be no .__Cast + function, and we will need to deal with this case either at compile-time (added handlers - specially for NativeArray), or at runtime (adding new runtime handlers) + 3. traverse the AST looking for casts involving type parameters, and replace them with .__Cast<>() calls. If type is @:nativegen, throw a warning. If really casting from one type parameter to another on a @:nativegen context, throw an error. + + + special literals: + it will use the special literal __typehandle__ that the target must implement in order to run this. This literal is a way to get the typehandle of e.g. the type parameters, + so we can compare them. In C# it's the equivalent of typeof(T).TypeHandle (TypeHandle compare is faster than System.Type.Equals()) + + dependencies: + (module filter) Interface creation must run AFTER enums are converted into classes, otherwise there is no way to tell parameterized enums to implement an interface + Must run AFTER CastDetect. This will be ensured per CastDetect + + *) + + module RealTypeParams = + struct + + let name = "real_type_params" + + let priority = priority + + let cast_field_name = "cast" + + let rec has_type_params t = + match follow t with + | TInst( { cl_kind = KTypeParameter _ }, _) -> true + | TAbstract(_, params) + | TEnum(_, params) + | TInst(_, params) -> List.exists (fun t -> has_type_params t) params + | TFun(args,ret) -> + List.exists (fun (n,o,t) -> has_type_params t) args || has_type_params ret + | _ -> false + + let rec follow_all_md md = + let t = match md with + | TClassDecl { cl_kind = KAbstractImpl a } -> + TAbstract(a, List.map snd a.a_params) + | 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) + in + Abstract.follow_with_abstracts t + + let rec is_hxgeneric md = + match md with + | TClassDecl { cl_kind = KAbstractImpl a } -> + is_hxgeneric (TAbstractDecl a) + | TClassDecl(cl) -> + not (Meta.has Meta.NativeGeneric cl.cl_meta) + | TEnumDecl(e) -> + not (Meta.has Meta.NativeGeneric e.e_meta) + | TAbstractDecl(a) when Meta.has Meta.NativeGeneric a.a_meta -> + not (Meta.has Meta.NativeGeneric a.a_meta) + | md -> match follow_all_md md with + | TInst(cl,_) -> is_hxgeneric (TClassDecl cl) + | TEnum(e,_) -> is_hxgeneric (TEnumDecl e) + | TAbstract(a,_) -> not (Meta.has Meta.NativeGeneric a.a_meta) + | _ -> true + + let rec set_hxgeneric gen mds isfirst md = + let path = t_path md in + if List.exists (fun m -> path = t_path m) mds then begin + if isfirst then + None (* we still can't determine *) + else + Some true (* if we're in second pass and still can't determine, it's because it can be hxgeneric *) + end else begin + let has_unresolved = ref false in + let is_false v = + match v with + | Some false -> true + | None -> has_unresolved := true; false + | Some true -> false + in + + let mds = md :: mds in + match md with + | TClassDecl(cl) -> + (* first see if any meta is present (already processed) *) + if Meta.has Meta.NativeGeneric cl.cl_meta then + Some false + else if Meta.has Meta.HaxeGeneric cl.cl_meta then + Some true + else if cl.cl_params = [] && is_hxgen md then + (cl.cl_meta <- (Meta.HaxeGeneric,[],cl.cl_pos) :: cl.cl_meta; + Some true) + else if cl.cl_params = [] then + (cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some false) + else if not (is_hxgen md) then + (cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some false) + else begin + (* + if it's not present, see if any superclass is nativegeneric. + nativegeneric is inherited, while hxgeneric can be later changed to nativegeneric + *) + (* on the first pass, our job is to find any evidence that makes it not be hxgeneric. Otherwise it will be hxgeneric *) + match cl.cl_super with + | Some (c,_) when is_false (set_hxgeneric gen mds isfirst (TClassDecl c)) -> + cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some false + | _ -> + (* see if it's a generic class *) + match cl.cl_params with + | [] -> + (* if it's not, then it will follow hxgen *) + if is_hxgen (TClassDecl cl) then + cl.cl_meta <- (Meta.HaxeGeneric, [], cl.cl_pos) :: cl.cl_meta + else + cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some true + | _ -> + (* if it is, loop through all fields + statics and look for non-hxgeneric + generic classes that have KTypeParameter as params *) + let rec loop cfs = + match cfs with + | [] -> false + | cf :: cfs -> + let t = follow (gen.greal_type cf.cf_type) in + match t with + | TInst( { cl_kind = KTypeParameter _ }, _ ) -> loop cfs + | TInst(cl,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TClassDecl cl)) -> + if not (Hashtbl.mem gen.gtparam_cast cl.cl_path) then true else loop cfs + | TEnum(e,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TEnumDecl e)) -> + if not (Hashtbl.mem gen.gtparam_cast e.e_path) then true else loop cfs + | _ -> loop cfs (* TAbstracts / Dynamics can't be generic *) + in + if loop cl.cl_ordered_fields then begin + cl.cl_meta <- (Meta.NativeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some false + end else if isfirst && !has_unresolved then + None + else begin + cl.cl_meta <- (Meta.HaxeGeneric, [], cl.cl_pos) :: cl.cl_meta; + Some true + end + end + | TEnumDecl e -> + if Meta.has Meta.NativeGeneric e.e_meta then + Some false + else if Meta.has Meta.HaxeGeneric e.e_meta then + Some true + else if not (is_hxgen (TEnumDecl e)) then begin + e.e_meta <- (Meta.NativeGeneric, [], e.e_pos) :: e.e_meta; + Some false + end else begin + (* if enum is not generic, then it's hxgeneric *) + match e.e_params with + | [] -> + e.e_meta <- (Meta.HaxeGeneric, [], e.e_pos) :: e.e_meta; + Some true + | _ -> + let rec loop efs = + match efs with + | [] -> false + | ef :: efs -> + let t = follow (gen.greal_type ef.ef_type) in + match t with + | TFun(args, _) -> + if List.exists (fun (n,o,t) -> + let t = follow t in + match t with + | TInst( { cl_kind = KTypeParameter _ }, _ ) -> + false + | TInst(cl,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TClassDecl cl)) -> + not (Hashtbl.mem gen.gtparam_cast cl.cl_path) + | TEnum(e,p) when has_type_params t && is_false (set_hxgeneric gen mds isfirst (TEnumDecl e)) -> + not (Hashtbl.mem gen.gtparam_cast e.e_path) + | _ -> false + ) args then + true + else + loop efs + | _ -> loop efs + in + let efs = PMap.fold (fun ef acc -> ef :: acc) e.e_constrs [] in + if loop efs then begin + e.e_meta <- (Meta.NativeGeneric, [], e.e_pos) :: e.e_meta; + Some false + end else if isfirst && !has_unresolved then + None + else begin + e.e_meta <- (Meta.HaxeGeneric, [], e.e_pos) :: e.e_meta; + Some true + end + end + | _ -> assert false + end + + let set_hxgeneric gen md = + let ret = match md with + | TClassDecl { cl_kind = KAbstractImpl a } -> (match follow_all_md md with + | (TInst _ | TEnum _ as t) -> ( + let md = match t with + | TInst(cl,_) -> TClassDecl cl + | TEnum(e,_) -> TEnumDecl e + | _ -> assert false + in + let ret = set_hxgeneric gen [] true md in + if ret = None then get (set_hxgeneric gen [] false md) else get ret) + | TAbstract(a,_) -> true + | _ -> true) + | _ -> match set_hxgeneric gen [] true md with + | None -> + get (set_hxgeneric gen [] false md) + | Some v -> + v + in + if not ret then begin + match md with + | TClassDecl c -> + let set_hxgeneric (_,param) = match follow param with + | TInst(c,_) -> + c.cl_meta <- (Meta.NativeGeneric, [], c.cl_pos) :: c.cl_meta + | _ -> () + in + List.iter set_hxgeneric c.cl_params; + let rec handle_field cf = + List.iter set_hxgeneric cf.cf_params; + List.iter handle_field cf.cf_overloads + in + (match c.cl_kind with + | KAbstractImpl a -> + List.iter set_hxgeneric a.a_params; + | _ -> ()); + List.iter handle_field c.cl_ordered_fields; + List.iter handle_field c.cl_ordered_statics + | _ -> () + end; + ret + + let params_has_tparams params = + List.fold_left (fun acc t -> acc || has_type_params t) false params + + (* ******************************************* *) + (* RealTypeParamsModf *) + (* ******************************************* *) + + (* + + This is the module filter of Real Type Parameters. It will traverse through all types and look for hxgeneric classes (only classes). + When found, a parameterless interface will be created and associated via the "ifaces" Hashtbl to the original class. + Also a "cast" function will be automatically generated which will handle unsafe downcasts to more specific type parameters (necessary for serialization) + + dependencies: + Anything that may create hxgeneric classes must run before it. + Should run before ReflectionCFs (this dependency will be added to ReflectionCFs), so the added interfaces also get to be real IHxObject's + + *) + + module RealTypeParamsModf = + struct + + let set_only_hxgeneric gen = + let rec run md = + match md with + | TTypeDecl _ | TAbstractDecl _ -> md + | _ -> ignore (set_hxgeneric gen md); md + in + run + + let name = "real_type_params_modf" + + let priority = solve_deps name [] + + let rec get_fields gen cl params_cl params_cf acc = + let fields = List.fold_left (fun acc cf -> + match follow (gen.greal_type (gen.gfollow#run_f (cf.cf_type))) with + | TInst(cli, ((_ :: _) as p)) when (not (is_hxgeneric (TClassDecl cli))) && params_has_tparams p -> + (cf, apply_params cl.cl_params params_cl cf.cf_type, apply_params cl.cl_params params_cf cf.cf_type) :: acc + | TEnum(e, ((_ :: _) as p)) when not (is_hxgeneric (TEnumDecl e)) && params_has_tparams p -> + (cf, apply_params cl.cl_params params_cl cf.cf_type, apply_params cl.cl_params params_cf cf.cf_type) :: acc + | _ -> acc + ) [] cl.cl_ordered_fields in + match cl.cl_super with + | Some(cs, tls) -> + get_fields gen cs (List.map (apply_params cl.cl_params params_cl) tls) (List.map (apply_params cl.cl_params params_cf) tls) (fields @ acc) + | None -> (fields @ acc) + + (* overrides all needed cast functions from super classes / interfaces to call the new cast function *) + let create_stub_casts gen cl cast_cfield = + (* go through superclasses and interfaces *) + let p = cl.cl_pos in + let this = { eexpr = TConst TThis; etype = (TInst(cl, List.map snd cl.cl_params)); epos = p } in + + let rec loop cls tls level reverse_params = + if (level <> 0 || cls.cl_interface) && tls <> [] && is_hxgeneric (TClassDecl cls) then begin + let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) cls.cl_params in + let name = String.concat "_" ((fst cls.cl_path) @ [snd cls.cl_path; cast_field_name]) in + if not (PMap.mem name cl.cl_fields) then begin + let reverse_params = List.map (apply_params cls.cl_params (List.map snd cparams)) reverse_params in + let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in + let field = { eexpr = TField(this, FInstance(cl,List.map snd cl.cl_params, cast_cfield)); etype = apply_params cast_cfield.cf_params reverse_params cast_cfield.cf_type; epos = p } in + let call = + { + eexpr = TCall(field, []); + etype = t_dynamic; + epos = p; + } in + let call = gen.gparam_func_call call field reverse_params [] in + let delay () = + cfield.cf_expr <- + Some { + eexpr = TFunction( + { + tf_args = []; + tf_type = t_dynamic; + tf_expr = + { + eexpr = TReturn( Some call ); + etype = t_dynamic; + epos = p; + } + }); + etype = cfield.cf_type; + epos = p; + } + in + gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended; (* do not let filters alter this expression content *) + cl.cl_ordered_fields <- cfield :: cl.cl_ordered_fields; + cl.cl_fields <- PMap.add cfield.cf_name cfield cl.cl_fields; + if level <> 0 then cl.cl_overrides <- cfield :: cl.cl_overrides + end + end; + let get_reverse super supertl = + let kv = List.map2 (fun (_,tparam) applied -> (follow applied, follow tparam)) super.cl_params supertl in + List.map (fun t -> + try + List.assq (follow t) kv + with | Not_found -> t + ) reverse_params + in + (match cls.cl_super with + | None -> () + | Some(super, supertl) -> + loop super supertl (level + 1) (get_reverse super supertl)); + List.iter (fun (iface, ifacetl) -> + loop iface ifacetl level (get_reverse iface ifacetl) + ) cls.cl_implements + in + loop cl (List.map snd cl.cl_params) 0 (List.map snd cl.cl_params) + + (* + Creates a cast classfield, with the desired name + + Will also look for previous cast() definitions and override them, to reflect the current type and fields + + FIXME: this function still doesn't support generics that extend generics, and are cast as one of its subclasses. This needs to be taken care, by + looking at previous superclasses and whenever a generic class is found, its cast argument must be overriden. the toughest part is to know how to type + the current type correctly. + *) + let create_cast_cfield gen cl name = + let basic = gen.gcon.basic in + let cparams = List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) cl.cl_params in + let cfield = mk_class_field name (TFun([], t_dynamic)) false cl.cl_pos (Method MethNormal) cparams in + let params = List.map snd cparams in + + let fields = get_fields gen cl (List.map snd cl.cl_params) params [] in + + (* now create the contents of the function *) + (* + it will look something like: + if (typeof(T) == typeof(T2)) return this; + + var new_me = new CurrentClass(EmptyInstnace); + + for (field in Reflect.fields(this)) + { + switch(field) + { + case "aNativeArray": + var newArray = new NativeArray(this.aNativeArray.Length); + + default: + Reflect.setField(new_me, field, Reflect.field(this, field)); + } + } + *) + + let new_t = TInst(cl, params) in + let pos = cl.cl_pos in + + let new_me_var = alloc_var "new_me" new_t in + let local_new_me = { eexpr = TLocal(new_me_var); etype = new_t; epos = pos } in + let this = { eexpr = TConst(TThis); etype = (TInst(cl, List.map snd cl.cl_params)); epos = pos } in + let field_var = alloc_var "field" gen.gcon.basic.tstring in + let local_field = { eexpr = TLocal(field_var); etype = field_var.v_type; epos = pos } in + let i_var = alloc_var "i" gen.gcon.basic.tint in + let local_i = { eexpr = TLocal(i_var); etype = gen.gcon.basic.tint; epos = pos } in + let incr_i = { eexpr = TUnop(Ast.Increment, Ast.Postfix, local_i); etype = basic.tint; epos = pos } in + let fields_var = alloc_var "fields" (gen.gcon.basic.tarray gen.gcon.basic.tstring) in + let local_fields = { eexpr = TLocal(fields_var); etype = (gen.gcon.basic.tarray gen.gcon.basic.tstring); epos = pos } in + + let get_path t = + match follow t with + | TInst(cl,_) -> cl.cl_path + | TEnum(e,_) -> e.e_path + | TAbstract(a,_) -> a.a_path + | TMono _ + | TDynamic _ -> ([], "Dynamic") + | _ -> assert false + in + + (* this will take all fields that were *) + let fields_to_cases fields = + List.map (fun (cf, t_cl, t_cf) -> + let this_field = { eexpr = TField(this, FInstance(cl, List.map snd cl.cl_params, cf)); etype = t_cl; epos = pos } in + let expr = + { + eexpr = TBinop(OpAssign, { eexpr = TField(local_new_me, FInstance(cl, List.map snd cl.cl_params, cf) ); etype = t_cf; epos = pos }, + 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 *) assert false + ); + etype = t_cf; + epos = pos; + } in + + ([{ eexpr = TConst(TString(cf.cf_name)); etype = gen.gcon.basic.tstring; epos = pos }], expr) + ) fields + in + + let mk_typehandle = + let thandle = alloc_var "__typeof__" t_dynamic in + (fun cl -> { eexpr = TCall(mk_local thandle pos, [ mk_classtype_access cl pos ]); etype = t_dynamic; epos = pos }) + in + let mk_eq cl1 cl2 = + { eexpr = TBinop(Ast.OpEq, mk_typehandle cl1, mk_typehandle cl2); etype = basic.tbool; epos = pos } + in + + let rec mk_typehandle_cond thisparams cfparams = + match thisparams, cfparams with + | TInst(cl_this,[]) :: [], TInst(cl_cf,[]) :: [] -> + mk_eq cl_this cl_cf + | TInst(cl_this,[]) :: hd, TInst(cl_cf,[]) :: hd2 -> + { eexpr = TBinop(Ast.OpBoolAnd, mk_eq cl_this cl_cf, mk_typehandle_cond hd hd2); etype = basic.tbool; epos = pos } + | v :: hd, v2 :: hd2 -> + (match follow v, follow v2 with + | (TInst(cl1,[]) as v), (TInst(cl2,[]) as v2) -> + mk_typehandle_cond (v :: hd) (v2 :: hd2) + | _ -> + assert false + ) + | _ -> assert false + in + + let fn = + { + tf_args = []; + tf_type = t_dynamic; + tf_expr = + { + eexpr = TBlock([ + (* if (typeof(T) == typeof(T2)) return this *) + { + eexpr = TIf( + mk_typehandle_cond (List.map snd cl.cl_params) params, + mk_return this, + None); + etype = basic.tvoid; + epos = pos; + }; + (* var new_me = /*special create empty with tparams construct*/ *) + { + eexpr = TVar(new_me_var, Some(gen.gtools.rf_create_empty cl params pos)); + etype = gen.gcon.basic.tvoid; + epos = pos + }; + (* var fields = Reflect.fields(this); *) + { + eexpr = TVar(fields_var, Some(gen.gtools.r_fields true this)); + etype = gen.gcon.basic.tvoid; + epos = pos + }; + (* var i = 0; *) + { + eexpr = TVar(i_var, Some(mk_int gen 0 pos)); + etype = gen.gcon.basic.tvoid; + epos = pos + }; + { + eexpr = TWhile( (* while (i < fields.length) *) + { + eexpr = TBinop(Ast.OpLt, + local_i, + mk_field_access gen local_fields "length" pos); + etype = gen.gcon.basic.tbool; + epos = pos + }, + { + eexpr = TBlock [ + (* var field = fields[i++]; *) + { + eexpr = TVar(field_var, Some { eexpr = TArray (local_fields, incr_i); etype = gen.gcon.basic.tstring; epos = pos }); + etype = gen.gcon.basic.tvoid; + epos = pos + }; + ( + (* default: Reflect.setField(new_me, field, Reflect.field(this, field)) *) + let edef = gen.gtools.r_set_field gen.gcon.basic.tvoid local_new_me local_field (gen.gtools.r_field false gen.gcon.basic.tvoid this local_field) in + if fields <> [] then + (* switch(field) { ... } *) + { + eexpr = TSwitch(local_field, fields_to_cases fields, Some(edef)); + etype = gen.gcon.basic.tvoid; + epos = pos; + } + else + edef; + ) + ]; + etype = gen.gcon.basic.tvoid; + epos = pos + }, + Ast.NormalWhile + ); + etype = gen.gcon.basic.tvoid; + epos = pos; + }; + (* return new_me *) + mk_return local_new_me + ]); + etype = t_dynamic; + epos = pos; + }; + } + in + + cfield.cf_expr <- Some( { eexpr = TFunction(fn); etype = cfield.cf_type; epos = pos } ); + + cfield + + let create_static_cast_cf gen iface cf = + let p = iface.cl_pos in + let basic = gen.gcon.basic in + let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst (map_param (get_cl_t t), []))) cf.cf_params in + let me_type = TInst(iface,[]) in + let cfield = mk_class_field "__hx_cast" (TFun(["me",false,me_type], t_dynamic)) false iface.cl_pos (Method MethNormal) (cparams) in + let params = List.map snd cparams in + + let me = alloc_var "me" me_type in + let field = { eexpr = TField(mk_local me p, FInstance(iface, List.map snd iface.cl_params, cf)); etype = apply_params cf.cf_params params cf.cf_type; epos = p } in + let call = + { + eexpr = TCall(field, []); + etype = t_dynamic; + epos = p; + } in + let call = gen.gparam_func_call call field params [] in + + (* since object.someCall() isn't allowed on Haxe, we need to directly apply the params and delay this call *) + let delay () = + cfield.cf_expr <- + Some { + eexpr = TFunction( + { + tf_args = [me,None]; + tf_type = t_dynamic; + tf_expr = + { + eexpr = TReturn( Some + { + eexpr = TIf( + { eexpr = TBinop(Ast.OpNotEq, mk_local me p, null me.v_type p); etype = basic.tbool; epos = p }, + call, + Some( null me.v_type p ) + ); + etype = t_dynamic; + epos = p; + }); + etype = basic.tvoid; + epos = p; + } + }); + etype = cfield.cf_type; + epos = p; + } + in + cfield, delay + + let get_cast_name cl = String.concat "_" ((fst cl.cl_path) @ [snd cl.cl_path; cast_field_name]) (* explicitly define it *) + + let default_implementation gen ifaces base_generic = + let add_iface cl = + gen.gadd_to_module (TClassDecl cl) (max_dep); + in + + let implement_stub_cast cthis iface tl = + let name = get_cast_name iface in + if not (PMap.mem name cthis.cl_fields) then begin + let cparams = List.map (fun (s,t) -> ("To_" ^ s, TInst(map_param (get_cl_t t), []))) iface.cl_params in + let field = mk_class_field name (TFun([],t_dynamic)) false iface.cl_pos (Method MethNormal) cparams in + let this = { eexpr = TConst TThis; etype = TInst(cthis, List.map snd cthis.cl_params); epos = cthis.cl_pos } in + field.cf_expr <- Some { + etype = TFun([],t_dynamic); + epos = this.epos; + eexpr = TFunction { + tf_type = t_dynamic; + tf_args = []; + tf_expr = mk_block { this with + eexpr = TReturn (Some this) + } + } + }; + cthis.cl_ordered_fields <- field :: cthis.cl_ordered_fields; + cthis.cl_fields <- PMap.add name field cthis.cl_fields + end + in + + let rec run md = + match md with + | TClassDecl ({ cl_params = [] } as cl) -> + (* see if we're implementing any generic interface *) + let rec check (iface,tl) = + if tl <> [] && set_hxgeneric gen (TClassDecl iface) then + (* implement cast stub *) + implement_stub_cast cl iface tl; + List.iter (fun (s,stl) -> check (s, List.map (apply_params iface.cl_params tl) stl)) iface.cl_implements; + in + List.iter (check) cl.cl_implements; + md + | TClassDecl ({ cl_params = hd :: tl } as cl) when set_hxgeneric gen md -> + let iface = mk_class cl.cl_module cl.cl_path cl.cl_pos in + iface.cl_array_access <- Option.map (apply_params (cl.cl_params) (List.map (fun _ -> t_dynamic) cl.cl_params)) cl.cl_array_access; + iface.cl_module <- cl.cl_module; + iface.cl_meta <- + (Meta.HxGen, [], cl.cl_pos) + :: + (Meta.Custom "generic_iface", [(EConst(Int(string_of_int(List.length cl.cl_params))), cl.cl_pos)], cl.cl_pos) + :: + iface.cl_meta; + Hashtbl.add ifaces cl.cl_path iface; + + iface.cl_implements <- (base_generic, []) :: iface.cl_implements; + iface.cl_interface <- true; + cl.cl_implements <- (iface, []) :: cl.cl_implements; + + let name = get_cast_name cl in + let cast_cf = create_cast_cfield gen cl name in + if not cl.cl_interface then create_stub_casts gen cl cast_cf; + + let rec loop c = match c.cl_super with + | None -> () + | Some(sup,_) -> try + let siface = Hashtbl.find ifaces sup.cl_path in + iface.cl_implements <- (siface,[]) :: iface.cl_implements; + () + with | Not_found -> loop sup + in + loop cl; + + (if not cl.cl_interface then cl.cl_ordered_fields <- cast_cf :: cl.cl_ordered_fields); + let iface_cf = mk_class_field name cast_cf.cf_type false cast_cf.cf_pos (Method MethNormal) cast_cf.cf_params in + let cast_static_cf, delay = create_static_cast_cf gen iface iface_cf in + + cl.cl_ordered_statics <- cast_static_cf :: cl.cl_ordered_statics; + cl.cl_statics <- PMap.add cast_static_cf.cf_name cast_static_cf cl.cl_statics; + gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended; (* do not let filters alter this expression content *) + + iface_cf.cf_type <- cast_cf.cf_type; + iface.cl_fields <- PMap.add name iface_cf iface.cl_fields; + let fields = List.filter (fun cf -> match cf.cf_kind with + | Var _ | Method MethDynamic -> false + | _ -> + let is_override = List.memq cf cl.cl_overrides in + let cf_type = if is_override && 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 + + not (has_type_params cf_type)) cl.cl_ordered_fields + in + let fields = List.map (fun f -> mk_class_field f.cf_name f.cf_type f.cf_public f.cf_pos f.cf_kind f.cf_params) fields in + let fields = iface_cf :: fields in + iface.cl_ordered_fields <- fields; + List.iter (fun f -> iface.cl_fields <- PMap.add f.cf_name f iface.cl_fields) fields; + + add_iface iface; + md + | TTypeDecl _ | TAbstractDecl _ -> md + | TEnumDecl _ -> + ignore (set_hxgeneric gen md); + md + | _ -> ignore (set_hxgeneric gen md); md + in + run + + let configure gen mapping_func = + let map e = Some(mapping_func e) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + + end;; + + (* create a common interface without type parameters and only a __Cast<> function *) + let default_implementation gen (dyn_tparam_cast:texpr->t->texpr) ifaces = + let change_expr e cl iface params = + let field = mk_static_field_access_infer cl "__hx_cast" e.epos params in + let elist = [mk_cast (TInst(iface,[])) e] in + let call = { eexpr = TCall(field, elist); etype = t_dynamic; epos = e.epos } in + + gen.gparam_func_call call field params elist + in + + let rec run e = + match e.eexpr with + | TCast(cast_expr, _) -> + (* see if casting to a native generic class *) + let t = gen.greal_type e.etype in + let unifies = + let ctype = gen.greal_type cast_expr.etype in + match follow ctype with + | TInst(cl,_) -> (try + unify ctype t; + true + with | Unify_error el -> + false) + | _ -> false + in + let unifies = unifies && not (PMap.mem "cs_safe_casts" gen.gcon.defines) in + (match follow t with + | TInst(cl, p1 :: pl) when is_hxgeneric (TClassDecl cl) && not unifies && not (Meta.has Meta.Enum cl.cl_meta) -> + let iface = Hashtbl.find ifaces cl.cl_path in + mk_cast e.etype (change_expr (Type.map_expr run cast_expr) cl iface (p1 :: pl)) + | _ -> Type.map_expr run e + ) + | _ -> Type.map_expr run e + in + run + + let configure gen traverse = + gen.ghas_tparam_cast_handler <- true; + let map e = Some(traverse e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + + let default_config gen (dyn_tparam_cast:texpr->t->texpr) ifaces base_generic = + configure gen (default_implementation gen dyn_tparam_cast ifaces); + RealTypeParamsModf.configure gen (RealTypeParamsModf.default_implementation gen ifaces base_generic) + + end;; + + (* ******************************************* *) + (* Rename Type Parameters *) + (* ******************************************* *) + + (* + + This module should run after everything is already applied, + it will look for possible type parameter name clashing and change the classes names to a + + dependencies: + should run after everything is already applied. There's no configure on this module, only 'run'. + + *) + + module RenameTypeParameters = + struct + + let name = "rename_type_parameters" + + let run gen = + let i = ref 0 in + let found_types = ref PMap.empty in + let check_type name on_changed = + let rec loop name = + incr i; + let changed_name = (name ^ (string_of_int !i)) in + if PMap.mem changed_name !found_types then loop name else changed_name + in + if PMap.mem name !found_types then begin + let new_name = loop name in + found_types := PMap.add new_name true !found_types; + on_changed new_name + end else found_types := PMap.add name true !found_types + in + + let get_cls t = + match follow t with + | TInst(cl,_) -> cl + | _ -> assert false + in + + let iter_types (nt,t) = + let cls = get_cls t in + let orig = cls.cl_path in + check_type (snd orig) (fun name -> cls.cl_path <- (fst orig, name)) + in + + let save_params save params = + List.fold_left (fun save (_,t) -> + let cls = get_cls t in + (cls.cl_path,t) :: save) save params + in + + List.iter (function + | TClassDecl cl -> + i := 0; + + let save = [] in + + found_types := PMap.empty; + let save = save_params save cl.cl_params in + List.iter iter_types cl.cl_params; + let cur_found_types = !found_types in + let save = ref save in + List.iter (fun cf -> + found_types := cur_found_types; + save := save_params !save cf.cf_params; + List.iter iter_types cf.cf_params + ) (cl.cl_ordered_fields @ cl.cl_ordered_statics); + + if !save <> [] then begin + let save = !save in + let res = cl.cl_restore in + cl.cl_restore <- (fun () -> + res(); + List.iter (fun (path,t) -> + let cls = get_cls t in + cls.cl_path <- path) save + ); + end + + | TEnumDecl ( ({ e_params = hd :: tl }) ) -> + i := 0; + found_types := PMap.empty; + List.iter iter_types (hd :: tl) + + | TAbstractDecl { a_params = hd :: tl } -> + i := 0; + found_types := PMap.empty; + List.iter iter_types (hd :: tl) + + | _ -> () + + ) gen.gtypes_list + + end;; + + + let configure gen (param_func_call:texpr->texpr->tparams->texpr list->texpr) = + (*let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map*) + gen.gparam_func_call <- param_func_call end;; (**************************************************************************************************************************) -(* SYNTAX FILTERS *) +(* SYNTAX FILTERS *) (**************************************************************************************************************************) (* ******************************************* *) @@ -4447,679 +5070,680 @@ end;; (* - This is the most important module for source-code based targets. It will follow a convention of what's an expression and what's a statement, - and will unwrap statements where expressions are expected, and vice-versa. + This is the most important module for source-code based targets. It will follow a convention of what's an expression and what's a statement, + and will unwrap statements where expressions are expected, and vice-versa. - It should be one of the first syntax filters to be applied. As a consequence, it's applied after all filters that add code to the AST, and by being - the first of the syntax filters, it will also have the AST retain most of the meaning of normal HaXe code. So it's easier to detect cases which are - side-effects free, for example + It should be one of the first syntax filters to be applied. As a consequence, it's applied after all filters that add code to the AST, and by being + the first of the syntax filters, it will also have the AST retain most of the meaning of normal Haxe code. So it's easier to detect cases which are + side-effects free, for example - Any target can make use of this, but there is one requirement: The target must accept null to be set to any kind of variable. For example, - var i:Int = null; must be accepted. The best way to deal with this is to (like it's done in C#) make null equal to "default(Type)" + Any target can make use of this, but there is one requirement: The target must accept null to be set to any kind of variable. For example, + var i:Int = null; must be accepted. The best way to deal with this is to (like it's done in C#) make null equal to "default(Type)" - dependencies: - While it's best for Expression Unwrap to delay its execution as much as possible, since theoretically any - filter can return an expression that needs to be unwrapped, it is also desirable for ExpresionUnwrap to have - the AST as close as possible as HaXe's, so it can make some correct predictions (for example, so it can - more accurately know what can be side-effects-free and what can't). - This way, it will run slightly after the Normal priority, so if you don't say that a syntax filter must run - before Expression Unwrap, it will run after it. + dependencies: + While it's best for Expression Unwrap to delay its execution as much as possible, since theoretically any + filter can return an expression that needs to be unwrapped, it is also desirable for ExpresionUnwrap to have + the AST as close as possible as Haxe's, so it can make some correct predictions (for example, so it can + more accurately know what can be side-effects-free and what can't). + This way, it will run slightly after the Normal priority, so if you don't say that a syntax filter must run + before Expression Unwrap, it will run after it. - TODO : While statement must become do / while, with the actual block inside an if for the condition, and else for 'break' + TODO : While statement must become do / while, with the actual block inside an if for the condition, and else for 'break' *) module ExpressionUnwrap = struct - let name = "expression_unwrap" - - (* priority: first syntax filter *) - let priority = -10.0 - - (* - We always need to rely on Blocks to be able to unwrap expressions correctly. - So the the standard traverse will always be based on blocks. - Normal block statements, like for(), while(), if(), ... will be mk_block'ed so there is always a block inside of them. - - At the block level, we'll define an "add_statement" function, which will allow the current expression to - add statements to the block. This statement may or may not contain statements as expressions, so the texpr will be evaluated recursively before being added. - - - traverse will always evaluate TBlocks - - for each texpr in a TBlock list, - check shallow type - if type is Statement or Both when it has problematic expression (var problematic_expr = count_problematic_expressions), - if we can eagerly call unwrap_statement on the whole expression (try_call_unwrap_statement), use the return expression - else - check expr_type of each underlying type (with expr_stat_map) - if it has ExprWithStatement or Statement, - call problematic_expression_unwrap in it - problematic_expr-- - else if problematic_expr == 0, just add the unchanged expression - else if NoSideEffects and doesn't have short-circuit, just add the unchanged expression - else call problematic_expression_unwrap in it - if type is Expression, check if there are statements or Both inside. - if there are, problematic_expression_unwrap in it - aftewards, use on_expr_as_statement to get it - - helpers: - try_call_unwrap_statement: (returns texpr option) - if underlying statement is TBinop(OpAssign/OpAssignOp), or TVars, with the right side being a Statement or a short circuit op, we can call apply_assign. - - apply_assign: - if is TVar, first declare the tvar with default expression = null; - will receive the left and right side of the assignment; right-side must be Statement - see if right side is a short-circuit operation, call short_circuit_op_unwrap - else see eexpr of the right side - if it's void, just add the statement with add_statement, and set the right side as null; - if not, it will have a block inside. set the left side = to the last expression on each block inside. add_statement for it. - - short_circuit_op_unwrap: x() && (1 + {var x = 0; x + 1;} == 2) && z() - -> var x = x(); - var y = false; - var z = false; - if (x) //for &&, neg for || - { - var temp = null; - { - var x = 0; - temp = x + 1; - } - - y = (1 + temp) == 2; - if (y) - { - z = z(); - } - } - expects to receive a texpr with TBinop(OpBoolAnd/OpBoolOr) - will traverse the AST while there is a TBinop(OpBoolAnd/OpBoolOr) as a right-side expr, and declare new temp vars in the for each found. - will collect the return value, a mapped expr with all exprs as TLocal of the temp vars created - - - problematic_expression_unwrap: - check expr_kind: - if it is NoSideEffects and not short-circuit, leave it there - if it is ExprWithStatement and not short-circuit, call Type.map_expr problematic_expression_unwrap - if it is Statement or Expression or short-circuit expr, call add_assign for this expression - - add_assign: - see if the type is void. If it is, just add_statement the expression argument, and return a null value - else create a new variable, set TVars with Some() with the expression argument, add TVar with add_statement, and return the TLocal of this expression. - - map_problematic_expr: - call expr_stat_map on statement with problematic_expression_unwrap - - types: - type shallow_expr_type = | Statement | Expression | Both (* shallow expression classification. Both means that they can be either Statements as Expressions *) - - type expr_kind = | NormalExpr | ExprNoSideEffects (* -> short-circuit is considered side-effects *) | ExprWithStatement | Statement - evaluates an expression (as in not a statement) type. If it is ExprWithStatement or Statement, it means it contains errors - - functions: - shallow_expr_type (expr:texpr) : shallow_expr_type - - expr_kind (expr:texpr) : expr_kind - deeply evaluates an expression type - - expr_stat_map (fn:texpr->texpr) (expr:texpr) : texpr - it will traverse the AST looking for places where an expression is expected, and map the value according to fn - - aggregate_expr_type (is_side_effects_free:bool) (children:expr_type list) : expr_type - helper function to deal with expr_type aggregation (e.g. an Expression + a Statement as a children, is a ExprWithStatement) - - check_statement_in_expression (expr:texpr) : texpr option : - will check - - *) - - type shallow_expr_type = | Statement | Expression of texpr | Both of texpr (* shallow expression classification. Both means that they can be either Statements as Expressions *) - - type expr_kind = | KNormalExpr | KNoSideEffects (* -> short-circuit is considered side-effects *) | KExprWithStatement | KStatement - - let rec no_paren e = - match e.eexpr with - | TParenthesis e -> no_paren e - | _ -> e - - (* must be called in a statement. Will execute fn whenever an expression (not statement) is expected *) - let expr_stat_map fn (expr:texpr) = - match (no_paren expr).eexpr with - | TBinop ( (Ast.OpAssign as op), left_e, right_e ) - | TBinop ( (Ast.OpAssignOp _ as op), left_e, right_e ) -> - { expr with eexpr = TBinop(op, fn left_e, fn right_e) } - | TParenthesis _ -> assert false - | TCall(left_e, params) -> - { expr with eexpr = TCall(fn left_e, List.map fn params) } - | TNew(cl, tparams, params) -> - { expr with eexpr = TNew(cl, tparams, List.map fn params) } - | TVars(vars) -> - { expr with eexpr = TVars( List.map (fun (v,eopt) -> (v, Option.map fn eopt)) vars ) } - | TFor (v,cond,block) -> - { expr with eexpr = TFor(v, fn cond, block) } - | TIf(cond,eif,eelse) -> - { expr with eexpr = TIf(fn cond, eif, eelse) } - | TWhile(cond, block, flag) -> - { expr with eexpr = TWhile(fn cond, block, flag) } - | TSwitch(cond, el_block_l, default) -> - { expr with eexpr = TSwitch( fn cond, List.map (fun (el,block) -> (List.map fn el, block)) el_block_l, default ) } - | TMatch(cond, enum, cases, default) -> - { expr with eexpr = TMatch(fn cond, enum, cases, default) } - | TReturn(eopt) -> - { expr with eexpr = TReturn(Option.map fn eopt) } - | TThrow (texpr) -> - { expr with eexpr = TThrow(fn texpr) } - | TBreak - | TContinue - | TTry _ - | TUnop (Ast.Increment, _, _) - | TUnop (Ast.Decrement, _, _) (* unop is a special case because the haxe compiler won't let us generate complex expressions with Increment/Decrement *) - | TBlock _ -> expr (* there is no expected expression here. Only statements *) - | _ -> assert false (* we only expect valid statements here. other expressions aren't valid statements *) - - let is_expr = function | Expression _ -> true | _ -> false - - let aggregate_expr_type map_fn side_effects_free children = - let rec loop acc children = - match children with - | [] -> acc - | hd :: children -> - match acc, map_fn hd with - | _, KExprWithStatement - | _, KStatement - | KExprWithStatement, _ - | KStatement, _ -> KExprWithStatement - | KNormalExpr, KNoSideEffects - | KNoSideEffects, KNormalExpr - | KNormalExpr, KNormalExpr -> loop KNormalExpr children - | KNoSideEffects, KNoSideEffects -> loop KNoSideEffects children - in - loop (if side_effects_free then KNoSideEffects else KNormalExpr) children - - (* statements: *) - (* Error CS0201: Only assignment, call, increment, *) - (* decrement, and new object expressions can be used as a *) - (* statement (CS0201). *) - let rec shallow_expr_type expr : shallow_expr_type = - match expr.eexpr with - | TCall _ when not (is_void expr.etype) -> Both expr - | TNew _ - | TUnop (Ast.Increment, _, _) - | TUnop (Ast.Decrement, _, _) - | TBinop (Ast.OpAssign, _, _) - | TBinop (Ast.OpAssignOp _, _, _) -> Both expr - | TIf (cond, eif, Some(eelse)) -> (match aggregate_expr_type expr_kind true [cond;eif;eelse] with - | KExprWithStatement -> Statement - | _ -> Both expr) - | TConst _ - | TLocal _ - | TArray _ - | TBinop _ - | TField _ - | TTypeExpr _ - | TObjectDecl _ - | TArrayDecl _ - | TFunction _ - | TCast _ - | TUnop _ -> Expression (expr) - | TParenthesis p -> shallow_expr_type p - | TBlock ([e]) -> shallow_expr_type e - | TCall _ - | TVars _ - | TBlock _ - | TFor _ - | TWhile _ - | TSwitch _ - | TMatch _ - | TTry _ - | TReturn _ - | TBreak - | TContinue - | TIf _ - | TThrow _ -> Statement - - and expr_kind expr = - match shallow_expr_type expr with - | Statement -> KStatement - | Both expr | Expression expr -> - let aggregate = aggregate_expr_type expr_kind in - match expr.eexpr with - | TConst _ - | TLocal _ - | TFunction _ - | TTypeExpr _ -> - KNoSideEffects - | TCall (ecall, params) -> - aggregate false (ecall :: params) - | TNew (_,_,params) -> - aggregate false params - | TUnop (Increment,_,e) - | TUnop (Decrement,_,e) -> - aggregate false [e] - | TUnop (_,_,e) -> - aggregate true [e] - | TBinop (Ast.OpBoolAnd, e1, e2) - | TBinop (Ast.OpBoolOr, e1, e2) -> (* TODO: should OpBool never be side-effects free? *) - aggregate true [e1;e2] - | TBinop (Ast.OpAssign, e1, e2) - | TBinop (Ast.OpAssignOp _, e1, e2) -> - aggregate false [e1;e2] - | TBinop (_, e1, e2) -> - aggregate true [e1;e2] - | TIf (cond, eif, Some(eelse)) -> (match aggregate true [cond;eif;eelse] with - | KExprWithStatement -> KStatement - | k -> k) - | TArray (e1,e2) -> - aggregate true [e1;e2] - | TParenthesis e - | TField (e,_) -> - aggregate true [e] - | TArrayDecl (el) -> - aggregate true el - | TObjectDecl (sel) -> - aggregate true (List.map snd sel) - | TCast (e,_) -> - aggregate true [e] - | _ -> trace (debug_expr expr); assert false (* should have been read as Statement by shallow_expr_type *) - - let is_side_effects_free e = - match expr_kind e with | KNoSideEffects -> true | _ -> false - - let get_kinds (statement:texpr) = - let kinds = ref [] in - ignore (expr_stat_map (fun e -> - kinds := (expr_kind e) :: !kinds; - e - ) statement); - List.rev !kinds - - let has_problematic_expressions (kinds:expr_kind list) = - let rec loop kinds = - match kinds with - | [] -> false - | KStatement :: _ - | KExprWithStatement :: _ -> true - | _ :: tl -> loop tl - in - loop kinds - - let count_problematic_expressions (statement:texpr) = - let count = ref 0 in - ignore (expr_stat_map (fun e -> - (match expr_kind e with - | KStatement | KExprWithStatement -> incr count - | _ -> () - ); - e - ) statement); - !count - - let apply_assign_block assign_fun elist = - let rec assign acc elist = - match elist with - | [] -> acc - | last :: [] -> - (assign_fun last) :: acc - | hd :: tl -> - assign (hd :: acc) tl - in - List.rev (assign [] elist) - - let mk_get_block assign_fun e = - match e.eexpr with - | TBlock [] -> e - | TBlock (el) -> - { e with eexpr = TBlock(apply_assign_block assign_fun el) } - | _ -> - { e with eexpr = TBlock([ assign_fun e ]) } - - let add_assign gen add_statement expr = - match expr.eexpr, follow expr.etype with - | _, TEnum({ e_path = ([],"Void") },[]) - | _, TAbstract ({ a_path = ([],"Void") },[]) - | TThrow _, _ -> - add_statement expr; - null expr.etype expr.epos - | _ -> - let var = mk_temp gen "stmt" expr.etype in - let tvars = { expr with eexpr = TVars([var,Some(expr)]) } in - let local = { expr with eexpr = TLocal(var) } in - add_statement tvars; - local - - (* requirement: right must be a statement *) - let rec apply_assign assign_fun right = - match right.eexpr with - | TBlock el -> - { right with eexpr = TBlock(apply_assign_block assign_fun el) } - | TSwitch (cond, elblock_l, default) -> - { right with eexpr = TSwitch(cond, List.map (fun (el,block) -> (el, mk_get_block assign_fun block)) elblock_l, Option.map (mk_get_block assign_fun) default) } - | TMatch (cond, ep, il_vlo_e_l, default) -> - { right with eexpr = TMatch(cond, ep, List.map (fun (il,vlo,e) -> (il,vlo,mk_get_block assign_fun e)) il_vlo_e_l, Option.map (mk_get_block assign_fun) default) } - | TTry (block, catches) -> - { right with eexpr = TTry(mk_get_block assign_fun block, List.map (fun (v,block) -> (v,mk_get_block assign_fun block) ) catches) } - | TIf (cond,eif,eelse) -> - { right with eexpr = TIf(cond, mk_get_block assign_fun eif, Option.map (mk_get_block assign_fun) eelse) } - | TThrow _ - | TWhile _ - | TFor _ - | TReturn _ - | TBreak - | TContinue -> right - | TParenthesis p -> - apply_assign assign_fun p - | _ -> - match follow right.etype with - | TEnum( { e_path = ([], "Void") }, [] ) - | TAbstract ({ a_path = ([], "Void") },[]) -> - right - | _ -> trace (debug_expr right); assert false (* a statement is required *) - - let short_circuit_op_unwrap gen add_statement expr :texpr = - let do_not expr = - { expr with eexpr = TUnop(Ast.Not, Ast.Prefix, expr) } - in - - (* loop will always return its own TBlock, and the mapped expression *) - let rec loop acc expr = - match expr.eexpr with - | TBinop ( (Ast.OpBoolAnd as op), left, right) -> - let var = mk_temp gen "boolv" right.etype in - let tvars = { right with eexpr = TVars([var, Some( { right with eexpr = TConst(TBool false); etype = gen.gcon.basic.tbool } )]); etype = gen.gcon.basic.tvoid } in - let local = { right with eexpr = TLocal(var) } in - - let mapped_left, ret_acc = loop ( (local, { right with eexpr = TBinop(Ast.OpAssign, local, right) } ) :: acc) left in - - add_statement tvars; - ({ expr with eexpr = TBinop(op, mapped_left, local) }, ret_acc) - (* we only accept OpBoolOr when it's the first to be evaluated *) - | TBinop ( (Ast.OpBoolOr as op), left, right) when acc = [] -> - let left = match left.eexpr with - | TLocal _ | TConst _ -> left - | _ -> add_assign gen add_statement left - in - - let var = mk_temp gen "boolv" right.etype in - let tvars = { right with eexpr = TVars([var, Some( { right with eexpr = TConst(TBool false); etype = gen.gcon.basic.tbool } )]); etype = gen.gcon.basic.tvoid } in - let local = { right with eexpr = TLocal(var) } in - add_statement tvars; - - ({ expr with eexpr = TBinop(op, left, local) }, [ do_not left, { right with eexpr = TBinop(Ast.OpAssign, local, right) } ]) - | _ when acc = [] -> assert false - | _ -> - let var = mk_temp gen "boolv" expr.etype in - let tvars = { expr with eexpr = TVars([var, Some( { expr with etype = gen.gcon.basic.tbool } )]); etype = gen.gcon.basic.tvoid } in - let local = { expr with eexpr = TLocal(var) } in - - let last_local = ref local in - let acc = List.map (fun (local, assign) -> - let l = !last_local in - last_local := local; - (l, assign) - ) acc in - - add_statement tvars; - (local, acc) - in - - let mapped_expr, local_assign_list = loop [] expr in - - let rec loop local_assign_list : texpr = - match local_assign_list with - | [local, assign] -> - { eexpr = TIf(local, assign, None); etype = gen.gcon.basic.tvoid; epos = assign.epos } - | (local, assign) :: tl -> - { eexpr = TIf(local, - { - eexpr = TBlock ( assign :: [loop tl] ); - etype = gen.gcon.basic.tvoid; - epos = assign.epos; - }, - None); etype = gen.gcon.basic.tvoid; epos = assign.epos } - | [] -> assert false - in - - add_statement (loop local_assign_list); - mapped_expr - - (* there are two short_circuit fuctions as I'm still testing the best way to do it *) - (*let short_circuit_op_unwrap gen add_statement expr :texpr = - let block = ref [] in - let rec short_circuit_op_unwrap is_first last_block expr = - match expr.eexpr with - | TBinop ( (Ast.OpBoolAnd as op), left, right) - | TBinop ( (Ast.OpBoolOr as op), left, right) -> - let var = mk_temp gen "boolv" left.etype in - let tvars = { left with eexpr = TVars([var, if is_first then Some(left) else Some( { left with eexpr = TConst(TBool false) } )]); etype = gen.gcon.basic.tvoid } in - let local = { left with eexpr = TLocal(var) } in - if not is_first then begin - last_block := !last_block @ [ { left with eexpr = TBinop(Ast.OpAssign, local, left) } ] - end; - - add_statement tvars; - let local_op = match op with | Ast.OpBoolAnd -> local | Ast.OpBoolOr -> { local with eexpr = TUnop(Ast.Not, Ast.Prefix, local) } | _ -> assert false in - - let new_block = ref [] in - let new_right = short_circuit_op_unwrap false new_block right in - last_block := !last_block @ [ { expr with eexpr = TIf(local_op, { right with eexpr = TBlock(!new_block) }, None) } ]; - - { expr with eexpr = TBinop(op, local, new_right) } - | _ when is_first -> assert false - | _ -> - let var = mk_temp gen "boolv" expr.etype in - let tvars = { expr with eexpr = TVars([var, Some ( { expr with eexpr = TConst(TBool false) } ) ]); etype = gen.gcon.basic.tvoid } in - let local = { expr with eexpr = TLocal(var) } in - last_block := !last_block @ [ { expr with eexpr = TBinop(Ast.OpAssign, local, expr) } ]; - add_statement tvars; - - local - in - let mapped_expr = short_circuit_op_unwrap true block expr in - add_statement { eexpr = TBlock(!block); etype = gen.gcon.basic.tvoid; epos = expr.epos }; - mapped_expr*) - - let twhile_with_condition_statement gen add_statement twhile cond e1 flag = - (* when a TWhile is found with a problematic condition *) - let basic = gen.gcon.basic in - - let block = if flag = Ast.NormalWhile then - { e1 with eexpr = TIf(cond, e1, Some({ e1 with eexpr = TBreak; etype = basic.tvoid })) } - else - Codegen.concat e1 { e1 with - eexpr = TIf({ - eexpr = TUnop(Ast.Not, Ast.Prefix, mk_paren cond); - etype = basic.tbool; - epos = cond.epos - }, { e1 with eexpr = TBreak; etype = basic.tvoid }, None); - etype = basic.tvoid - } - in - - add_statement { twhile with - eexpr = TWhile( - { eexpr = TConst(TBool true); etype = basic.tbool; epos = cond.epos }, - block, - Ast.DoWhile - ); - } - - let try_call_unwrap_statement gen problematic_expression_unwrap (add_statement:texpr->unit) (expr:texpr) : texpr option = - let check_left left = - 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 *) - | _ -> left - in - - let handle_assign op left right = - let left = check_left left in - Some (apply_assign (fun e -> { e with eexpr = TBinop(op, left, if is_void left.etype then e else gen.ghandle_cast left.etype e.etype e) }) right ) - in - - let handle_return e = - Some( apply_assign (fun e -> - match e.eexpr with - | TThrow _ -> e - | _ when is_void e.etype -> - { e with eexpr = TBlock([e; { e with eexpr = TReturn None }]) } - | _ -> - { e with eexpr = TReturn( Some e ) } - ) e ) - in - - let is_problematic_if right = - match expr_kind right with - | KStatement | KExprWithStatement -> true - | _ -> false - in - - match expr.eexpr with - | TBinop((Ast.OpAssign as op),left,right) - | TBinop((Ast.OpAssignOp _ as op),left,right) when shallow_expr_type right = Statement -> - handle_assign op left right - | TReturn( Some right ) when shallow_expr_type right = Statement -> - handle_return right - | TBinop((Ast.OpAssign as op),left, ({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right) ) - | TBinop((Ast.OpAssign as op),left,({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right)) - | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right) ) - | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right) ) -> - let right = short_circuit_op_unwrap gen add_statement right in - Some { expr with eexpr = TBinop(op, check_left left, right) } - | TVars([v,Some({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right)]) - | TVars([v,Some({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right)]) -> - let right = short_circuit_op_unwrap gen add_statement right in - Some { expr with eexpr = TVars([v, Some(right)]) } - | TVars([v,Some(right)]) when shallow_expr_type right = Statement -> - add_statement ({ expr with eexpr = TVars([v, Some(null right.etype right.epos)]) }); - handle_assign Ast.OpAssign { expr with eexpr = TLocal(v); etype = v.v_type } right - (* TIf handling *) - | TBinop((Ast.OpAssign as op),left, ({ eexpr = TIf _ } as right)) - | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TIf _ } as right)) when is_problematic_if right -> - handle_assign op left right - | TVars([v,Some({ eexpr = TIf _ } as right)]) when is_problematic_if right -> - add_statement ({ expr with eexpr = TVars([v, Some(null right.etype right.epos)]) }); - handle_assign Ast.OpAssign { expr with eexpr = TLocal(v); etype = v.v_type } right - | TWhile(cond, e1, flag) when is_problematic_if cond -> - twhile_with_condition_statement gen add_statement expr cond e1 flag; - Some (null expr.etype expr.epos) - | _ -> None - - - let traverse gen (on_expr_as_statement:texpr->texpr option) = - - let add_assign = add_assign gen in - - let problematic_expression_unwrap add_statement expr e_type = - let rec problematic_expression_unwrap is_first expr e_type = - match e_type, expr.eexpr with - | _, TBinop(Ast.OpBoolAnd, _, _) - | _, TBinop(Ast.OpBoolOr, _, _) -> add_assign add_statement expr (* add_assign so try_call_unwrap_expr *) - | KNoSideEffects, _ -> expr - | KStatement, _ - | KNormalExpr, _ -> add_assign add_statement expr - | KExprWithStatement, TCall _ - | KExprWithStatement, TNew _ - | KExprWithStatement, TBinop (Ast.OpAssign,_,_) - | KExprWithStatement, TBinop (Ast.OpAssignOp _,_,_) - | KExprWithStatement, TUnop (Ast.Increment,_,_) (* all of these may have side-effects, so they must also be add_assign'ed . is_first avoids infinite loop *) - | KExprWithStatement, TUnop (Ast.Decrement,_,_) when not is_first -> add_assign add_statement expr - - (* bugfix: Type.map_expr doesn't guarantee the correct order of execution *) - | KExprWithStatement, TBinop(op,e1,e2) -> - let e1 = problematic_expression_unwrap false e1 (expr_kind e1) in - let e2 = problematic_expression_unwrap false e2 (expr_kind e2) in - { expr with eexpr = TBinop(op, e1, e2) } - | KExprWithStatement, TArray(e1,e2) -> - let e1 = problematic_expression_unwrap false e1 (expr_kind e1) in - let e2 = problematic_expression_unwrap false e2 (expr_kind e2) in - { expr with eexpr = TArray(e1, e2) } - (* bugfix: calls should not be transformed into closure calls *) - | KExprWithStatement, TCall(( { eexpr = TField (ef_left, f) } as ef ), eargs) -> - { expr with eexpr = TCall( - { ef with eexpr = TField(problematic_expression_unwrap false ef_left (expr_kind ef_left), f) }, - List.map (fun e -> problematic_expression_unwrap false e (expr_kind e)) eargs) - } - | KExprWithStatement, _ -> Type.map_expr (fun e -> problematic_expression_unwrap false e (expr_kind e)) expr - in - problematic_expression_unwrap true expr e_type - in - - let rec traverse e = - match e.eexpr with - | TBlock el -> - let new_block = ref [] in - let rec process_statement e = - let e = no_paren e in - match e.eexpr, shallow_expr_type e with - | TVars( (hd1 :: hd2 :: _) as vars ), _ -> - List.iter (fun v -> process_statement { e with eexpr = TVars([v]) }) vars - | TCall( { eexpr = TLocal v } as elocal, elist ), _ when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> - new_block := { e with eexpr = TCall( elocal, List.map (fun e -> - match e.eexpr with - | TBlock _ -> traverse e - | _ -> e - ) elist ) } :: !new_block - | _, Statement | _, Both _ -> - let e = match e.eexpr with | TReturn (Some ({ eexpr = TThrow _ } as ethrow)) -> ethrow | _ -> e in - let kinds = get_kinds e in - if has_problematic_expressions kinds then begin - match try_call_unwrap_statement gen problematic_expression_unwrap add_statement e with - | Some { eexpr = TConst(TNull) } (* no op *) - | Some { eexpr = TBlock [] } -> () - | Some e -> - if has_problematic_expressions (get_kinds e) then begin - process_statement e - end else - new_block := (traverse e) :: !new_block - | None -> - ( - let acc = ref kinds in - let new_e = expr_stat_map (fun e -> - match !acc with - | hd :: tl -> - acc := tl; - if has_problematic_expressions (hd :: tl) then begin - problematic_expression_unwrap add_statement e hd - end else - e - | [] -> assert false - ) e in - - new_block := (traverse new_e) :: !new_block - ) - end else begin new_block := (traverse e) :: !new_block end - | _, Expression e -> - match on_expr_as_statement e with - | None -> () - | Some e -> process_statement e - and add_statement expr = - process_statement expr - in - - List.iter (process_statement) el; - let block = List.rev !new_block in - { e with eexpr = TBlock(block) } - | TTry (block, catches) -> - { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) } - | TMatch (cond,ep,il_vol_e_l,default) -> - { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } - | TSwitch (cond,el_e_l, default) -> - { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) } - | TWhile (cond,block,flag) -> - {e with eexpr = TWhile(cond,traverse (mk_block block), flag) } - | TIf (cond, eif, eelse) -> - { e with eexpr = TIf(cond, traverse (mk_block eif), Option.map (fun e -> traverse (mk_block e)) eelse) } - | TFor (v,it,block) -> - { e with eexpr = TFor(v,it, traverse (mk_block block)) } - | TFunction (tfunc) -> - { e with eexpr = TFunction({ tfunc with tf_expr = traverse (mk_block tfunc.tf_expr) }) } - | _ -> e (* if expression doesn't have a block, we will exit *) - in - traverse - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "expression_unwrap" + + (* priority: first syntax filter *) + let priority = -10.0 + + (* + We always need to rely on Blocks to be able to unwrap expressions correctly. + So the the standard traverse will always be based on blocks. + Normal block statements, like for(), while(), if(), ... will be mk_block'ed so there is always a block inside of them. + + At the block level, we'll define an "add_statement" function, which will allow the current expression to + add statements to the block. This statement may or may not contain statements as expressions, so the texpr will be evaluated recursively before being added. + + - traverse will always evaluate TBlocks + - for each texpr in a TBlock list, + check shallow type + if type is Statement or Both when it has problematic expression (var problematic_expr = count_problematic_expressions), + if we can eagerly call unwrap_statement on the whole expression (try_call_unwrap_statement), use the return expression + else + check expr_type of each underlying type (with expr_stat_map) + if it has ExprWithStatement or Statement, + call problematic_expression_unwrap in it + problematic_expr-- + else if problematic_expr == 0, just add the unchanged expression + else if NoSideEffects and doesn't have short-circuit, just add the unchanged expression + else call problematic_expression_unwrap in it + if type is Expression, check if there are statements or Both inside. + if there are, problematic_expression_unwrap in it + aftewards, use on_expr_as_statement to get it + + helpers: + try_call_unwrap_statement: (returns texpr option) + if underlying statement is TBinop(OpAssign/OpAssignOp), or TVar, with the right side being a Statement or a short circuit op, we can call apply_assign. + + apply_assign: + if is TVar, first declare the tvar with default expression = null; + will receive the left and right side of the assignment; right-side must be Statement + see if right side is a short-circuit operation, call short_circuit_op_unwrap + else see eexpr of the right side + if it's void, just add the statement with add_statement, and set the right side as null; + if not, it will have a block inside. set the left side = to the last expression on each block inside. add_statement for it. + + short_circuit_op_unwrap: x() && (1 + {var x = 0; x + 1;} == 2) && z() + -> var x = x(); + var y = false; + var z = false; + if (x) //for &&, neg for || + { + var temp = null; + { + var x = 0; + temp = x + 1; + } + + y = (1 + temp) == 2; + if (y) + { + z = z(); + } + } + expects to receive a texpr with TBinop(OpBoolAnd/OpBoolOr) + will traverse the AST while there is a TBinop(OpBoolAnd/OpBoolOr) as a right-side expr, and declare new temp vars in the for each found. + will collect the return value, a mapped expr with all exprs as TLocal of the temp vars created + + + problematic_expression_unwrap: + check expr_kind: + if it is NoSideEffects and not short-circuit, leave it there + if it is ExprWithStatement and not short-circuit, call Type.map_expr problematic_expression_unwrap + if it is Statement or Expression or short-circuit expr, call add_assign for this expression + + add_assign: + see if the type is void. If it is, just add_statement the expression argument, and return a null value + else create a new variable, set TVar with Some() with the expression argument, add TVar with add_statement, and return the TLocal of this expression. + + map_problematic_expr: + call expr_stat_map on statement with problematic_expression_unwrap + + types: + type shallow_expr_type = | Statement | Expression | Both (* shallow expression classification. Both means that they can be either Statements as Expressions *) + + type expr_kind = | NormalExpr | ExprNoSideEffects (* -> short-circuit is considered side-effects *) | ExprWithStatement | Statement + evaluates an expression (as in not a statement) type. If it is ExprWithStatement or Statement, it means it contains errors + + functions: + shallow_expr_type (expr:texpr) : shallow_expr_type + + expr_kind (expr:texpr) : expr_kind + deeply evaluates an expression type + + expr_stat_map (fn:texpr->texpr) (expr:texpr) : texpr + it will traverse the AST looking for places where an expression is expected, and map the value according to fn + + aggregate_expr_type (is_side_effects_free:bool) (children:expr_type list) : expr_type + helper function to deal with expr_type aggregation (e.g. an Expression + a Statement as a children, is a ExprWithStatement) + + check_statement_in_expression (expr:texpr) : texpr option : + will check + + *) + + type shallow_expr_type = | Statement | Expression of texpr | Both of texpr (* shallow expression classification. Both means that they can be either Statements as Expressions *) + + type expr_kind = | KNormalExpr | KNoSideEffects (* -> short-circuit is considered side-effects *) | KExprWithStatement | KStatement + + let rec no_paren e = + match e.eexpr with + | TParenthesis e -> no_paren e + | _ -> e + + (* must be called in a statement. Will execute fn whenever an expression (not statement) is expected *) + let rec expr_stat_map fn (expr:texpr) = + match (no_paren expr).eexpr with + | TBinop ( (Ast.OpAssign as op), left_e, right_e ) + | TBinop ( (Ast.OpAssignOp _ as op), left_e, right_e ) -> + { expr with eexpr = TBinop(op, fn left_e, fn right_e) } + | TParenthesis _ -> assert false + | TCall(left_e, params) -> + { expr with eexpr = TCall(fn left_e, List.map fn params) } + | TNew(cl, tparams, params) -> + { expr with eexpr = TNew(cl, tparams, List.map fn params) } + | TVar(v,eopt) -> + { expr with eexpr = TVar(v, Option.map fn eopt) } + | TFor (v,cond,block) -> + { expr with eexpr = TFor(v, fn cond, block) } + | TIf(cond,eif,eelse) -> + { expr with eexpr = TIf(fn cond, eif, eelse) } + | TWhile(cond, block, flag) -> + { expr with eexpr = TWhile(fn cond, block, flag) } + | TSwitch(cond, el_block_l, default) -> + { expr with eexpr = TSwitch( fn cond, List.map (fun (el,block) -> (List.map fn el, block)) el_block_l, default ) } +(* | TMatch(cond, enum, cases, default) -> + { expr with eexpr = TMatch(fn cond, enum, cases, default) } *) + | TReturn(eopt) -> + { expr with eexpr = TReturn(Option.map fn eopt) } + | TThrow (texpr) -> + { expr with eexpr = TThrow(fn texpr) } + | TBreak + | TContinue + | TTry _ + | TUnop (Ast.Increment, _, _) + | TUnop (Ast.Decrement, _, _) (* unop is a special case because the haxe compiler won't let us generate complex expressions with Increment/Decrement *) + | 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 *) + + let is_expr = function | Expression _ -> true | _ -> false + + let aggregate_expr_type map_fn side_effects_free children = + let rec loop acc children = + match children with + | [] -> acc + | hd :: children -> + match acc, map_fn hd with + | _, KExprWithStatement + | _, KStatement + | KExprWithStatement, _ + | KStatement, _ -> KExprWithStatement + | KNormalExpr, KNoSideEffects + | KNoSideEffects, KNormalExpr + | KNormalExpr, KNormalExpr -> loop KNormalExpr children + | KNoSideEffects, KNoSideEffects -> loop KNoSideEffects children + in + loop (if side_effects_free then KNoSideEffects else KNormalExpr) children + + (* statements: *) + (* Error CS0201: Only assignment, call, increment, *) + (* decrement, and new object expressions can be used as a *) + (* statement (CS0201). *) + let rec shallow_expr_type expr : shallow_expr_type = + match expr.eexpr with + | TCall _ when not (is_void expr.etype) -> Both expr + | TNew _ + | TUnop (Ast.Increment, _, _) + | TUnop (Ast.Decrement, _, _) + | TBinop (Ast.OpAssign, _, _) + | TBinop (Ast.OpAssignOp _, _, _) -> Both expr + | TIf (cond, eif, Some(eelse)) -> (match aggregate_expr_type expr_kind true [cond;eif;eelse] with + | KExprWithStatement -> Statement + | _ -> Both expr) + | TConst _ + | TLocal _ + | TArray _ + | TBinop _ + | TField _ + | TEnumParameter _ + | TTypeExpr _ + | TObjectDecl _ + | TArrayDecl _ + | TFunction _ + | TCast _ + | TUnop _ -> Expression (expr) + | TParenthesis p | TMeta(_,p) -> shallow_expr_type p + | TBlock ([e]) -> shallow_expr_type e + | TCall _ + | TVar _ + | TBlock _ + | TFor _ + | TWhile _ + | TSwitch _ + | TTry _ + | TReturn _ + | TBreak + | TContinue + | TIf _ + | TThrow _ -> Statement + + and expr_kind expr = + match shallow_expr_type expr with + | Statement -> KStatement + | Both expr | Expression expr -> + let aggregate = aggregate_expr_type expr_kind in + match expr.eexpr with + | TConst _ + | TLocal _ + | TFunction _ + | TTypeExpr _ -> + KNoSideEffects + | TCall (ecall, params) -> + aggregate false (ecall :: params) + | TNew (_,_,params) -> + aggregate false params + | TUnop (Increment,_,e) + | TUnop (Decrement,_,e) -> + aggregate false [e] + | TUnop (_,_,e) -> + aggregate true [e] + | TBinop (Ast.OpBoolAnd, e1, e2) + | TBinop (Ast.OpBoolOr, e1, e2) -> (* TODO: should OpBool never be side-effects free? *) + aggregate true [e1;e2] + | TBinop (Ast.OpAssign, e1, e2) + | TBinop (Ast.OpAssignOp _, e1, e2) -> + aggregate false [e1;e2] + | TBinop (_, e1, e2) -> + aggregate true [e1;e2] + | TIf (cond, eif, Some(eelse)) -> (match aggregate true [cond;eif;eelse] with + | KExprWithStatement -> KStatement + | k -> k) + | TArray (e1,e2) -> + aggregate true [e1;e2] + | TParenthesis e + | TMeta(_,e) + | TField (e,_) -> + aggregate true [e] + | TArrayDecl (el) -> + aggregate true el + | TObjectDecl (sel) -> + aggregate true (List.map snd sel) + | TCast (e,_) -> + aggregate true [e] + | _ -> trace (debug_expr expr); assert false (* should have been read as Statement by shallow_expr_type *) + + let is_side_effects_free e = + match expr_kind e with | KNoSideEffects -> true | _ -> false + + let get_kinds (statement:texpr) = + let kinds = ref [] in + ignore (expr_stat_map (fun e -> + kinds := (expr_kind e) :: !kinds; + e + ) statement); + List.rev !kinds + + let has_problematic_expressions (kinds:expr_kind list) = + let rec loop kinds = + match kinds with + | [] -> false + | KStatement :: _ + | KExprWithStatement :: _ -> true + | _ :: tl -> loop tl + in + loop kinds + + let count_problematic_expressions (statement:texpr) = + let count = ref 0 in + ignore (expr_stat_map (fun e -> + (match expr_kind e with + | KStatement | KExprWithStatement -> incr count + | _ -> () + ); + e + ) statement); + !count + + let apply_assign_block assign_fun elist = + let rec assign acc elist = + match elist with + | [] -> acc + | last :: [] -> + (assign_fun last) :: acc + | hd :: tl -> + assign (hd :: acc) tl + in + List.rev (assign [] elist) + + let mk_get_block assign_fun e = + match e.eexpr with + | TBlock [] -> e + | TBlock (el) -> + { e with eexpr = TBlock(apply_assign_block assign_fun el) } + | _ -> + { e with eexpr = TBlock([ assign_fun e ]) } + + let add_assign gen add_statement expr = + match expr.eexpr, follow expr.etype with + | _, TAbstract ({ a_path = ([],"Void") },[]) + | TThrow _, _ -> + add_statement expr; + null expr.etype expr.epos + | _ -> + let var = mk_temp gen "stmt" expr.etype in + let tvars = { expr with eexpr = TVar(var,Some(expr)) } in + let local = { expr with eexpr = TLocal(var) } in + add_statement tvars; + local + + (* requirement: right must be a statement *) + let rec apply_assign assign_fun right = + match right.eexpr with + | TBlock el -> + { right with eexpr = TBlock(apply_assign_block assign_fun el) } + | TSwitch (cond, elblock_l, default) -> + { right with eexpr = TSwitch(cond, List.map (fun (el,block) -> (el, mk_get_block assign_fun block)) elblock_l, Option.map (mk_get_block assign_fun) default) } +(* | TMatch (cond, ep, il_vlo_e_l, default) -> + { right with eexpr = TMatch(cond, ep, List.map (fun (il,vlo,e) -> (il,vlo,mk_get_block assign_fun e)) il_vlo_e_l, Option.map (mk_get_block assign_fun) default) } *) + | TTry (block, catches) -> + { right with eexpr = TTry(mk_get_block assign_fun block, List.map (fun (v,block) -> (v,mk_get_block assign_fun block) ) catches) } + | TIf (cond,eif,eelse) -> + { right with eexpr = TIf(cond, mk_get_block assign_fun eif, Option.map (mk_get_block assign_fun) eelse) } + | TThrow _ + | TWhile _ + | TFor _ + | TReturn _ + | TBreak + | TContinue -> right + | TParenthesis p | TMeta(_,p) -> + apply_assign assign_fun p + | TVar _ -> + right + | _ -> + match follow right.etype with + | TAbstract ({ a_path = ([], "Void") },[]) -> + right + | _ -> trace (debug_expr right); assert false (* a statement is required *) + + let short_circuit_op_unwrap gen add_statement expr :texpr = + let do_not expr = + { expr with eexpr = TUnop(Ast.Not, Ast.Prefix, expr) } + in + + (* loop will always return its own TBlock, and the mapped expression *) + let rec loop acc expr = + match expr.eexpr with + | TBinop ( (Ast.OpBoolAnd as op), left, right) -> + let var = mk_temp gen "boolv" right.etype in + let tvars = { right with eexpr = TVar(var, Some( { right with eexpr = TConst(TBool false); etype = gen.gcon.basic.tbool } )); etype = gen.gcon.basic.tvoid } in + let local = { right with eexpr = TLocal(var) } in + + let mapped_left, ret_acc = loop ( (local, { right with eexpr = TBinop(Ast.OpAssign, local, right) } ) :: acc) left in + + add_statement tvars; + ({ expr with eexpr = TBinop(op, mapped_left, local) }, ret_acc) + (* we only accept OpBoolOr when it's the first to be evaluated *) + | TBinop ( (Ast.OpBoolOr as op), left, right) when acc = [] -> + let left = match left.eexpr with + | TLocal _ | TConst _ -> left + | _ -> add_assign gen add_statement left + in + + let var = mk_temp gen "boolv" right.etype in + let tvars = { right with eexpr = TVar(var, Some( { right with eexpr = TConst(TBool false); etype = gen.gcon.basic.tbool } )); etype = gen.gcon.basic.tvoid } in + let local = { right with eexpr = TLocal(var) } in + add_statement tvars; + + ({ expr with eexpr = TBinop(op, left, local) }, [ do_not left, { right with eexpr = TBinop(Ast.OpAssign, local, right) } ]) + | _ when acc = [] -> assert false + | _ -> + let var = mk_temp gen "boolv" expr.etype in + let tvars = { expr with eexpr = TVar(var, Some( { expr with etype = gen.gcon.basic.tbool } )); etype = gen.gcon.basic.tvoid } in + let local = { expr with eexpr = TLocal(var) } in + + let last_local = ref local in + let acc = List.map (fun (local, assign) -> + let l = !last_local in + last_local := local; + (l, assign) + ) acc in + + add_statement tvars; + (local, acc) + in + + let mapped_expr, local_assign_list = loop [] expr in + + let rec loop local_assign_list : texpr = + match local_assign_list with + | [local, assign] -> + { eexpr = TIf(local, assign, None); etype = gen.gcon.basic.tvoid; epos = assign.epos } + | (local, assign) :: tl -> + { eexpr = TIf(local, + { + eexpr = TBlock ( assign :: [loop tl] ); + etype = gen.gcon.basic.tvoid; + epos = assign.epos; + }, + None); etype = gen.gcon.basic.tvoid; epos = assign.epos } + | [] -> assert false + in + + add_statement (loop local_assign_list); + mapped_expr + + (* there are two short_circuit fuctions as I'm still testing the best way to do it *) + (*let short_circuit_op_unwrap gen add_statement expr :texpr = + let block = ref [] in + let rec short_circuit_op_unwrap is_first last_block expr = + match expr.eexpr with + | TBinop ( (Ast.OpBoolAnd as op), left, right) + | TBinop ( (Ast.OpBoolOr as op), left, right) -> + let var = mk_temp gen "boolv" left.etype in + let tvars = { left with eexpr = TVar([var, if is_first then Some(left) else Some( { left with eexpr = TConst(TBool false) } )]); etype = gen.gcon.basic.tvoid } in + let local = { left with eexpr = TLocal(var) } in + if not is_first then begin + last_block := !last_block @ [ { left with eexpr = TBinop(Ast.OpAssign, local, left) } ] + end; + + add_statement tvars; + let local_op = match op with | Ast.OpBoolAnd -> local | Ast.OpBoolOr -> { local with eexpr = TUnop(Ast.Not, Ast.Prefix, local) } | _ -> assert false in + + let new_block = ref [] in + let new_right = short_circuit_op_unwrap false new_block right in + last_block := !last_block @ [ { expr with eexpr = TIf(local_op, { right with eexpr = TBlock(!new_block) }, None) } ]; + + { expr with eexpr = TBinop(op, local, new_right) } + | _ when is_first -> assert false + | _ -> + let var = mk_temp gen "boolv" expr.etype in + let tvars = { expr with eexpr = TVar([var, Some ( { expr with eexpr = TConst(TBool false) } ) ]); etype = gen.gcon.basic.tvoid } in + let local = { expr with eexpr = TLocal(var) } in + last_block := !last_block @ [ { expr with eexpr = TBinop(Ast.OpAssign, local, expr) } ]; + add_statement tvars; + + local + in + let mapped_expr = short_circuit_op_unwrap true block expr in + add_statement { eexpr = TBlock(!block); etype = gen.gcon.basic.tvoid; epos = expr.epos }; + mapped_expr*) + + let twhile_with_condition_statement gen add_statement twhile cond e1 flag = + (* when a TWhile is found with a problematic condition *) + let basic = gen.gcon.basic in + + let block = if flag = Ast.NormalWhile then + { e1 with eexpr = TIf(cond, e1, Some({ e1 with eexpr = TBreak; etype = basic.tvoid })) } + else + Type.concat e1 { e1 with + eexpr = TIf({ + eexpr = TUnop(Ast.Not, Ast.Prefix, mk_paren cond); + etype = basic.tbool; + epos = cond.epos + }, { e1 with eexpr = TBreak; etype = basic.tvoid }, None); + etype = basic.tvoid + } + in + + add_statement { twhile with + eexpr = TWhile( + { eexpr = TConst(TBool true); etype = basic.tbool; epos = cond.epos }, + block, + Ast.DoWhile + ); + } + + let try_call_unwrap_statement gen problematic_expression_unwrap (add_statement:texpr->unit) (expr:texpr) : texpr option = + let check_left left = + 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 *) + | _ -> left + in + + let handle_assign op left right = + let left = check_left left in + Some (apply_assign (fun e -> { e with eexpr = TBinop(op, left, if is_void left.etype then e else gen.ghandle_cast left.etype e.etype e) }) right ) + in + + let handle_return e = + Some( apply_assign (fun e -> + match e.eexpr with + | TThrow _ -> e + | _ when is_void e.etype -> + { e with eexpr = TBlock([e; { e with eexpr = TReturn None }]) } + | _ -> + { e with eexpr = TReturn( Some e ) } + ) e ) + in + + let is_problematic_if right = + match expr_kind right with + | KStatement | KExprWithStatement -> true + | _ -> false + in + + match expr.eexpr with + | TBinop((Ast.OpAssign as op),left,right) + | TBinop((Ast.OpAssignOp _ as op),left,right) when shallow_expr_type right = Statement -> + handle_assign op left right + | TReturn( Some right ) when shallow_expr_type right = Statement -> + handle_return right + | TBinop((Ast.OpAssign as op),left, ({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right) ) + | TBinop((Ast.OpAssign as op),left,({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right)) + | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right) ) + | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right) ) -> + let right = short_circuit_op_unwrap gen add_statement right in + Some { expr with eexpr = TBinop(op, check_left left, right) } + | TVar(v,Some({ eexpr = TBinop(Ast.OpBoolAnd,_,_) } as right)) + | TVar(v,Some({ eexpr = TBinop(Ast.OpBoolOr,_,_) } as right)) -> + let right = short_circuit_op_unwrap gen add_statement right in + Some { expr with eexpr = TVar(v, Some(right)) } + | TVar(v,Some(right)) when shallow_expr_type right = Statement -> + add_statement ({ expr with eexpr = TVar(v, Some(null right.etype right.epos)) }); + handle_assign Ast.OpAssign { expr with eexpr = TLocal(v); etype = v.v_type } right + (* TIf handling *) + | TBinop((Ast.OpAssign as op),left, ({ eexpr = TIf _ } as right)) + | TBinop((Ast.OpAssignOp _ as op),left,({ eexpr = TIf _ } as right)) when is_problematic_if right -> + handle_assign op left right + | TVar(v,Some({ eexpr = TIf _ } as right)) when is_problematic_if right -> + add_statement ({ expr with eexpr = TVar(v, Some(null right.etype right.epos)) }); + handle_assign Ast.OpAssign { expr with eexpr = TLocal(v); etype = v.v_type } right + | TWhile(cond, e1, flag) when is_problematic_if cond -> + twhile_with_condition_statement gen add_statement expr cond e1 flag; + Some (null expr.etype expr.epos) + | _ -> None + + + let traverse gen (on_expr_as_statement:texpr->texpr option) = + + let add_assign = add_assign gen in + + let problematic_expression_unwrap add_statement expr e_type = + let rec problematic_expression_unwrap is_first expr e_type = + match e_type, expr.eexpr with + | _, TBinop(Ast.OpBoolAnd, _, _) + | _, TBinop(Ast.OpBoolOr, _, _) -> add_assign add_statement expr (* add_assign so try_call_unwrap_expr *) + | KNoSideEffects, _ -> expr + | KStatement, _ + | KNormalExpr, _ -> add_assign add_statement expr + | KExprWithStatement, TCall _ + | KExprWithStatement, TNew _ + | KExprWithStatement, TBinop (Ast.OpAssign,_,_) + | KExprWithStatement, TBinop (Ast.OpAssignOp _,_,_) + | KExprWithStatement, TUnop (Ast.Increment,_,_) (* all of these may have side-effects, so they must also be add_assign'ed . is_first avoids infinite loop *) + | KExprWithStatement, TUnop (Ast.Decrement,_,_) when not is_first -> add_assign add_statement expr + + (* bugfix: Type.map_expr doesn't guarantee the correct order of execution *) + | KExprWithStatement, TBinop(op,e1,e2) -> + let e1 = problematic_expression_unwrap false e1 (expr_kind e1) in + let e2 = problematic_expression_unwrap false e2 (expr_kind e2) in + { expr with eexpr = TBinop(op, e1, e2) } + | KExprWithStatement, TArray(e1,e2) -> + let e1 = problematic_expression_unwrap false e1 (expr_kind e1) in + let e2 = problematic_expression_unwrap false e2 (expr_kind e2) in + { expr with eexpr = TArray(e1, e2) } + (* bugfix: calls should not be transformed into closure calls *) + | KExprWithStatement, TCall(( { eexpr = TField (ef_left, f) } as ef ), eargs) -> + { expr with eexpr = TCall( + { ef with eexpr = TField(problematic_expression_unwrap false ef_left (expr_kind ef_left), f) }, + List.map (fun e -> problematic_expression_unwrap false e (expr_kind e)) eargs) + } + | KExprWithStatement, _ -> Type.map_expr (fun e -> problematic_expression_unwrap false e (expr_kind e)) expr + in + problematic_expression_unwrap true expr e_type + in + + let rec traverse e = + match e.eexpr with + | TBlock el -> + let new_block = ref [] in + let rec process_statement e = + let e = no_paren e in + match e.eexpr, shallow_expr_type e with + | TCall( { eexpr = TLocal v } as elocal, elist ), _ when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> + new_block := { e with eexpr = TCall( elocal, List.map (fun e -> + match e.eexpr with + | TBlock _ -> traverse e + | _ -> e + ) elist ) } :: !new_block + | _, Statement | _, Both _ -> + let e = match e.eexpr with | TReturn (Some ({ eexpr = TThrow _ } as ethrow)) -> ethrow | _ -> e in + let kinds = get_kinds e in + if has_problematic_expressions kinds then begin + match try_call_unwrap_statement gen problematic_expression_unwrap add_statement e with + | Some { eexpr = TConst(TNull) } (* no op *) + | Some { eexpr = TBlock [] } -> () + | Some e -> + if has_problematic_expressions (get_kinds e) then begin + process_statement e + end else + new_block := (traverse e) :: !new_block + | None -> + ( + let acc = ref kinds in + let new_e = expr_stat_map (fun e -> + match !acc with + | hd :: tl -> + acc := tl; + if has_problematic_expressions (hd :: tl) then begin + problematic_expression_unwrap add_statement e hd + end else + e + | [] -> assert false + ) e in + + new_block := (traverse new_e) :: !new_block + ) + end else begin new_block := (traverse e) :: !new_block end + | _, Expression e -> + match on_expr_as_statement e with + | None -> () + | Some e -> process_statement e + and add_statement expr = + process_statement expr + in + + List.iter (process_statement) el; + let block = List.rev !new_block in + { e with eexpr = TBlock(block) } + | TTry (block, catches) -> + { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) } +(* | TMatch (cond,ep,il_vol_e_l,default) -> + { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } *) + | TSwitch (cond,el_e_l, default) -> + { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) } + | TWhile (cond,block,flag) -> + {e with eexpr = TWhile(cond,traverse (mk_block block), flag) } + | TIf (cond, eif, eelse) -> + { e with eexpr = TIf(cond, traverse (mk_block eif), Option.map (fun e -> traverse (mk_block e)) eelse) } + | TFor (v,it,block) -> + { e with eexpr = TFor(v,it, traverse (mk_block block)) } + | TFunction (tfunc) -> + { e with eexpr = TFunction({ tfunc with tf_expr = traverse (mk_block tfunc.tf_expr) }) } + | _ -> e (* if expression doesn't have a block, we will exit *) + in + traverse + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -5129,924 +5753,1073 @@ end;; (* - Will detect implicit casts and add TCast for them. Since everything is already followed by follow_all, typedefs are considered a new type altogether + Will detect implicit casts and add TCast for them. Since everything is already followed by follow_all, typedefs are considered a new type altogether - Types shouldn't be cast if: - * When an instance is being coerced to a superclass or to an implemented interface - * When anything is being coerced to Dynamic + Types shouldn't be cast if: + * When an instance is being coerced to a superclass or to an implemented interface + * When anything is being coerced to Dynamic - edit: - As a matter of performance, we will also run the type parameters casts in here. Otherwise the exact same computation would have to be performed twice, - with maybe even some loss of information + edit: + As a matter of performance, we will also run the type parameters casts in here. Otherwise the exact same computation would have to be performed twice, + with maybe even some loss of information - * TAnon / TDynamic will call - * Type parameter handling will be abstracted + * TAnon / TDynamic will call + * Type parameter handling will be abstracted - dependencies: - Must run before ExpressionUnwrap + dependencies: + Must run before ExpressionUnwrap *) module CastDetect = struct - let name = "cast_detect_2" - - let priority = solve_deps name [DBefore TypeParams.priority; DBefore ExpressionUnwrap.priority] - - (* ******************************************* *) - (* ReturnCast *) - (* ******************************************* *) - - (* - - Cast detection for return types can't be done at CastDetect time, since we need an - unwrapped expression to make sure we catch all return cast detections. So this module - is specifically to deal with that, and is configured automatically by CastDetect - - dependencies: - - - *) - - module ReturnCast = - struct - - let name = "return_cast" - - let priority = solve_deps name [DAfter priority; DAfter ExpressionUnwrap.priority] - - let default_implementation gen = - let rec extract_expr e = match e.eexpr with - | TParenthesis e - | TCast(e,_) -> extract_expr e - | _ -> e - in - let current_ret_type = ref None in - let handle e tto tfrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type tfrom) e in - let in_value = ref false in - - let rec run e = - let was_in_value = !in_value in - in_value := true; - 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 - (match eopt with - | None when not (is_void ret_type) -> - { e with eexpr = TReturn( Some(null ret_type e.epos)) } - | None -> e - | Some eret -> - { e with eexpr = TReturn( Some(handle (run eret) ret_type eret.etype ) ) }) - | TFunction(tfunc) -> - let last_ret = !current_ret_type in - current_ret_type := Some(tfunc.tf_type); - let ret = Type.map_expr run e in - current_ret_type := last_ret; - ret - | TBlock el -> - { e with eexpr = TBlock ( List.map (fun e -> in_value := false; run e) el ) } - | TBinop ( (Ast.OpAssign as op),e1,e2) - | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) when was_in_value -> - let e1 = extract_expr (run e1) in - let r = { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } in - handle r e.etype e1.etype - | TBinop ( (Ast.OpAssign as op),({ eexpr = TField(tf, f) } as e1), e2 ) - | TBinop ( (Ast.OpAssignOp _ as op),({ eexpr = TField(tf, f) } as e1), e2 ) -> - (match field_access gen (gen.greal_type tf.etype) (field_name f) with - | FClassField(cl,params,_,_,is_static,actual_t,_) -> - let actual_t = if is_static then actual_t else apply_params cl.cl_types params actual_t in - let e1 = extract_expr (run e1) in - { e with eexpr = TBinop(op, e1, handle (run e2) actual_t e2.etype); etype = e1.etype } - | _ -> - let e1 = extract_expr (run e1) in - { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } - ) - | TBinop ( (Ast.OpAssign as op),e1,e2) - | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) -> - let e1 = extract_expr (run e1) in - { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } - | _ -> Type.map_expr run e - in - run - - let configure gen = - let map e = Some(default_implementation gen e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map - - end;; - - let get_args t = match follow t with - | TFun(args,ret) -> args,ret - | _ -> trace (debug_type t); assert false - - let s_path (pack,n) = (String.concat "." (pack @ [n])) - - (* - Since this function is applied under native-context only, the type paraters will already be changed - *) - let map_cls gen also_implements fn super = - let rec loop c tl = - if c == super then - fn c tl - else (match c.cl_super with - | None -> false - | Some (cs,tls) -> - let tls = gen.greal_type_param (TClassDecl cs) tls in - loop cs (List.map (apply_params c.cl_types tl) tls) - ) || (if also_implements then List.exists (fun (cs,tls) -> - loop cs (List.map (apply_params c.cl_types tl) tls) - ) c.cl_implements else false) - in - loop - - let follow_dyn t = match follow t with - | TMono _ | TLazy _ -> t_dynamic - | t -> t - - (* - this has a slight change from the type.ml version, in which it doesn't - change a TMono into the other parameter - *) - let rec type_eq gen param a b = - if a == b then - () - else match follow_dyn (gen.greal_type a) , follow_dyn (gen.greal_type b) with - | TEnum (e1,tl1) , TEnum (e2,tl2) -> - if e1 != e2 && not (param = EqCoreType && e1.e_path = e2.e_path) then Type.error [cannot_unify a b]; - List.iter2 (type_eq gen param) tl1 tl2 - | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> - if a1 != a2 && not (param = EqCoreType && a1.a_path = a2.a_path) then Type.error [cannot_unify a b]; - List.iter2 (type_eq gen param) 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 Type.error [cannot_unify a b]; - List.iter2 (type_eq gen param) tl1 tl2 - | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> - (try - type_eq gen param r1 r2; - List.iter2 (fun (n,o1,t1) (_,o2,t2) -> - if o1 <> o2 then Type.error [Not_matching_optional n]; - type_eq gen param t1 t2 - ) l1 l2 - with - Unify_error l -> Type.error (cannot_unify a b :: l)) - | TDynamic a , TDynamic b -> - type_eq gen param a b - | TAnon a1, TAnon a2 -> - (try - 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 Type.error [invalid_kind n f1.cf_kind f2.cf_kind]; - try - type_eq gen param f1.cf_type f2.cf_type - with - Unify_error l -> Type.error (invalid_field n :: l) - 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]; - 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]; - a1.a_fields <- PMap.add n f2 a1.a_fields - end; - ) a2.a_fields; - with - Unify_error l -> Type.error (cannot_unify a b :: l)) - | _ , _ -> - if b == t_dynamic && (param = EqRightDynamic || param = EqBothDynamic) then - () - else if a == t_dynamic && param = EqBothDynamic then - () - else - Type.error [cannot_unify a b] - - let type_iseq gen a b = - try - type_eq gen EqStrict a b; - true - with - Unify_error _ -> false - - (* will return true if both arguments are compatible. If it's not the case, a runtime error is very likely *) - let is_cl_related gen cl tl super superl = - let is_cl_related cl tl super superl = map_cls gen (gen.guse_tp_constraints || (match cl.cl_kind,super.cl_kind with KTypeParameter _, _ | _,KTypeParameter _ -> false | _ -> true)) (fun _ _ -> true) super cl tl in - is_cl_related cl tl super superl || is_cl_related super superl cl tl - - - let rec is_unsafe_cast gen to_t from_t = - match (follow to_t, follow from_t) with - | TInst(cl_to, to_params), TInst(cl_from, from_params) -> - not (is_cl_related gen cl_from from_params cl_to to_params) - | TEnum(e_to, _), TEnum(e_from, _) -> - e_to.e_path <> e_from.e_path - | TFun _, TFun _ -> - (* functions are never unsafe cast by default. This behavior might be changed *) - (* with a later AST pass which will run through TFun to TFun casts *) - false - | TMono _, _ - | _, TMono _ - | TDynamic _, _ - | _, TDynamic _ -> - false - | TAnon _, _ - | _, TAnon _ -> - (* anonymous are never unsafe also. *) - (* Though they will generate a cast, so if this cast is unneeded it's better to avoid them by tweaking gen.greal_type *) - false - | TAbstract _, _ - | _, TAbstract _ -> - (try - unify from_t to_t; - false - with | Unify_error _ -> - try - unify to_t from_t; (* still not unsafe *) - false - with | Unify_error _ -> - true) - | _ -> true - - let do_unsafe_cast gen from_t to_t e = - let t_path t = - match t with - | TInst(cl, _) -> cl.cl_path - | TEnum(e, _) -> e.e_path - | TType(t, _) -> t.t_path - | TAbstract(a, _) -> a.a_path - | TDynamic _ -> ([], "Dynamic") - | _ -> raise Not_found - in - let do_default () = - gen.gon_unsafe_cast to_t e.etype e.epos; - mk_cast to_t (mk_cast t_dynamic e) - in - (* TODO: there really should be a better way to write that *) - try - if (Hashtbl.find gen.gsupported_conversions (t_path from_t)) from_t to_t then - mk_cast to_t e - else - do_default() - with - | Not_found -> - try - if (Hashtbl.find gen.gsupported_conversions (t_path to_t)) from_t to_t then - mk_cast to_t e - else - do_default() - with - | Not_found -> do_default() - - (* ****************************** *) - (* cast handler *) - (* decides if a cast should be emitted, given a from and a to type *) - (* - this function is like a mini unify, without e.g. subtyping, which makes sense - at the backend level, since most probably Anons and TInst will have a different representation there - *) - let rec handle_cast gen e real_to_t real_from_t = - let do_unsafe_cast () = do_unsafe_cast gen real_from_t real_to_t { e with etype = real_from_t } in - let to_t, from_t = real_to_t, real_from_t in - - let mk_cast t e = - match e.eexpr with - (* TThrow is always typed as Dynamic, we just need to type it accordingly *) - | TThrow _ -> { e with etype = t } - | _ -> mk_cast t e - in - - let e = { e with etype = real_from_t } in - if try fast_eq real_to_t real_from_t with Invalid_argument("List.for_all2") -> false then e else - match real_to_t, real_from_t with - (* string is the only type that can be implicitly converted from any other *) - | TInst( { cl_path = ([], "String") }, []), _ -> - mk_cast to_t e - | TInst(cl_to, params_to), TInst(cl_from, params_from) -> - let ret = ref None in - (* - this is a little confusing: - we are here mapping classes until we have the same to and from classes, applying the type parameters in each step, so we can - compare the type parameters; - - If a class is found - meaning that the cl_from can be converted without a cast into cl_to, - we still need to check their type parameters. - *) - ignore (map_cls gen (gen.guse_tp_constraints || (match cl_from.cl_kind,cl_to.cl_kind with KTypeParameter _, _ | _,KTypeParameter _ -> false | _ -> true)) (fun _ tl -> - try - (* type found, checking type parameters *) - List.iter2 (type_eq gen EqStrict) tl params_to; - ret := Some e; - true - with | Unify_error _ -> - (* type parameters need casting *) - if gen.ghas_tparam_cast_handler then begin - (* - if we are already handling type parameter casts on other part of code (e.g. RealTypeParameters), - we'll just make a cast to indicate that this place needs type parameter-involved casting - *) - ret := Some (mk_cast to_t e); - true - end else - (* - if not, we're going to check if we only need a simple cast, - or if we need to first cast into the dynamic version of it - *) - try - List.iter2 (type_eq gen EqRightDynamic) tl params_to; - ret := Some (mk_cast to_t e); - true - with | Unify_error _ -> - ret := Some (mk_cast to_t (mk_cast (TInst(cl_to, List.map (fun _ -> t_dynamic) params_to)) e)); - true - ) cl_to cl_from params_from); - if is_some !ret then - get !ret - else if is_cl_related gen cl_from params_from cl_to params_to then - mk_cast to_t e - else - (* potential unsafe cast *) - (do_unsafe_cast ()) - | TMono _, TMono _ - | TMono _, TDynamic _ - | TDynamic _, TDynamic _ - | TDynamic _, TMono _ -> - e - | TMono _, _ - | TDynamic _, _ - | TAnon _, _ when gen.gneeds_box real_from_t -> - mk_cast to_t e - | TMono _, _ - | TDynamic _, _ -> e - | _, TMono _ - | _, TDynamic _ -> mk_cast to_t e - | TAnon (a_to), TAnon (a_from) -> - if a_to == a_from then - e - else if type_iseq gen to_t from_t then (* FIXME apply unify correctly *) - e - else - mk_cast to_t e - | _, TAnon(anon) -> (try - let p2 = match !(anon.a_status) with - | Statics c -> TInst(c,List.map (fun _ -> t_dynamic) c.cl_types) - | EnumStatics e -> TEnum(e, List.map (fun _ -> t_dynamic) e.e_types) - | AbstractStatics a -> TAbstract(a, List.map (fun _ -> t_dynamic) a.a_types) - | _ -> raise Not_found - in - let tclass = match get_type gen ([],"Class") with - | TAbstractDecl(a) -> a - | _ -> assert false in - handle_cast gen e real_to_t (gen.greal_type (TAbstract(tclass, [p2]))) - with | Not_found -> - mk_cast to_t e) - | TAbstract (a_to, _), TAbstract(a_from, _) when a_to == a_from -> - e - | TAbstract _, _ - | _, TAbstract _ -> - (try - unify from_t to_t; - mk_cast to_t e - with | Unify_error _ -> - try - unify to_t from_t; - mk_cast to_t e - with | Unify_error _ -> - do_unsafe_cast()) - | TEnum(e_to, []), TEnum(e_from, []) -> - if e_to == e_from then - e - else - (* potential unsafe cast *) - (do_unsafe_cast ()) - | TEnum(e_to, params_to), TEnum(e_from, params_from) when e_to.e_path = e_from.e_path -> - (try - List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; - e - with - | Unify_error _ -> do_unsafe_cast () - ) - | TEnum(en, params_to), TInst(cl, params_from) - | TInst(cl, params_to), TEnum(en, params_from) -> - (* this is here for max compatibility with EnumsToClass module *) - if en.e_path = cl.cl_path && en.e_extern then begin - (try - List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; - e - with - | Invalid_argument("List.iter2") -> - (* - this is a hack for RealTypeParams. Since there is no way at this stage to know if the class is the actual - EnumsToClass derived from the enum, we need to imply from possible ArgumentErrors (because of RealTypeParams interfaces), - that they would only happen if they were a RealTypeParams created interface - *) - e - | Unify_error _ -> do_unsafe_cast () - ) - end else - do_unsafe_cast () - | TType(t_to, params_to), TType(t_from, params_from) when t_to == t_from -> - if gen.gspecial_needs_cast real_to_t real_from_t then - (try - List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; - e - with - | Unify_error _ -> do_unsafe_cast () - ) - else - e - | TType(t_to, _), TType(t_from,_) -> - if gen.gspecial_needs_cast real_to_t real_from_t then - mk_cast to_t e - else - e - | TType _, _ when gen.gspecial_needs_cast real_to_t real_from_t -> - mk_cast to_t e - | _, TType _ when gen.gspecial_needs_cast real_to_t real_from_t -> - mk_cast to_t e - (*| TType(t_to, _), TType(t_from, _) -> - if t_to.t_path = t_from.t_path then - e - else if is_unsafe_cast gen real_to_t real_from_t then (* is_unsafe_cast will already follow both *) - (do_unsafe_cast ()) - else - mk_cast to_t e*) - | TType _, _ - | _, TType _ -> - if is_unsafe_cast gen real_to_t real_from_t then (* is_unsafe_cast will already follow both *) - (do_unsafe_cast ()) - else - mk_cast to_t e - | TAnon anon, _ -> - if PMap.is_empty anon.a_fields then - e - else - mk_cast to_t e - | TFun(args, ret), TFun(args2, ret2) -> - let get_args = List.map (fun (_,_,t) -> t) in - (try List.iter2 (type_eq gen (EqBothDynamic)) (ret :: get_args args) (ret2 :: get_args args2); e with | Unify_error _ | Invalid_argument("List.iter2") -> mk_cast to_t e) - | _, _ -> - do_unsafe_cast () - - (* end of cast handler *) - (* ******************* *) - - let is_static_overload c name = - match c.cl_super with - | None -> false - | Some (sup,_) -> - let rec loop c = - (PMap.mem name c.cl_statics) || (match c.cl_super with - | None -> false - | Some (sup,_) -> loop sup) - in - loop sup - - let does_unify a b = - try - unify a b; - true - with | Unify_error _ -> false - - (* this is a workaround for issue #1743, as FInstance() is returning the incorrect classfield *) - let select_overload gen applied_f overloads types params = - let rec check_arg arglist elist = - match arglist, elist with - | [], [] -> true (* it is valid *) - | (_,_,t) :: arglist, (_,_,et) :: elist when Type.type_iseq et t -> - check_arg arglist elist - | _ -> false - in - match follow applied_f with - | TFun _ -> - replace_mono applied_f; - let args, _ = get_fun applied_f in - let elist = List.rev args in - let rec check_overload overloads = - match overloads with - | (t, cf) :: overloads -> - let cft = apply_params types params t in - let cft = monomorphs cf.cf_params cft in - let args, _ = get_fun cft in - if check_arg (List.rev args) elist then - cf,t,false - else if overloads = [] then - cf,t,true (* no compatible overload was found *) - else - check_overload overloads - | [] -> assert false - in - check_overload overloads - | _ -> match overloads with (* issue #1742 *) - | (t,cf) :: [] -> cf,t,true - | (t,cf) :: _ -> cf,t,false - | _ -> assert false - - let choose_ctor gen cl tparams etl maybe_empty_t p = - let ctor, sup, stl = OverloadingConstructor.cur_ctor cl tparams in - (* get returned stl, with Dynamic as t_empty *) - let rec get_changed_stl c tl = - if c == sup then - tl - else match c.cl_super with - | None -> stl - | Some(sup,stl) -> get_changed_stl sup (List.map (apply_params c.cl_types tl) stl) - in - let ret_tparams = List.map (fun t -> match follow t with - | TDynamic _ | TMono _ -> t_empty - | _ -> t) tparams in - let ret_stl = get_changed_stl cl ret_tparams in - let ctors = ctor :: ctor.cf_overloads in - List.iter replace_mono etl; - (* first filter out or select outright maybe_empty *) - let ctors, is_overload = match etl, maybe_empty_t with - | [t], Some empty_t -> - let count = ref 0 in - let is_empty_call = Type.type_iseq t empty_t in - let ret = List.filter (fun cf -> match follow cf.cf_type with - (* | TFun([_,_,t],_) -> incr count; true *) - | TFun([_,_,t],_) -> replace_mono t; incr count; is_empty_call = (Type.type_iseq t empty_t) - | _ -> false) ctors in - ret, !count > 1 - | _ -> - let len = List.length etl in - let ret = List.filter (fun cf -> List.length (fst (get_fun cf.cf_type)) = len) ctors in - ret, (match ret with | _ :: [] -> false | _ -> true) - in - let rec check_arg arglist elist = - match arglist, elist with - | [], [] -> true - | (_,_,t) :: arglist, et :: elist -> (try - unify et t; - check_arg arglist elist - with | Unify_error el -> - (* List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) p) el; *) - false) - | _ -> false - in - let rec check_cf cf = - let t = apply_params sup.cl_types stl cf.cf_type in - replace_mono t; - let args, _ = get_fun t in - check_arg args etl - in - is_overload, List.find check_cf ctors, sup, ret_stl - - (* - - Type parameter handling - It will detect if/what type parameters were used, and call the cast handler - It will handle both TCall(TField) and TCall by receiving a texpr option field: e - Also it will transform the type parameters with greal_type_param and make - - handle_impossible_tparam - should cases where the type parameter is impossible to be determined from the called parameters be Dynamic? - e.g. static function test():T {} - *) - - (* match e.eexpr with | TCall( ({ eexpr = TField(ef, f) }) as e1, elist ) -> *) - let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist calls_parameters_explicitly = - (* the ONLY way to know if this call has parameters is to analyze the calling field. *) - (* To make matters a little worse, on both C# and Java only in some special cases that type parameters will be used *) - (* Namely, when using reflection type parameters are useless, of course. This also includes anonymous types *) - (* this will have to be handled by gparam_func_call *) - - let return_var efield = - match e with - | None -> - efield - | Some ecall -> - match follow efield.etype with - | TFun(_,ret) -> - (* closures will be handled by the closure handler. So we will just hint what's the expected type *) - (* FIXME: should closures have also its arguments cast correctly? In the current implementation I think not. TO_REVIEW *) - handle_cast gen { ecall with eexpr = TCall(efield, elist) } (gen.greal_type ecall.etype) ret - | _ -> - { ecall with eexpr = TCall(efield, elist) } - in - - let real_type = gen.greal_type ef.etype in - (* this part was rewritten at roughly r6477 in order to correctly support overloads *) - (match field_access gen real_type (field_name f) with - | FClassField (cl, params, _, cf, is_static, actual_t, declared_t) when e <> None && (cf.cf_kind = Method MethNormal || cf.cf_kind = Method MethInline) -> - (* C# target changes params with a real_type function *) - let params = match follow clean_ef.etype with - | TInst(_,params) -> params - | _ -> params in - let ecall = get e in - let ef = ref ef in - let is_overload = cf.cf_overloads <> [] || Meta.has Meta.Overload cf.cf_meta || (is_static && is_static_overload cl (field_name f)) in - let cf, actual_t, error = match is_overload with - | false -> - (* since actual_t from FClassField already applies greal_type, we're using the get_overloads helper to get this info *) - cf,declared_t,false - | true -> - let (cf, actual_t, error), is_static = match f with - | FInstance(c,cf) | FClosure(Some c,cf) -> - (* get from overloads *) - (* FIXME: this is a workaround for issue #1743 . Uncomment this code after it was solved *) - (* let t, cf = List.find (fun (t,cf2) -> cf == cf2) (Typeload.get_overloads cl (field_name f)) in *) - (* cf, t, false *) - select_overload gen e1.etype (Typeload.get_overloads cl (field_name f)) cl.cl_types params, false - | FStatic(c,f) -> - (* workaround for issue #1743 *) - (* f,f.cf_type, false *) - select_overload gen e1.etype ((f.cf_type,f) :: List.map (fun f -> f.cf_type,f) f.cf_overloads) [] [], true - | _ -> - gen.gcon.warning "Overloaded classfield typed as anonymous" ecall.epos; - (cf, actual_t, true), true - in - if not (is_static || error) then match find_first_declared_field gen cl ~exact_field:{ cf with cf_type = actual_t } cf.cf_name with - | Some(_,actual_t,_,_,declared_cl,tl,tlch) -> - if declared_cl != cl && overloads_cast_to_base then begin - let pos = (!ef).epos in - ef := { - eexpr = TCall( - { eexpr = TLocal(alloc_var "__as__" t_dynamic); etype = t_dynamic; epos = pos }, - [!ef]); - etype = TInst(declared_cl,List.map (apply_params cl.cl_types params) tl); - epos = pos - } - end; - cf,actual_t,false - | None -> - gen.gcon.warning "Cannot find matching overload" ecall.epos; - cf, actual_t, true - else - cf,actual_t,error - in - let error = error || (match follow actual_t with | TFun _ -> false | _ -> true) in - if error then (* if error, ignore arguments *) - mk_cast ecall.etype { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist ) } - else begin - (* infer arguments *) - (* 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 fparams = TypeParams.infer_params gen ecall.epos (get_fun (apply_params cl.cl_types params actual_t)) (get_fun called_t) 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 - let real_params = gen.greal_type_param (TClassDecl cl) params in - let function_t = apply_params cl.cl_types real_params actual_t in - let real_fparams = if calls_parameters_explicitly then - gen.greal_type_param (TClassDecl cl) fparams - else - gen.greal_type_param (TClassDecl cl) (TypeParams.infer_params gen ecall.epos (get_fun function_t) (get_fun (get_real_fun gen called_t)) cf.cf_params calls_parameters_explicitly) in - let function_t = get_real_fun gen (apply_params cf.cf_params real_fparams function_t) in - let args_ft, ret_ft = get_fun function_t in - (* applied function *) - let applied = elist in - (* check types list *) - let new_ecall, elist = try - let elist = List.map2 (fun applied (_,_,funct) -> - match is_overload, applied.eexpr with - | true, TConst TNull -> - mk_cast (gen.greal_type funct) applied - | true, _ -> (* when not (type_iseq gen (gen.greal_type applied.etype) funct) -> *) - let ret = handle_cast gen applied (funct) (gen.greal_type applied.etype) in - (match ret.eexpr with - | TCast _ -> ret - | _ -> mk_cast (funct) ret) - | _ -> - handle_cast gen applied (funct) (gen.greal_type applied.etype) - ) applied args_ft in - { ecall with - eexpr = TCall( - { e1 with eexpr = TField(!ef, f) }, - elist); - }, elist - with | Invalid_argument("List.map2") -> - gen.gcon.warning ("This expression may be invalid" ) ecall.epos; - { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist) }, elist - in - let new_ecall = if fparams <> [] then gen.gparam_func_call new_ecall { e1 with eexpr = TField(!ef, f) } fparams elist else new_ecall in - handle_cast gen new_ecall (gen.greal_type ecall.etype) (gen.greal_type ret_ft) - end - | FClassField (cl,params,_,{ cf_kind = (Method MethDynamic | Var _) },_,actual_t,_) -> - (* if it's a var, we will just try to apply the class parameters that have been changed with greal_type_param *) - let t = apply_params cl.cl_types (gen.greal_type_param (TClassDecl cl) params) (gen.greal_type actual_t) in - return_var (handle_cast gen { e1 with eexpr = TField(ef, f) } (gen.greal_type e1.etype) (gen.greal_type t)) - | 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 - (match en.e_types with - (* - | [] -> - let args, ret = get_args (efield.ef_type) in - let ef = { ef with eexpr = TTypeExpr( TEnumDecl en ); etype = TEnum(en, []) } in - handle_cast gen { ecall with eexpr = TCall({ e1 with eexpr = TField(ef, FEnum(en, efield)) }, List.map2 (fun param (_,_,t) -> handle_cast gen param (gen.greal_type t) (gen.greal_type param.etype)) elist args) } (gen.greal_type ecall.etype) (gen.greal_type ret) - *) - | _ -> - 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 args, ret = get_args 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 - (* - because of differences on how is handled on the platforms, this is a hack to be able to - correctly use class field type parameters with RealTypeParams - *) - let cf_params = List.map (fun t -> match follow t with | TDynamic _ -> t_empty | _ -> t) _params in - (* params are inverted *) - let cf_params = List.rev cf_params in - let t = apply_params en.e_types (gen.greal_type_param (TEnumDecl en) cf_params) actual_t in - let t = apply_params efield.ef_params (List.map (fun _ -> t_dynamic) efield.ef_params) t in - - let args, ret = get_args t in - - let elist = List.map2 (fun param (_,_,t) -> handle_cast gen (param) (gen.greal_type t) (gen.greal_type param.etype)) elist args in - let e1 = { e1 with eexpr = TField({ ef with eexpr = TTypeExpr( TEnumDecl en ); etype = TEnum(en, _params) }, FEnum(en, efield) ) } in - let new_ecall = gen.gparam_func_call ecall e1 _params elist in - - handle_cast gen new_ecall (gen.greal_type ecall.etype) (gen.greal_type ret) - ) - | FEnumField _ when is_some e -> assert false - | 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 *) - | FAnonField cf -> - let t = gen.greal_type cf.cf_type in - return_var (handle_cast gen { e1 with eexpr = TField(ef, f) } (gen.greal_type e1.etype) t) - | FNotFound - | FDynamicField _ -> - if is_some e then - return_var { e1 with eexpr = TField(ef, f) } - else - 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 *) - ) - - (* end of type parameter handling *) - (* ****************************** *) - - (** overloads_cast_to_base argument will cast overloaded function types to the class that declared it. **) - (** This is necessary for C#, and if true, will require the target to implement __as__, as a `quicker` form of casting **) - let default_implementation gen ?(native_string_cast = true) ?(overloads_cast_to_base = false) maybe_empty_t calls_parameters_explicitly = - let handle e t1 t2 = handle_cast gen e (gen.greal_type t1) (gen.greal_type t2) in - - let in_value = ref false in - - let rec run ?(just_type = false) e = - let handle = if not just_type then handle else fun e t1 t2 -> { e with etype = gen.greal_type t2 } in - let was_in_value = !in_value in - in_value := true; - match e.eexpr with - | TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) -> - { e with eexpr = TBinop(op, run ~just_type:true e1, run e2) } - | TField(ef, f) -> - handle_type_parameter gen None e (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f [] calls_parameters_explicitly - | TArrayDecl el -> - let et = e.etype in - let base_type = match follow et with - | TInst({ cl_path = ([], "Array") } as cl, bt) -> gen.greal_type_param (TClassDecl cl) bt - | _ -> assert false - 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 } - | TCall( ({ eexpr = TLocal v } as local), params ) when String.get v.v_name 0 = '_' && String.get v.v_name 1 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> - { e with eexpr = TCall(local, List.map run params) } - | TCall( ({ eexpr = TField(ef, f) }) as e1, elist ) -> - handle_type_parameter gen (Some e) (e1) (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f (List.map run elist) calls_parameters_explicitly - - (* the TNew and TSuper code was modified at r6497 *) - | TCall( { eexpr = TConst TSuper } as ef, eparams ) -> - let cl, tparams = match follow ef.etype with - | TInst(cl,p) -> cl, p - | _ -> assert false 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 = - if is_overload then - let ret = handle e t1 t2 in - match ret.eexpr with - | TCast _ -> ret - | _ -> mk_cast (gen.greal_type t1) e - else - handle e t1 t2 - in - let stl = gen.greal_type_param (TClassDecl sup) stl in - let args, _ = get_fun (apply_params sup.cl_types stl cf.cf_type) in - let eparams = List.map2 (fun e (_,_,t) -> - handle (run e) t e.etype - ) eparams args in - { e with eexpr = TCall(ef, eparams) } - with | Not_found -> - gen.gcon.warning "No overload found for this constructor call" e.epos; - { e with eexpr = TCall(ef, List.map run eparams) }) - | TCall (ef, eparams) -> - (match ef.etype with - | TFun(p, ret) -> - handle ({ e with eexpr = TCall(run ef, List.map2 (fun param (_,_,t) -> handle (run param) t param.etype) eparams p) }) e.etype ret - | _ -> Type.map_expr run e - ) - (* the TNew and TSuper code was modified at r6497 *) - | TNew (cl, tparams, eparams) -> (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 = - if true then - let ret = handle e t1 t2 in - match ret.eexpr with - | TCast _ -> ret - | _ -> mk_cast (gen.greal_type t1) e - else - handle e t1 t2 - in - let stl = gen.greal_type_param (TClassDecl sup) stl in - let args, _ = get_fun (apply_params sup.cl_types stl cf.cf_type) in - let eparams = List.map2 (fun e (_,_,t) -> - handle (run e) t e.etype - ) eparams args in - { e with eexpr = TNew(cl, tparams, eparams) } - with | Not_found -> - gen.gcon.warning "No overload found for this constructor call" e.epos; - { e with eexpr = TNew(cl, tparams, List.map run eparams) }) - | TArray(arr, idx) -> - let arr_etype = match follow arr.etype with - | (TInst _ as t) -> t - | TAbstract ({ a_impl = Some _ } as a, pl) -> - follow (Codegen.Abstract.get_underlying_type a pl) - | t -> t in - let idx = match gen.greal_type idx.etype with - | TAbstract({ a_path = [],"Int" },_) -> run idx - | _ -> match handle (run idx) gen.gcon.basic.tint (gen.greal_type idx.etype) with - | ({ eexpr = TCast _ } as idx) -> idx - | idx -> mk_cast gen.gcon.basic.tint idx - in - let e = { e with eexpr = TArray(run arr, idx) } in - (* get underlying class (if it's a class *) - (match arr_etype with - | TInst(cl, params) -> - (* see if it implements ArrayAccess *) - (match cl.cl_array_access with - | None -> e - | Some t -> - (* if it does, apply current parameters (and change them) *) - (* let real_t = apply_params_internal (List.map (gen.greal_type_param (TClassDecl cl))) cl params t in *) - let param = apply_params cl.cl_types (gen.greal_type_param (TClassDecl cl) params) t in - let real_t = apply_params cl.cl_types params param in - (* see if it needs a cast *) - - handle (e) (gen.greal_type e.etype) (gen.greal_type real_t) - ) - | _ -> Type.map_expr run e) - | TVars (veopt_l) -> - { e with eexpr = TVars (List.map (fun (v,eopt) -> - match eopt with - | None -> (v,eopt) - | Some e -> - (v, Some( handle (run e) v.v_type e.etype )) - ) veopt_l) } - (* FIXME deal with in_value when using other statements that may not have a TBlock wrapped on them *) - | TIf (econd, ethen, Some(eelse)) when was_in_value -> - { e with eexpr = TIf (handle (run econd) gen.gcon.basic.tbool econd.etype, handle (run ethen) e.etype ethen.etype, Some( handle (run eelse) e.etype eelse.etype ) ) } - | TIf (econd, ethen, eelse) -> - { e with eexpr = TIf (handle (run econd) gen.gcon.basic.tbool econd.etype, run (mk_block ethen), Option.map (fun e -> run (mk_block e)) eelse) } - | TWhile (econd, e1, flag) -> - { e with eexpr = TWhile (handle (run econd) gen.gcon.basic.tbool econd.etype, run (mk_block e1), flag) } - | TSwitch (cond, el_e_l, edef) -> - { e with eexpr = TSwitch(run cond, List.map (fun (el,e) -> (List.map run el, run (mk_block e))) el_e_l, Option.map (fun e -> run (mk_block e)) edef) } - | TMatch (cond, en, il_vl_e_l, edef) -> - { e with eexpr = TMatch(run cond, en, List.map (fun (il, vl, e) -> (il, vl, run (mk_block e))) il_vl_e_l, Option.map (fun e -> run (mk_block e)) edef) } - | TFor (v,cond,e1) -> - { e with eexpr = TFor(v, run cond, run (mk_block e1)) } - | TTry (e, ve_l) -> - { e with eexpr = TTry(run (mk_block e), List.map (fun (v,e) -> (v, run (mk_block e))) ve_l) } - | TBlock el -> - { e with eexpr = TBlock ( List.map (fun e -> in_value := false; run e) el ) } - | TCast (expr, md) when is_void (follow e.etype) -> - run expr - | TCast (expr, md) -> - let rec get_null e = - match e.eexpr with - | TConst TNull -> Some e - | TParenthesis e -> get_null e - | _ -> None - in - (match get_null expr with - | Some enull -> { enull with etype = e.etype } - | _ -> - let last_unsafe = gen.gon_unsafe_cast in - gen.gon_unsafe_cast <- (fun t t2 pos -> ()); - let ret = handle (run expr) e.etype expr.etype in - gen.gon_unsafe_cast <- last_unsafe; - match ret.eexpr with - | TCast _ -> ret - | _ -> { e with eexpr = TCast(ret,md); etype = gen.greal_type e.etype } - ) - (*| TCast _ -> - (* if there is already a cast, we should skip this cast check *) - Type.map_expr run e*) - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - gen.ghandle_cast <- (fun tto tfrom expr -> handle_cast gen expr (gen.greal_type tto) (gen.greal_type tfrom)); - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map; - ReturnCast.configure gen + let name = "cast_detect_2" + + let priority = solve_deps name [DBefore TypeParams.priority; DBefore ExpressionUnwrap.priority] + + (* ******************************************* *) + (* ReturnCast *) + (* ******************************************* *) + + (* + + Cast detection for return types can't be done at CastDetect time, since we need an + unwrapped expression to make sure we catch all return cast detections. So this module + is specifically to deal with that, and is configured automatically by CastDetect + + dependencies: + + + *) + + module ReturnCast = + struct + + let name = "return_cast" + + let priority = solve_deps name [DAfter priority; DAfter ExpressionUnwrap.priority] + + let default_implementation gen = + let rec extract_expr e = match e.eexpr with + | TParenthesis e + | TMeta (_,e) + | TCast(e,_) -> extract_expr e + | _ -> e + in + let current_ret_type = ref None in + let handle e tto tfrom = gen.ghandle_cast (gen.greal_type tto) (gen.greal_type tfrom) e in + let in_value = ref false in + + let rec run e = + let was_in_value = !in_value in + in_value := true; + 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 + (match eopt with + | None when not (is_void ret_type) -> + { e with eexpr = TReturn( Some(null ret_type e.epos)) } + | None -> e + | Some eret -> + { e with eexpr = TReturn( Some(handle (run eret) ret_type eret.etype ) ) }) + | TFunction(tfunc) -> + let last_ret = !current_ret_type in + current_ret_type := Some(tfunc.tf_type); + let ret = Type.map_expr run e in + current_ret_type := last_ret; + ret + | TBlock el -> + { e with eexpr = TBlock ( List.map (fun e -> in_value := false; run e) el ) } + | TBinop ( (Ast.OpAssign as op),e1,e2) + | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) when was_in_value -> + let e1 = extract_expr (run e1) in + let r = { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } in + handle r e.etype e1.etype + | TBinop ( (Ast.OpAssign as op),({ eexpr = TField(tf, f) } as e1), e2 ) + | TBinop ( (Ast.OpAssignOp _ as op),({ eexpr = TField(tf, f) } as e1), e2 ) -> + (match field_access_esp gen (gen.greal_type tf.etype) (f) with + | FClassField(cl,params,_,_,is_static,actual_t,_) -> + let actual_t = if is_static then actual_t else apply_params cl.cl_params params actual_t in + let e1 = extract_expr (run e1) in + { e with eexpr = TBinop(op, e1, handle (run e2) actual_t e2.etype); etype = e1.etype } + | _ -> + let e1 = extract_expr (run e1) in + { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } + ) + | TBinop ( (Ast.OpAssign as op),e1,e2) + | TBinop ( (Ast.OpAssignOp _ as op),e1,e2) -> + let e1 = extract_expr (run e1) in + { e with eexpr = TBinop(op, e1, handle (run e2) e1.etype e2.etype); etype = e1.etype } + | _ -> Type.map_expr run e + in + run + + let configure gen = + let map e = Some(default_implementation gen e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + + end;; + + let get_args t = match follow t with + | TFun(args,ret) -> args,ret + | _ -> trace (debug_type t); assert false + + let s_path (pack,n) = (String.concat "." (pack @ [n])) + + (* + Since this function is applied under native-context only, the type paraters will already be changed + *) + let map_cls gen also_implements fn super = + let rec loop c tl = + if c == super then + fn c tl + else (match c.cl_super with + | None -> false + | Some (cs,tls) -> + let tls = gen.greal_type_param (TClassDecl cs) tls in + loop cs (List.map (apply_params c.cl_params tl) tls) + ) || (if also_implements then List.exists (fun (cs,tls) -> + loop cs (List.map (apply_params c.cl_params tl) tls) + ) c.cl_implements else false) + in + loop + + let follow_dyn t = match follow t with + | TMono _ | TLazy _ -> t_dynamic + | t -> t + + (* + this has a slight change from the type.ml version, in which it doesn't + change a TMono into the other parameter + *) + let rec type_eq gen param a b = + if a == b then + () + else match follow_dyn (gen.greal_type a) , follow_dyn (gen.greal_type b) with + | TEnum (e1,tl1) , TEnum (e2,tl2) -> + if e1 != e2 && not (param = EqCoreType && e1.e_path = e2.e_path) then Type.error [cannot_unify a b]; + List.iter2 (type_eq gen param) tl1 tl2 + | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> + if a1 != a2 && not (param = EqCoreType && a1.a_path = a2.a_path) then Type.error [cannot_unify a b]; + List.iter2 (type_eq gen param) 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 Type.error [cannot_unify a b]; + List.iter2 (type_eq gen param) tl1 tl2 + | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> + (try + type_eq gen param r1 r2; + List.iter2 (fun (n,o1,t1) (_,o2,t2) -> + if o1 <> o2 then Type.error [Not_matching_optional n]; + type_eq gen param t1 t2 + ) l1 l2 + with + Unify_error l -> Type.error (cannot_unify a b :: l)) + | TDynamic a , TDynamic b -> + type_eq gen param a b + | TAnon a1, TAnon a2 -> + (try + 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 Type.error [invalid_kind n f1.cf_kind f2.cf_kind]; + try + type_eq gen param f1.cf_type f2.cf_type + with + Unify_error l -> Type.error (invalid_field n :: l) + 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]; + 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]; + a1.a_fields <- PMap.add n f2 a1.a_fields + end; + ) a2.a_fields; + with + Unify_error l -> Type.error (cannot_unify a b :: l)) + | _ , _ -> + if b == t_dynamic && (param = EqRightDynamic || param = EqBothDynamic) then + () + else if a == t_dynamic && param = EqBothDynamic then + () + else + Type.error [cannot_unify a b] + + let type_iseq gen a b = + try + type_eq gen EqStrict a b; + true + with + Unify_error _ -> false + + (* will return true if both arguments are compatible. If it's not the case, a runtime error is very likely *) + let is_cl_related gen cl tl super superl = + let is_cl_related cl tl super superl = map_cls gen (gen.guse_tp_constraints || (match cl.cl_kind,super.cl_kind with KTypeParameter _, _ | _,KTypeParameter _ -> false | _ -> true)) (fun _ _ -> true) super cl tl in + is_cl_related cl tl super superl || is_cl_related super superl cl tl + + + let rec is_unsafe_cast gen to_t from_t = + match (follow to_t, follow from_t) with + | TInst(cl_to, to_params), TInst(cl_from, from_params) -> + not (is_cl_related gen cl_from from_params cl_to to_params) + | TEnum(e_to, _), TEnum(e_from, _) -> + e_to.e_path <> e_from.e_path + | TFun _, TFun _ -> + (* functions are never unsafe cast by default. This behavior might be changed *) + (* with a later AST pass which will run through TFun to TFun casts *) + false + | TMono _, _ + | _, TMono _ + | TDynamic _, _ + | _, TDynamic _ -> + false + | TAnon _, _ + | _, TAnon _ -> + (* anonymous are never unsafe also. *) + (* Though they will generate a cast, so if this cast is unneeded it's better to avoid them by tweaking gen.greal_type *) + false + | TAbstract _, _ + | _, TAbstract _ -> + (try + unify from_t to_t; + false + with | Unify_error _ -> + try + unify to_t from_t; (* still not unsafe *) + false + with | Unify_error _ -> + true) + | _ -> true + + let unifies tfrom tto = try + unify tfrom tto; + true + with | _ -> + false + + let do_unsafe_cast gen from_t to_t e = + let t_path t = + match t with + | TInst(cl, _) -> cl.cl_path + | TEnum(e, _) -> e.e_path + | TType(t, _) -> t.t_path + | TAbstract(a, _) -> a.a_path + | TDynamic _ -> ([], "Dynamic") + | _ -> raise Not_found + in + match gen.gfollow#run_f from_t, gen.gfollow#run_f to_t with + | TInst({ cl_kind = KTypeParameter tl },_), t2 when List.exists (fun t -> unifies t t2) tl -> + mk_cast to_t (mk_cast t_dynamic e) + | _ -> + let do_default () = + gen.gon_unsafe_cast to_t e.etype e.epos; + mk_cast to_t (mk_cast t_dynamic e) + in + (* TODO: there really should be a better way to write that *) + try + if (Hashtbl.find gen.gsupported_conversions (t_path from_t)) from_t to_t then + mk_cast to_t e + else + do_default() + with + | Not_found -> + try + if (Hashtbl.find gen.gsupported_conversions (t_path to_t)) from_t to_t then + mk_cast to_t e + else + do_default() + with + | Not_found -> do_default() + + (* ****************************** *) + (* cast handler *) + (* decides if a cast should be emitted, given a from and a to type *) + (* + this function is like a mini unify, without e.g. subtyping, which makes sense + at the backend level, since most probably Anons and TInst will have a different representation there + *) + let rec handle_cast gen e real_to_t real_from_t = + let do_unsafe_cast () = do_unsafe_cast gen real_from_t real_to_t { e with etype = real_from_t } in + let to_t, from_t = real_to_t, real_from_t in + + let mk_cast t e = + match e.eexpr with + (* TThrow is always typed as Dynamic, we just need to type it accordingly *) + | TThrow _ -> { e with etype = t } + | _ -> mk_cast t e + in + + let e = { e with etype = real_from_t } in + if try fast_eq real_to_t real_from_t with Invalid_argument("List.for_all2") -> false then e else + match real_to_t, real_from_t with + (* string is the only type that can be implicitly converted from any other *) + | TInst( { cl_path = ([], "String") }, []), _ -> + mk_cast to_t e + | TInst(cl_to, params_to), TInst(cl_from, params_from) -> + let ret = ref None in + (* + this is a little confusing: + we are here mapping classes until we have the same to and from classes, applying the type parameters in each step, so we can + compare the type parameters; + + If a class is found - meaning that the cl_from can be converted without a cast into cl_to, + we still need to check their type parameters. + *) + ignore (map_cls gen (gen.guse_tp_constraints || (match cl_from.cl_kind,cl_to.cl_kind with KTypeParameter _, _ | _,KTypeParameter _ -> false | _ -> true)) (fun _ tl -> + try + (* type found, checking type parameters *) + List.iter2 (type_eq gen EqStrict) tl params_to; + ret := Some e; + true + with | Unify_error _ -> + (* type parameters need casting *) + if gen.ghas_tparam_cast_handler then begin + (* + if we are already handling type parameter casts on other part of code (e.g. RealTypeParameters), + we'll just make a cast to indicate that this place needs type parameter-involved casting + *) + ret := Some (mk_cast to_t e); + true + end else + (* + if not, we're going to check if we only need a simple cast, + or if we need to first cast into the dynamic version of it + *) + try + List.iter2 (type_eq gen EqRightDynamic) tl params_to; + ret := Some (mk_cast to_t e); + true + with | Unify_error _ -> + ret := Some (mk_cast to_t (mk_cast (TInst(cl_to, List.map (fun _ -> t_dynamic) params_to)) e)); + true + ) cl_to cl_from params_from); + if is_some !ret then + get !ret + else if is_cl_related gen cl_from params_from cl_to params_to then + mk_cast to_t e + else + (* potential unsafe cast *) + (do_unsafe_cast ()) + | TMono _, TMono _ + | TMono _, TDynamic _ + | TDynamic _, TDynamic _ + | TDynamic _, TMono _ -> + e + | TMono _, _ + | TDynamic _, _ + | TAnon _, _ when gen.gneeds_box real_from_t -> + mk_cast to_t e + | TMono _, _ + | TDynamic _, _ -> e + | _, TMono _ + | _, TDynamic _ -> mk_cast to_t e + | TAnon (a_to), TAnon (a_from) -> + if a_to == a_from then + e + else if type_iseq gen to_t from_t then (* FIXME apply unify correctly *) + e + else + mk_cast to_t e + | _, TAnon(anon) -> (try + let p2 = match !(anon.a_status) with + | Statics c -> TInst(c,List.map (fun _ -> t_dynamic) c.cl_params) + | EnumStatics e -> TEnum(e, List.map (fun _ -> t_dynamic) e.e_params) + | AbstractStatics a -> TAbstract(a, List.map (fun _ -> t_dynamic) a.a_params) + | _ -> raise Not_found + in + let tclass = match get_type gen ([],"Class") with + | TAbstractDecl(a) -> a + | _ -> assert false in + handle_cast gen e real_to_t (gen.greal_type (TAbstract(tclass, [p2]))) + with | Not_found -> + mk_cast to_t e) + | TAbstract (a_to, _), TAbstract(a_from, _) when a_to == a_from -> + e + | TAbstract _, TInst({ cl_kind = KTypeParameter _ }, _) + | TInst({ cl_kind = KTypeParameter _ }, _), TAbstract _ -> + do_unsafe_cast() + | TAbstract _, _ + | _, TAbstract _ -> + (try + unify from_t to_t; + mk_cast to_t e + with | Unify_error _ -> + try + unify to_t from_t; + mk_cast to_t e + with | Unify_error _ -> + do_unsafe_cast()) + | TEnum(e_to, []), TEnum(e_from, []) -> + if e_to == e_from then + e + else + (* potential unsafe cast *) + (do_unsafe_cast ()) + | TEnum(e_to, params_to), TEnum(e_from, params_from) when e_to.e_path = e_from.e_path -> + (try + List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; + e + with + | Unify_error _ -> do_unsafe_cast () + ) + | TEnum(en, params_to), TInst(cl, params_from) + | TInst(cl, params_to), TEnum(en, params_from) -> + (* this is here for max compatibility with EnumsToClass module *) + if en.e_path = cl.cl_path && Meta.has Meta.Class en.e_meta then begin + (try + List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; + e + with + | Invalid_argument("List.iter2") -> + (* + this is a hack for RealTypeParams. Since there is no way at this stage to know if the class is the actual + EnumsToClass derived from the enum, we need to imply from possible ArgumentErrors (because of RealTypeParams interfaces), + that they would only happen if they were a RealTypeParams created interface + *) + e + | Unify_error _ -> do_unsafe_cast () + ) + end else + do_unsafe_cast () + | TType(t_to, params_to), TType(t_from, params_from) when t_to == t_from -> + if gen.gspecial_needs_cast real_to_t real_from_t then + (try + List.iter2 (type_eq gen (if gen.gallow_tp_dynamic_conversion then EqRightDynamic else EqStrict)) params_from params_to; + e + with + | Unify_error _ -> do_unsafe_cast () + ) + else + e + | TType(t_to, _), TType(t_from,_) -> + if gen.gspecial_needs_cast real_to_t real_from_t then + mk_cast to_t e + else + e + | TType _, _ when gen.gspecial_needs_cast real_to_t real_from_t -> + mk_cast to_t e + | _, TType _ when gen.gspecial_needs_cast real_to_t real_from_t -> + mk_cast to_t e + (*| TType(t_to, _), TType(t_from, _) -> + if t_to.t_path = t_from.t_path then + e + else if is_unsafe_cast gen real_to_t real_from_t then (* is_unsafe_cast will already follow both *) + (do_unsafe_cast ()) + else + mk_cast to_t e*) + | TType _, _ + | _, TType _ -> + if is_unsafe_cast gen real_to_t real_from_t then (* is_unsafe_cast will already follow both *) + (do_unsafe_cast ()) + else + mk_cast to_t e + | TAnon anon, _ -> + if PMap.is_empty anon.a_fields then + e + else + mk_cast to_t e + | TFun(args, ret), TFun(args2, ret2) -> + let get_args = List.map (fun (_,_,t) -> t) in + (try List.iter2 (type_eq gen (EqBothDynamic)) (ret :: get_args args) (ret2 :: get_args args2); e with | Unify_error _ | Invalid_argument("List.iter2") -> mk_cast to_t e) + | _, _ -> + do_unsafe_cast () + + (* end of cast handler *) + (* ******************* *) + + let is_static_overload c name = + match c.cl_super with + | None -> false + | Some (sup,_) -> + let rec loop c = + (PMap.mem name c.cl_statics) || (match c.cl_super with + | None -> false + | Some (sup,_) -> loop sup) + in + loop sup + + let does_unify a b = + try + unify a b; + true + with | Unify_error _ -> false + + (* this is a workaround for issue #1743, as FInstance() is returning the incorrect classfield *) + let rec clean_t t = match follow t with + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + clean_t (Abstract.get_underlying_type a tl) + | t -> t + + let select_overload gen applied_f overloads types params = + let rec check_arg arglist elist = + match arglist, elist with + | [], [] -> true (* it is valid *) + | (_,_,TAbstract({ a_path = (["haxe";"extern"],"Rest") }, [t])) :: [], elist -> + List.for_all (fun (_,_,et) -> Type.type_iseq (clean_t et) (clean_t t)) elist + | (_,_,t) :: arglist, (_,_,et) :: elist when Type.type_iseq (clean_t et) (clean_t t) -> + check_arg arglist elist + | _ -> false + in + match follow applied_f with + | TFun _ -> + replace_mono applied_f; + let args, _ = get_fun applied_f in + let elist = List.rev args in + let rec check_overload overloads = + match overloads with + | (t, cf) :: overloads -> + let cft = apply_params types params t in + let cft = monomorphs cf.cf_params cft in + let args, _ = get_fun cft in + if check_arg (List.rev args) elist then + cf,t,false + else if overloads = [] then + cf,t,true (* no compatible overload was found *) + else + check_overload overloads + | [] -> assert false + in + check_overload overloads + | _ -> match overloads with (* issue #1742 *) + | (t,cf) :: [] -> cf,t,true + | (t,cf) :: _ -> cf,t,false + | _ -> assert false + + let choose_ctor gen cl tparams etl maybe_empty_t p = + let ctor, sup, stl = OverloadingConstructor.cur_ctor cl tparams in + (* get returned stl, with Dynamic as t_empty *) + let rec get_changed_stl c tl = + if c == sup then + tl + else match c.cl_super with + | None -> stl + | Some(sup,stl) -> get_changed_stl sup (List.map (apply_params c.cl_params tl) stl) + in + let ret_tparams = List.map (fun t -> match follow t with + | TDynamic _ | TMono _ -> t_empty + | _ -> t) tparams in + let ret_stl = get_changed_stl cl ret_tparams in + let ctors = ctor :: ctor.cf_overloads in + List.iter replace_mono etl; + (* first filter out or select outright maybe_empty *) + let ctors, is_overload = match etl, maybe_empty_t with + | [t], Some empty_t -> + let count = ref 0 in + let is_empty_call = Type.type_iseq t empty_t in + let ret = List.filter (fun cf -> match follow cf.cf_type with + (* | TFun([_,_,t],_) -> incr count; true *) + | TFun([_,_,t],_) -> + replace_mono t; incr count; is_empty_call = (Type.type_iseq t empty_t) + | _ -> false) ctors in + ret, !count > 1 + | _ -> + let len = List.length etl in + let ret = List.filter (fun cf -> List.length (fst (get_fun cf.cf_type)) = len) ctors in + ret, (match ret with | _ :: [] -> false | _ -> true) + in + let rec check_arg arglist elist = + match arglist, elist with + | [], [] -> true + | (_,_,t) :: arglist, et :: elist -> (try + let t = run_follow gen t in + unify et t; + check_arg arglist elist + with | Unify_error el -> + (* List.iter (fun el -> gen.gcon.warning (Typecore.unify_error_msg (print_context()) el) p) el; *) + false) + | _ -> + false + in + let rec check_cf cf = + let t = apply_params sup.cl_params stl cf.cf_type in + replace_mono t; + let args, _ = get_fun t in + check_arg args etl + in + match is_overload, ctors with + | false, [c] -> + false, c, sup, ret_stl + | _ -> + is_overload, List.find check_cf ctors, sup, ret_stl + + let change_rest tfun elist = + let rec loop acc arglist elist = match arglist, elist with + | (_,_,TAbstract({ a_path = (["haxe";"extern"],"Rest") },[t])) :: [], elist -> + List.rev (List.map (fun _ -> "rest",false,t) elist @ acc) + | (n,o,t) :: arglist, _ :: elist -> + loop ((n,o,t) :: acc) arglist elist + | _, _ -> + List.rev acc + in + let args,ret = get_fun tfun in + TFun(loop [] args elist, ret) + + (* + + Type parameter handling + It will detect if/what type parameters were used, and call the cast handler + It will handle both TCall(TField) and TCall by receiving a texpr option field: e + Also it will transform the type parameters with greal_type_param and make + + handle_impossible_tparam - should cases where the type parameter is impossible to be determined from the called parameters be Dynamic? + e.g. static function test():T {} + *) + + (* match e.eexpr with | TCall( ({ eexpr = TField(ef, f) }) as e1, elist ) -> *) + let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist calls_parameters_explicitly = + (* the ONLY way to know if this call has parameters is to analyze the calling field. *) + (* To make matters a little worse, on both C# and Java only in some special cases that type parameters will be used *) + (* Namely, when using reflection type parameters are useless, of course. This also includes anonymous types *) + (* this will have to be handled by gparam_func_call *) + + let return_var efield = + match e with + | None -> + efield + | Some ecall -> + match follow efield.etype with + | TFun(_,ret) -> + (* closures will be handled by the closure handler. So we will just hint what's the expected type *) + (* FIXME: should closures have also its arguments cast correctly? In the current implementation I think not. TO_REVIEW *) + handle_cast gen { ecall with eexpr = TCall(efield, elist) } (gen.greal_type ecall.etype) ret + | _ -> + { ecall with eexpr = TCall(efield, elist) } + in + + let real_type = gen.greal_type ef.etype in + (* this part was rewritten at roughly r6477 in order to correctly support overloads *) + (match field_access_esp gen real_type (f) with + | FClassField (cl, params, _, cf, is_static, actual_t, declared_t) when e <> None && (cf.cf_kind = Method MethNormal || cf.cf_kind = Method MethInline) -> + (* C# target changes params with a real_type function *) + let params = match follow clean_ef.etype with + | TInst(_,params) -> params + | _ -> params + in + let ecall = get e in + let ef = ref ef in + let is_overload = cf.cf_overloads <> [] || Meta.has Meta.Overload cf.cf_meta || (is_static && is_static_overload cl (field_name f)) in + let cf, actual_t, error = match is_overload with + | false -> + (* since actual_t from FClassField already applies greal_type, we're using the get_overloads helper to get this info *) + let t = if cf.cf_params = [] then (* this if statement must be eliminated - it's a workaround for #3516 + infer params. *) + actual_t + else + declared_t + in + cf,t,false + | true -> + let (cf, actual_t, error), is_static = match f with + | FInstance(c,_,cf) | FClosure(Some (c,_),cf) -> + (* get from overloads *) + (* FIXME: this is a workaround for issue #1743 . Uncomment this code after it was solved *) + (* let t, cf = List.find (fun (t,cf2) -> cf == cf2) (Typeload.get_overloads cl (field_name f)) in *) + (* cf, t, false *) + select_overload gen e1.etype (Typeload.get_overloads cl (field_name f)) cl.cl_params params, false + | FStatic(c,f) -> + (* workaround for issue #1743 *) + (* f,f.cf_type, false *) + select_overload gen e1.etype ((f.cf_type,f) :: List.map (fun f -> f.cf_type,f) f.cf_overloads) [] [], true + | _ -> + gen.gcon.warning "Overloaded classfield typed as anonymous" ecall.epos; + (cf, actual_t, true), true + in + + if not (is_static || error) then match find_first_declared_field gen cl ~exact_field:{ cf with cf_type = actual_t } cf.cf_name with + | Some(cf_orig,actual_t,_,_,declared_cl,tl,tlch) -> + let rec is_super e = match e.eexpr with + | TConst TSuper -> true + | TParenthesis p | TMeta(_,p) -> is_super p + | _ -> false + in + if declared_cl != cl && overloads_cast_to_base && not (is_super !ef) then begin + let pos = (!ef).epos in + ef := { + eexpr = TCall( + { eexpr = TLocal(alloc_var "__as__" t_dynamic); etype = t_dynamic; epos = pos }, + [!ef]); + etype = TInst(declared_cl,List.map (apply_params cl.cl_params params) tl); + epos = pos + } + end; + { cf_orig with cf_name = cf.cf_name },actual_t,false + | None -> + gen.gcon.warning "Cannot find matching overload" ecall.epos; + cf, actual_t, true + else + cf,actual_t,error + in + + (* take off Rest param *) + let actual_t = change_rest actual_t elist in + (* set the real (selected) class field *) + let f = match f with + | FInstance(c,tl,_) -> FInstance(c,tl,cf) + | FClosure(c,_) -> FClosure(c,cf) + | FStatic(c,_) -> FStatic(c,cf) + | f -> f + in + let error = error || (match follow actual_t with | TFun _ -> false | _ -> true) in + if error then (* if error, ignore arguments *) + if is_void ecall.etype then + { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist ) } + else + mk_cast ecall.etype { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist ) } + else begin + (* infer arguments *) + (* 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 = TypeParams.infer_params gen ecall.epos (get_fun (apply_params cl.cl_params params actual_t)) (get_fun called_t) 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 + let real_params = gen.greal_type_param (TClassDecl cl) params in + let function_t = apply_params cl.cl_params real_params actual_t in + let real_fparams = if calls_parameters_explicitly then + gen.greal_type_param (TClassDecl cl) fparams + else + gen.greal_type_param (TClassDecl cl) (TypeParams.infer_params gen ecall.epos (get_fun function_t) (get_fun (get_real_fun gen called_t)) cf.cf_params calls_parameters_explicitly) in + let function_t = get_real_fun gen (apply_params cf.cf_params real_fparams function_t) in + let args_ft, ret_ft = get_fun function_t in + (* applied function *) + let applied = elist in + (* check types list *) + let new_ecall, elist = try + let elist = List.map2 (fun applied (_,_,funct) -> + match is_overload, applied.eexpr with + | true, TConst TNull -> + mk_cast (gen.greal_type funct) applied + | true, _ -> (* when not (type_iseq gen (gen.greal_type applied.etype) funct) -> *) + let ret = handle_cast gen applied (funct) (gen.greal_type applied.etype) in + (match ret.eexpr with + | TCast _ -> ret + | _ -> mk_cast (funct) ret) + | _ -> + handle_cast gen applied (funct) (gen.greal_type applied.etype) + ) applied args_ft in + { ecall with + eexpr = TCall( + { e1 with eexpr = TField(!ef, f) }, + elist); + }, elist + with | Invalid_argument("List.map2") -> + gen.gcon.warning ("This expression may be invalid" ) ecall.epos; + { ecall with eexpr = TCall({ e1 with eexpr = TField(!ef, f) }, elist) }, elist + in + let new_ecall = if fparams <> [] then gen.gparam_func_call new_ecall { e1 with eexpr = TField(!ef, f) } fparams elist else new_ecall in + let ret = handle_cast gen new_ecall (gen.greal_type ecall.etype) (gen.greal_type ret_ft) in + (match gen.gcon.platform, cf.cf_params, ret.eexpr with + | _, _, TCast _ -> ret + | Java, _ :: _, _ -> + (* this is a workaround for a javac openjdk issue with unused type parameters and return type inference *) + (* see more at issue #3123 *) + mk_cast (gen.greal_type ret_ft) new_ecall + | _ -> ret) + end + | FClassField (cl,params,_,{ cf_kind = (Method MethDynamic | Var _) },_,actual_t,_) -> + (* if it's a var, we will just try to apply the class parameters that have been changed with greal_type_param *) + let t = apply_params cl.cl_params (gen.greal_type_param (TClassDecl cl) params) (gen.greal_type actual_t) in + return_var (handle_cast gen { e1 with eexpr = TField(ef, f) } (gen.greal_type e1.etype) (gen.greal_type t)) + | 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 + (match en.e_params with + (* + | [] -> + let args, ret = get_args (efield.ef_type) in + let ef = { ef with eexpr = TTypeExpr( TEnumDecl en ); etype = TEnum(en, []) } in + handle_cast gen { ecall with eexpr = TCall({ e1 with eexpr = TField(ef, FEnum(en, efield)) }, List.map2 (fun param (_,_,t) -> handle_cast gen param (gen.greal_type t) (gen.greal_type param.etype)) elist args) } (gen.greal_type ecall.etype) (gen.greal_type ret) + *) + | _ -> + 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 args, ret = get_args 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 + (* + because of differences on how is handled on the platforms, this is a hack to be able to + correctly use class field type parameters with RealTypeParams + *) + let cf_params = List.map (fun t -> match follow t with | TDynamic _ -> t_empty | _ -> t) _params in + let t = apply_params en.e_params (gen.greal_type_param (TEnumDecl en) cf_params) actual_t in + let t = apply_params efield.ef_params (List.map (fun _ -> t_dynamic) efield.ef_params) t in + + let args, ret = get_args t in + + let elist = List.map2 (fun param (_,_,t) -> handle_cast gen (param) (gen.greal_type t) (gen.greal_type param.etype)) elist args in + let e1 = { e1 with eexpr = TField({ ef with eexpr = TTypeExpr( TEnumDecl en ); etype = TEnum(en, _params) }, FEnum(en, efield) ) } in + let new_ecall = gen.gparam_func_call ecall e1 _params elist in + + handle_cast gen new_ecall (gen.greal_type ecall.etype) (gen.greal_type ret) + ) + | FEnumField _ when is_some e -> assert false + | 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 *) + | FAnonField cf -> + let t = gen.greal_type cf.cf_type in + return_var (handle_cast gen { e1 with eexpr = TField(ef, f) } (gen.greal_type e1.etype) t) + | FNotFound + | FDynamicField _ -> + if is_some e then + return_var { e1 with eexpr = TField(ef, f) } + else + 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 *) + ) + + (* end of type parameter handling *) + (* ****************************** *) + + (** overloads_cast_to_base argument will cast overloaded function types to the class that declared it. **) + (** This is necessary for C#, and if true, will require the target to implement __as__, as a `quicker` form of casting **) + let default_implementation gen ?(native_string_cast = true) ?(overloads_cast_to_base = false) maybe_empty_t calls_parameters_explicitly = + let handle e t1 t2 = handle_cast gen e (gen.greal_type t1) (gen.greal_type t2) in + + let in_value = ref false in + + let rec clean_cast e = match e.eexpr with + | TCast(e,_) -> clean_cast e + | TParenthesis(e) | TMeta(_,e) -> clean_cast e + | _ -> e + in + + let get_abstract_impl t = match t with + | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> + Abstract.get_underlying_type a pl + | t -> t + in + + let rec is_abstract_to_struct t = match t with + | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> + is_abstract_to_struct (Abstract.get_underlying_type a pl) + | TInst(c,_) when Meta.has Meta.Struct c.cl_meta -> + true + | _ -> false + in + + let rec run ?(just_type = false) e = + let handle = if not just_type then handle else fun e t1 t2 -> { e with etype = gen.greal_type t2 } in + let was_in_value = !in_value in + in_value := true; + match e.eexpr with + | TConst ( TInt _ | TFloat _ | TBool _ as const ) -> + (* take off any Null<> that it may have *) + let t = follow (run_follow gen e.etype) in + (* do not allow constants typed as Single - need to cast them *) + let real_t = match const with + | TInt _ -> gen.gcon.basic.tint + | TFloat _ -> gen.gcon.basic.tfloat + | TBool _ -> gen.gcon.basic.tbool + | _ -> assert false + in + handle e t real_t + | TCast( { eexpr = TConst TNull }, _ ) -> + { e with eexpr = TConst TNull } + | TCast( { eexpr = TCall( { eexpr = TLocal { v_name = "__delegate__" } } as local, [del] ) } as e2, _) -> + { e with eexpr = TCast({ e2 with eexpr = TCall(local, [Type.map_expr run del]) }, None) } + + | TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) -> + let e1 = run ~just_type:true e1 in + let e2 = handle (run e2) e1.etype e2.etype in + { e with eexpr = TBinop(op, clean_cast e1, e2) } + | TBinop ( (Ast.OpShl | Ast.OpShr | Ast.OpUShr as op), e1, e2 ) -> + let e1 = run e1 in + let e2 = handle (run e2) (gen.gcon.basic.tint) e2.etype in + { e with eexpr = TBinop(op, e1, e2) } + | TField(ef, f) -> + handle_type_parameter gen None e (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f [] calls_parameters_explicitly + | TArrayDecl el -> + let et = e.etype in + let base_type = match follow et with + | TInst({ cl_path = ([], "Array") } as cl, bt) -> gen.greal_type_param (TClassDecl cl) bt + | _ -> + gen.gcon.warning (debug_type et) e.epos; + (match gen.gcurrent_class with + | Some cl -> print_endline (path_s cl.cl_path) + | _ -> ()); + assert false + 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 } + | TCall ({ eexpr = TLocal { v_name = "__array__" } } as arr_local, el) -> + let et = e.etype in + let base_type = match follow et with + | TInst(cl, bt) -> gen.greal_type_param (TClassDecl cl) bt + | _ -> assert false + 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 } + | TCall( ({ eexpr = TLocal v } as local), params ) when String.get v.v_name 0 = '_' && String.get v.v_name 1 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> + { e with eexpr = TCall(local, List.map (fun e -> (match e.eexpr with TBlock _ -> in_value := false | _ -> ()); run e) params) } + | TCall( ({ eexpr = TField(ef, f) }) as e1, elist ) -> + handle_type_parameter gen (Some e) (e1) (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f (List.map run elist) calls_parameters_explicitly + + (* the TNew and TSuper code was modified at r6497 *) + | TCall( { eexpr = TConst TSuper } as ef, eparams ) -> + let cl, tparams = match follow ef.etype with + | TInst(cl,p) -> + cl,p + | _ -> assert false 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 = + if is_overload then + let ret = handle e t1 t2 in + match ret.eexpr with + | TCast _ -> ret + | _ -> mk_cast (gen.greal_type t1) e + else + handle e t1 t2 + in + let stl = gen.greal_type_param (TClassDecl sup) stl in + let args, _ = get_fun (apply_params sup.cl_params stl cf.cf_type) in + let eparams = List.map2 (fun e (_,_,t) -> + handle (run e) t e.etype + ) eparams args in + { e with eexpr = TCall(ef, eparams) } + with | Not_found -> + gen.gcon.warning "No overload found for this constructor call" e.epos; + { e with eexpr = TCall(ef, List.map run eparams) }) + | TCall (ef, eparams) -> + (match ef.etype with + | TFun(p, ret) -> + handle ({ e with eexpr = TCall(run ef, List.map2 (fun param (_,_,t) -> handle (run param) t param.etype) eparams p) }) e.etype ret + | _ -> Type.map_expr run e + ) + (* the TNew and TSuper code was modified at r6497 *) + | TNew ({ cl_kind = KTypeParameter _ }, _, _) -> + Type.map_expr run e + | TNew (cl, tparams, eparams) -> (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 = + if is_overload then + let ret = handle e t1 t2 in + match ret.eexpr with + | TCast _ -> ret + | _ -> mk_cast (gen.greal_type t1) e + else + handle e t1 t2 + in + let stl = gen.greal_type_param (TClassDecl sup) stl in + let args, _ = get_fun (apply_params sup.cl_params stl cf.cf_type) in + let eparams = List.map2 (fun e (_,_,t) -> + handle (run e) t e.etype + ) eparams args in + { e with eexpr = TNew(cl, tparams, eparams) } + with | Not_found -> + gen.gcon.warning "No overload found for this constructor call" e.epos; + { e with eexpr = TNew(cl, tparams, List.map run eparams) }) + | TArray(arr, idx) -> + let arr_etype = match follow arr.etype with + | (TInst _ as t) -> t + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + follow (Abstract.get_underlying_type a pl) + | t -> t in + let idx = match gen.greal_type idx.etype with + | TAbstract({ a_path = [],"Int" },_) -> run idx + | _ -> match handle (run idx) gen.gcon.basic.tint (gen.greal_type idx.etype) with + | ({ eexpr = TCast _ } as idx) -> idx + | idx -> mk_cast gen.gcon.basic.tint idx + in + let e = { e with eexpr = TArray(run arr, idx) } in + (* get underlying class (if it's a class *) + (match arr_etype with + | TInst(cl, params) -> + (* see if it implements ArrayAccess *) + (match cl.cl_array_access with + | None -> e + | Some t -> + (* if it does, apply current parameters (and change them) *) + (* let real_t = apply_params_internal (List.map (gen.greal_type_param (TClassDecl cl))) cl params t in *) + let param = apply_params cl.cl_params (gen.greal_type_param (TClassDecl cl) params) t in + let real_t = apply_params cl.cl_params params param in + (* see if it needs a cast *) + + handle (e) (gen.greal_type e.etype) (gen.greal_type real_t) + ) + | _ -> Type.map_expr run e) + | TVar (v, eopt) -> + { e with eexpr = TVar (v, match eopt with + | None -> eopt + | Some e -> Some( handle (run e) v.v_type e.etype )) + } + (* FIXME deal with in_value when using other statements that may not have a TBlock wrapped on them *) + | TIf (econd, ethen, Some(eelse)) when was_in_value -> + { e with eexpr = TIf (handle (run econd) gen.gcon.basic.tbool econd.etype, handle (run ethen) e.etype ethen.etype, Some( handle (run eelse) e.etype eelse.etype ) ) } + | TIf (econd, ethen, eelse) -> + { e with eexpr = TIf (handle (run econd) gen.gcon.basic.tbool econd.etype, (in_value := false; run (mk_block ethen)), Option.map (fun e -> in_value := false; run (mk_block e)) eelse) } + | TWhile (econd, e1, flag) -> + { e with eexpr = TWhile (handle (run econd) gen.gcon.basic.tbool econd.etype, (in_value := false; run (mk_block e1)), flag) } + | TSwitch (cond, el_e_l, edef) -> + { e with eexpr = TSwitch(run cond, List.map (fun (el,e) -> (List.map run el, (in_value := false; run (mk_block e)))) el_e_l, Option.map (fun e -> in_value := false; run (mk_block e)) edef) } +(* | TMatch (cond, en, il_vl_e_l, edef) -> + { e with eexpr = TMatch(run cond, en, List.map (fun (il, vl, e) -> (il, vl, run (mk_block e))) il_vl_e_l, Option.map (fun e -> run (mk_block e)) edef) } *) + | TFor (v,cond,e1) -> + { e with eexpr = TFor(v, run cond, (in_value := false; run (mk_block e1))) } + | TTry (e, ve_l) -> + { e with eexpr = TTry((in_value := false; run (mk_block e)), List.map (fun (v,e) -> in_value := false; (v, run (mk_block e))) ve_l) } + | TBlock el -> + let i = ref 0 in + let len = List.length el in + { e with eexpr = TBlock ( List.map (fun e -> + incr i; + if !i <> len || not was_in_value then + in_value := false; + run e + ) el ) } + | TCast (expr, md) when is_void (follow e.etype) -> + run expr + | TCast (expr, md) -> + let rec get_null e = + match e.eexpr with + | TConst TNull -> Some e + | TParenthesis e | TMeta(_,e) -> get_null e + | _ -> None + in + + (match get_null expr with + | Some enull -> + if gen.gcon.platform = Cs then + { enull with etype = gen.greal_type e.etype } + else + mk_cast (gen.greal_type e.etype) enull + | _ when is_abstract_to_struct expr.etype && type_iseq gen e.etype (get_abstract_impl expr.etype) -> + run { expr with etype = expr.etype } + | _ -> + match gen.greal_type e.etype, gen.greal_type expr.etype with + | (TInst(c,tl) as tinst1), TAbstract({ a_path = ["cs"],"Pointer" }, [tinst2]) when type_iseq gen tinst1 (gen.greal_type tinst2) -> + run expr + | _ -> + let last_unsafe = gen.gon_unsafe_cast in + gen.gon_unsafe_cast <- (fun t t2 pos -> ()); + let ret = handle (run expr) e.etype expr.etype in + gen.gon_unsafe_cast <- last_unsafe; + match ret.eexpr with + | TCast _ -> { ret with etype = gen.greal_type e.etype } + | _ -> { e with eexpr = TCast(ret,md); etype = gen.greal_type e.etype } + ) + (*| TCast _ -> + (* if there is already a cast, we should skip this cast check *) + Type.map_expr run e*) + | TFunction f -> + in_value := false; + Type.map_expr run e + + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + gen.ghandle_cast <- (fun tto tfrom expr -> handle_cast gen expr (gen.greal_type tto) (gen.greal_type tfrom)); + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map; + ReturnCast.configure gen end;; @@ -6055,62 +6828,62 @@ end;; (* ******************************************* *) (* - This is the most hardcore codegen part of the code. There's much to improve so this code can be more readable, but at least it's running correctly right now! This will be improved. (TODO) + This is the most hardcore codegen part of the code. There's much to improve so this code can be more readable, but at least it's running correctly right now! This will be improved. (TODO) - This module will create class fields that enable reflection for targets that have a slow or inexistent reflection abilities. Because of the similarity - of strategies between what should have been different modules, they are all unified in this reflection-enabling class fields. + This module will create class fields that enable reflection for targets that have a slow or inexistent reflection abilities. Because of the similarity + of strategies between what should have been different modules, they are all unified in this reflection-enabling class fields. - They include: - * Get(isStatic, throwErrors, isCheck) / Set fields . Remember to allow implements Dynamic also. - * Invoke fields(isStatic) -> You need to configure how many invoke_field fields there will be. + invokeDynamic - * Has field -> parameter in get field that returns __undefined__ if it doesn't exist. + They include: + * Get(isStatic, throwErrors, isCheck) / Set fields . Remember to allow implements Dynamic also. + * Invoke fields(isStatic) -> You need to configure how many invoke_field fields there will be. + invokeDynamic + * Has field -> parameter in get field that returns __undefined__ if it doesn't exist. - * GetType -> return the current Class<> / Enum<> - * Fields(isStatic) -> returns all the fields / static fields. Remember to allow implements Dynamic also + * GetType -> return the current Class<> / Enum<> + * Fields(isStatic) -> returns all the fields / static fields. Remember to allow implements Dynamic also - * Create(arguments array), CreateEmpty - calls new() or create empty - * getInstanceFields / getClassFields -> show even function fields, everything! + * Create(arguments array), CreateEmpty - calls new() or create empty + * getInstanceFields / getClassFields -> show even function fields, everything! - * deleteField -> only for implements Dynamic + * deleteField -> only for implements Dynamic - for enums: - * createEnum -> invokeField for classes - * createEnumIndex -> use invokeField as well, and use numbers e.g. "0", "1", "2" .... For this, use "@:alias" metadata - * getEnumConstructs -> fields() + for enums: + * createEnum -> invokeField for classes + * createEnumIndex -> use invokeField as well, and use numbers e.g. "0", "1", "2" .... For this, use "@:alias" metadata + * getEnumConstructs -> fields() - need to be solved outside: - * getEnumName - * enumIndex - * + need to be solved outside: + * getEnumName + * enumIndex + * - need to be solved by haxe code: - * enumParameters -> for (field in Reflect.fields(enum)) arr.push(Reflect.field(enum, field)) + need to be solved by haxe code: + * enumParameters -> for (field in Reflect.fields(enum)) arr.push(Reflect.field(enum, field)) - Standard: - if a class contains a @:$enum metadata, it's treated as a converted enum to class + Standard: + if a class contains a @:$enum metadata, it's treated as a converted enum to class - Optimizations: - * if optimize is true, all fields will be hashed by the same hashing function as neko (31 bits int : always positive). Every function that expects a string for the field will expect also an int, for the hash - a string (which is nullable for compile-time hashes) + an int. - At compile-time, a collision will throw an error (like neko). - At runtime, a collision will make a negative int. Negative ints will always resolve to a special Hash<> field which takes a string. - * if optimize is true, Reflect.field/setField will be replaced by either the runtime version (with already hashed string), either by the own .Field()/.SetField() HxObject's version, - if the type is detected to already be hxgen - * TODO: if for() optimization for arrays is disabled, we can replace for(field in Reflect.fields(obj)) to: - for (field in ( (Std.is(obj, HxObject) ? ((HxObject)obj).Fields() : Reflect.fields(obj)) )) // no array copying . for further optimization this could be guaranteed to return - the already hashed fields. + Optimizations: + * if optimize is true, all fields will be hashed by the same hashing function as neko (31 bits int : always positive). Every function that expects a string for the field will expect also an int, for the hash + a string (which is nullable for compile-time hashes) + an int. + At compile-time, a collision will throw an error (like neko). + At runtime, a collision will make a negative int. Negative ints will always resolve to a special Hash<> field which takes a string. + * if optimize is true, Reflect.field/setField will be replaced by either the runtime version (with already hashed string), either by the own .Field()/.SetField() HxObject's version, + if the type is detected to already be hxgen + * TODO: if for() optimization for arrays is disabled, we can replace for(field in Reflect.fields(obj)) to: + for (field in ( (Std.is(obj, HxObject) ? ((HxObject)obj).Fields() : Reflect.fields(obj)) )) // no array copying . for further optimization this could be guaranteed to return + the already hashed fields. - Mappings: - * if create Dynamic class is true, TObjectDecl will be mapped to new DynamicClass(fields, [hashedFields], values) - * + Mappings: + * if create Dynamic class is true, TObjectDecl will be mapped to new DynamicClass(fields, [hashedFields], values) + * - dependencies: - There is no big dependency from this target. Though it should be a syntax filter, mainly one of the first so most expression generation has already been done, - while the AST has its meaning close to haxe's. - Should run before InitFunction so it detects variables containing expressions as "always-execute" expressions, even when using CreateEmpty + dependencies: + There is no big dependency from this target. Though it should be a syntax filter, mainly one of the first so most expression generation has already been done, + while the AST has its meaning close to haxe's. + Should run before InitFunction so it detects variables containing expressions as "always-execute" expressions, even when using CreateEmpty - * Must run before switch() syntax changes + * Must run before switch() syntax changes *) @@ -6118,2134 +6891,2184 @@ open ClosuresToClass;; module ReflectionCFs = struct - let name = "reflection_cfs" + let name = "reflection_cfs" + + type rcf_ctx = + { + rcf_gen : generator_ctx; + rcf_ft : ClosuresToClass.closures_ctx; + rcf_optimize : bool; + mutable rcf_float_special_case : bool; + + mutable rcf_object_iface : tclass; + + mutable rcf_create_getsetinvoke_fields : bool; + (* should we create the get type (get Class)? *) + mutable rcf_create_get_type : bool; + (* should we handle implements dynamic? *) + mutable rcf_handle_impl_dynamic : bool; + (* + create_dyn_overloading_ctor : + when creating the implements dynamic code, we can also create a special constructor for + the actual DynamicObject class, which will receive all its fields from the code outside. + Note that this will only work on targets that support overloading contrstuctors, as any class that extends + our DynamicObject will have an empty super() call + *) + mutable rcf_create_dyn_ctor : bool; + + mutable rcf_max_func_arity : int; + + (* + the hash lookup function. can be an inlined expr or simply a function call. + its only needed features is that it should return the index of the key if found, and the + complement of the index of where it should be inserted if not found (Ints). + + hash->hash_array->length->returning expression + *) + mutable rcf_hash_function : texpr->texpr->texpr->texpr; + + mutable rcf_lookup_function : texpr->texpr; + + (* hash_array->length->pos->value *) + mutable rcf_insert_function : texpr->texpr->texpr->texpr->texpr; + + (* hash_array->length->pos->value *) + mutable rcf_remove_function : texpr->texpr->texpr->texpr; + + (* + class_cl is the real class for Class<> instances. + In the current implementation, due to some targets' limitations, (in particular, Java), + we have to use an empty object so we can access its virtual mehtods. + FIXME find a better way to create Class<> objects in a performant way + *) + mutable rcf_class_cl : tclass option; + (* + Also about the Class<> type, should we crate all classes eagerly? + If false, it means that we should have a way at runtime to create the class when needed by + Type.resolveClass/Enum + *) + mutable rcf_class_eager_creation : bool; + + rcf_hash_fields : (int, string) Hashtbl.t; + + rcf_hash_paths : (path * int, string) Hashtbl.t; + + (* + main expr -> field expr -> field string -> possible hash int (if optimize) -> possible set expr -> should_throw_exceptions -> changed expression + + Changes a get / set field to the runtime resolution function + *) + mutable rcf_on_getset_field : texpr->texpr->string->int32 option->texpr option->bool->texpr; + + mutable rcf_on_call_field : texpr->texpr->string->int32 option->texpr list->texpr; + + mutable rcf_handle_statics : bool; + } + + let new_ctx gen ft object_iface optimize dynamic_getset_field dynamic_call_field hash_function lookup_function insert_function remove_function handle_statics = + { + rcf_gen = gen; + rcf_ft = ft; + + rcf_optimize = optimize; + + rcf_float_special_case = true; + + rcf_object_iface = object_iface; + + rcf_create_getsetinvoke_fields = true; + rcf_create_get_type = true; + + rcf_handle_impl_dynamic = true; + rcf_create_dyn_ctor = true; + + rcf_max_func_arity = 10; + + rcf_hash_function = hash_function; + rcf_lookup_function = lookup_function; + + rcf_insert_function = insert_function; + rcf_remove_function = remove_function; + + rcf_class_cl = None; + rcf_class_eager_creation = false; + + rcf_hash_fields = Hashtbl.create 100; + rcf_hash_paths = Hashtbl.create 100; + + rcf_on_getset_field = dynamic_getset_field; + rcf_on_call_field = dynamic_call_field; + + rcf_handle_statics = handle_statics; + } + + (* + methods as a bool option is a little laziness of my part. + None means that methods are included with normal fields; + Some(true) means collect only methods + Some(false) means collect only fields (and MethDynamic fields) + *) + let collect_fields cl (methods : bool option) (statics : bool option) = + let collected = Hashtbl.create 0 in + let collect cf acc = + if Meta.has Meta.CompilerGenerated cf.cf_meta || Meta.has Meta.SkipReflection cf.cf_meta then + acc + else match methods, cf.cf_kind with + | None, _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc + | Some true, Method MethDynamic -> acc + | Some true, Method _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc + | Some false, Method MethDynamic + | Some false, Var _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc + | _ -> acc + in + let collect_cfs cfs acc = + let rec loop cfs acc = + match cfs with + | [] -> acc + | hd :: tl -> loop tl (collect hd acc) + in + loop cfs acc + in + let rec loop cl acc = + let acc = match statics with + | None -> collect_cfs cl.cl_ordered_fields (collect_cfs cl.cl_ordered_statics acc) + | Some true -> collect_cfs cl.cl_ordered_statics acc + | Some false -> collect_cfs cl.cl_ordered_fields acc + in + match cl.cl_super with + | None -> acc + | Some(cl,_) -> + if not (is_hxgen (TClassDecl cl)) then loop cl acc else acc + in + + loop cl [] + + let hash f = + let h = ref 0 in + for i = 0 to String.length f - 1 do + h := !h * 223 + int_of_char (String.unsafe_get f i); + done; + if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h + + let hash_field ctx f pos = + let h = hash f in + (try + let f2 = Hashtbl.find ctx.rcf_hash_paths (ctx.rcf_gen.gcurrent_path, h) in + if f <> f2 then ctx.rcf_gen.gcon.error ("Field conflict between " ^ f ^ " and " ^ f2) pos + with Not_found -> + Hashtbl.add ctx.rcf_hash_paths (ctx.rcf_gen.gcurrent_path, h) f; + Hashtbl.replace ctx.rcf_hash_fields h f); + h + + (* ( tf_args, switch_var ) *) + let field_type_args ctx pos = + match ctx.rcf_optimize with + | true -> + let field_name, field_hash = alloc_var "field" ctx.rcf_gen.gcon.basic.tstring, alloc_var "hash" ctx.rcf_gen.gcon.basic.tint in + + [field_name, None; field_hash, None], field_hash + | false -> + let field_name = alloc_var "field" ctx.rcf_gen.gcon.basic.tstring in + [field_name, None], field_name + + let hash_field_i32 ctx pos field_name = + let i = hash_field ctx field_name pos in + let i = Int32.of_int (i) in + if i < Int32.zero then + Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30) + else i + + let switch_case ctx pos field_name = + match ctx.rcf_optimize with + | true -> + let i = hash_field_i32 ctx pos field_name in + { eexpr = TConst(TInt(i)); etype = ctx.rcf_gen.gcon.basic.tint; epos = pos } + | false -> + { eexpr = TConst(TString(field_name)); etype = ctx.rcf_gen.gcon.basic.tstring; epos = pos } + + (* + Will implement getField / setField which will follow the following rule: + function getField(field, isStatic, throwErrors, isCheck, handleProperty, isFirst):Dynamic + { + if (isStatic) + { + switch(field) + { + case "aStaticField": return ThisClass.aStaticField; + case "aDynamicField": return ThisClass.aDynamicField; + default: + if (isFirst) return getField_d(field, isStatic, throwErrors, handleProperty, false); + if(throwErrors) throw "Field not found"; else if (isCheck) return __undefined__ else return null; + } + } else { + switch(field) + { + case "aNormalField": return this.aNormalField; + case "aBoolField": return this.aBoolField; + case "aDoubleField": return this.aDoubleField; + default: return getField_d(field, isStatic, throwErrors, isCheck); + } + } + } + + function getField_d(field, isStatic, throwErrors, handleProperty, isFirst):Float + { + if (isStatic) + { + switch(field) + { + case "aDynamicField": return cast ThisClass.aDynamicField; + default: if (throwErrors) throw "Field not found"; else return null; + } + } + etc... + } + + function setField(field, value, isStatic):Dynamic {} + function setField_d(field, value:Float, isStatic):Float {} + *) + + let call_super ctx fn_args ret_t cf cl this_t pos = + { + eexpr = TCall({ + eexpr = TField({ eexpr = TConst(TSuper); etype = this_t; epos = pos }, FInstance(cl,List.map snd cl.cl_params,cf)); + etype = TFun(fun_args fn_args, ret_t); + epos = pos; + }, List.map (fun (v,_) -> mk_local v pos) fn_args); + etype = ret_t; + epos = pos; + } + + let mk_string ctx str pos = + { eexpr = TConst(TString(str)); etype = ctx.rcf_gen.gcon.basic.tstring; epos = pos } + + let mk_int ctx i pos = + { eexpr = TConst(TInt(Int32.of_int i)); etype = ctx.rcf_gen.gcon.basic.tint; epos = pos } + + let mk_bool ctx b pos = + { eexpr = TConst(TBool(b)); etype = ctx.rcf_gen.gcon.basic.tbool; epos = pos } + + let mk_throw ctx str pos = { eexpr = TThrow (mk_string ctx str pos); etype = ctx.rcf_gen.gcon.basic.tvoid; epos = pos } + + let enumerate_dynamic_fields ctx cl when_found = + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + + let vtmp = alloc_var "i" basic.tint in + + let mk_for arr len = + let t = if ctx.rcf_optimize then basic.tint else basic.tstring in + let convert_str e = if ctx.rcf_optimize then ctx.rcf_lookup_function e else e in + let tmpinc = { eexpr = TUnop(Ast.Increment, Ast.Postfix, mk_local vtmp pos); etype = basic.tint; epos = pos } in + { + eexpr = TBlock [ + { eexpr = TBinop(OpAssign, mk_local vtmp pos, mk_int ctx 0 pos); etype = basic.tint; epos = pos }; + { + eexpr = TWhile ( + { eexpr = TBinop(Ast.OpLt, mk_local vtmp pos, len); etype = basic.tbool; epos = pos }, + mk_block (when_found (convert_str { eexpr = TArray (arr, tmpinc); etype = t; epos = pos })), + Ast.NormalWhile + ); + etype = basic.tvoid; + epos = pos + } + ]; + etype = basic.tvoid; + epos = pos; + } + in + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + + { eexpr = TVar (vtmp,None); etype = basic.tvoid; epos = pos } + :: + if ctx.rcf_optimize then + [ + mk_for (mk_this (gen.gmk_internal_name "hx" "hashes") (gen.gclasses.nativearray basic.tint)) (mk_this (gen.gmk_internal_name "hx" "length") basic.tint); + mk_for (mk_this (gen.gmk_internal_name "hx" "hashes_f") (gen.gclasses.nativearray basic.tint)) (mk_this (gen.gmk_internal_name "hx" "length_f") basic.tint); + ] else [ + mk_for (mk_this (gen.gmk_internal_name "hx" "hashes") (gen.gclasses.nativearray basic.tstring)) (mk_this (gen.gmk_internal_name "hx" "length") basic.tint); + mk_for (mk_this (gen.gmk_internal_name "hx" "hashes_f") (gen.gclasses.nativearray basic.tstring)) (mk_this (gen.gmk_internal_name "hx" "length_f") basic.tint); + ] + + (* ********************* + Dynamic lookup + ********************* + + This is the behavior of standard classes. It will replace the error throwing + if a field doesn't exists when looking it up. + + In order for it to work, an implementation for hash_function must be created. + hash_function is the function to be called/inlined that will allow us to lookup the hash into a sorted array of hashes. + A binary search or linear search algorithm may be implemented. The only need is that if not found, the NegBits of + the place where it should be inserted must be returned. + *) + let abstract_dyn_lookup_implementation ctx this hash_local may_value is_float pos = + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + let a_t = if ctx.rcf_optimize then basic.tint else basic.tstring in + let hx_hashes = mk_this (gen.gmk_internal_name "hx" "hashes") (gen.gclasses.nativearray a_t) in + let hx_hashes_f = mk_this (gen.gmk_internal_name "hx" "hashes_f") (gen.gclasses.nativearray a_t) in + let hx_dynamics = mk_this (gen.gmk_internal_name "hx" "dynamics") (gen.gclasses.nativearray t_empty) in + let hx_dynamics_f = mk_this (gen.gmk_internal_name "hx" "dynamics_f") (gen.gclasses.nativearray basic.tfloat) in + let hx_length = mk_this (gen.gmk_internal_name "hx" "length") (basic.tint) in + let hx_length_f = mk_this (gen.gmk_internal_name "hx" "length_f") (basic.tint) in + let res = alloc_var "res" basic.tint in + let fst_hash, snd_hash, fst_dynamics, snd_dynamics, fst_length, snd_length = + if is_float then + hx_hashes_f, hx_hashes, hx_dynamics_f, hx_dynamics, hx_length_f, hx_length + else + hx_hashes, hx_hashes_f, hx_dynamics, hx_dynamics_f, hx_length, hx_length_f + in + let res_local = mk_local res pos in + let gte = { + eexpr = TBinop(Ast.OpGte, res_local, { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }); + etype = basic.tbool; + epos = pos; + } in + let mk_tarray arr idx = + { + eexpr = TArray(arr, idx); + etype = gen.gclasses.nativearray_type arr.etype; + epos = pos; + } + in + let ret_t = if is_float then basic.tfloat else t_dynamic in + + match may_value with + | None -> + (* + var res = lookup(this.__hx_hashes/f, hash); + if (res < 0) + { + res = lookup(this.__hx_hashes_f/_, hash); + if(res < 0) + return null; + else + return __hx_dynamics_f[res]; + } else { + return __hx_dynamics[res]; + } + *) + let block = + [ + { eexpr = TVar(res, Some(ctx.rcf_hash_function hash_local fst_hash fst_length)); etype = basic.tvoid; epos = pos }; + { eexpr = TIf(gte, mk_return (mk_tarray fst_dynamics res_local), Some({ + eexpr = TBlock( + [ + { eexpr = TBinop(Ast.OpAssign, res_local, ctx.rcf_hash_function hash_local snd_hash snd_length); etype = basic.tint; epos = pos }; + { eexpr = TIf(gte, mk_return (mk_tarray snd_dynamics res_local), None); etype = ret_t; epos = pos } + ]); + etype = ret_t; + epos = pos; + })); etype = ret_t; epos = pos } + ] in + block + | Some value_local -> + (* + //if is not float: + //if (isNumber(value_local)) return this.__hx_setField_f(field, getNumber(value_local), false(not static)); + var res = lookup(this.__hx_hashes/f, hash); + if (res >= 0) + { + return __hx_dynamics/f[res] = value_local; + } else { + res = lookup(this.__hx_hashes_f/_, hash); + if (res >= 0) + { + __hx_dynamics_f/_.splice(res,1); + __hx_hashes_f/_.splice(res,1); + } + } + + __hx_hashses/_f.insert(~res, hash); + __hx_dynamics/_f.insert(~res, value_local); + return value_local; + *) + let neg_res = { eexpr = TUnop(Ast.NegBits, Ast.Prefix, res_local); etype = basic.tint; epos = pos } in + + let res2 = alloc_var "res2" basic.tint in + let res2_local = mk_local res2 pos in + let gte2 = { + eexpr = TBinop(Ast.OpGte, res2_local, { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }); + etype = basic.tbool; + epos = pos; + } in + + let block = + [ + { eexpr = TVar(res, Some(ctx.rcf_hash_function hash_local fst_hash fst_length)); etype = basic.tvoid; epos = pos }; + { + eexpr = TIf(gte, + mk_return { eexpr = TBinop(Ast.OpAssign, mk_tarray fst_dynamics res_local, value_local); etype = value_local.etype; epos = pos }, + Some({ eexpr = TBlock([ + { eexpr = TVar( res2, Some(ctx.rcf_hash_function hash_local snd_hash snd_length)); etype = basic.tvoid; epos = pos }; + { + eexpr = TIf(gte2, { eexpr = TBlock([ + ctx.rcf_remove_function snd_hash snd_length res2_local; + ctx.rcf_remove_function snd_dynamics snd_length res2_local; + mk (TUnop(Decrement,Postfix,snd_length)) basic.tint pos + ]); etype = t_dynamic; epos = pos }, None); + etype = t_dynamic; + epos = pos; + } + ]); etype = t_dynamic; epos = pos })); + etype = t_dynamic; + epos = pos; + }; + ctx.rcf_insert_function fst_hash fst_length neg_res hash_local; + ctx.rcf_insert_function fst_dynamics fst_length neg_res value_local; + mk (TUnop(Increment,Postfix,fst_length)) basic.tint pos; + mk_return value_local + ] in + block + + let get_delete_field ctx cl is_dynamic = + let pos = cl.cl_pos in + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let tf_args, switch_var = field_type_args ctx pos in + let local_switch_var = mk_local switch_var pos in + let fun_type = TFun(fun_args tf_args,basic.tbool) in + let cf = mk_class_field (gen.gmk_internal_name "hx" "deleteField") fun_type false pos (Method MethNormal) [] in + let body = if is_dynamic then begin + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + let a_t = if ctx.rcf_optimize then basic.tint else basic.tstring in + let hx_hashes = mk_this (gen.gmk_internal_name "hx" "hashes") (gen.gclasses.nativearray a_t) in + let hx_hashes_f = mk_this (gen.gmk_internal_name "hx" "hashes_f") (gen.gclasses.nativearray a_t) in + let hx_dynamics = mk_this (gen.gmk_internal_name "hx" "dynamics") (gen.gclasses.nativearray t_empty) in + let hx_dynamics_f = mk_this (gen.gmk_internal_name "hx" "dynamics_f") (gen.gclasses.nativearray basic.tfloat) in + let hx_length = mk_this (gen.gmk_internal_name "hx" "length") (basic.tint) in + let hx_length_f = mk_this (gen.gmk_internal_name "hx" "length_f") (basic.tint) in + let res = alloc_var "res" basic.tint in + let res_local = mk_local res pos in + let gte = { + eexpr = TBinop(Ast.OpGte, res_local, { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }); + etype = basic.tbool; + epos = pos; + } in + (* + var res = lookup(this.__hx_hashes, hash); + if (res >= 0) + { + __hx_dynamics.splice(res,1); + __hx_hashes.splice(res,1); + + return true; + } else { + res = lookup(this.__hx_hashes_f, hash); + if (res >= 0) + { + __hx_dynamics_f.splice(res,1); + __hx_hashes_f.splice(res,1); + + return true; + } + } + + return false; + *) + [ + { eexpr = TVar(res,Some(ctx.rcf_hash_function local_switch_var hx_hashes hx_length)); etype = basic.tvoid; epos = pos }; + { + eexpr = TIf(gte, { eexpr = TBlock([ + ctx.rcf_remove_function hx_hashes hx_length res_local; + ctx.rcf_remove_function hx_dynamics hx_length res_local; + mk (TUnop(Decrement,Postfix,hx_length)) basic.tint pos; + mk_return { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } + ]); etype = t_dynamic; epos = pos }, Some({ eexpr = TBlock([ + { eexpr = TBinop(Ast.OpAssign, res_local, ctx.rcf_hash_function local_switch_var hx_hashes_f hx_length_f); etype = basic.tint; epos = pos }; + { eexpr = TIf(gte, { eexpr = TBlock([ + ctx.rcf_remove_function hx_hashes_f hx_length_f res_local; + ctx.rcf_remove_function hx_dynamics_f hx_length_f res_local; + mk (TUnop(Decrement,Postfix,hx_length_f)) basic.tint pos; + mk_return { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } + ]); etype = t_dynamic; epos = pos }, None); etype = t_dynamic; epos = pos } + ]); etype = t_dynamic; epos = pos })); + etype = t_dynamic; + epos = pos; + }; + mk_return { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } + ] + end else + [ + mk_return { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } + ] in + + (* create function *) + let fn = + { + tf_args = tf_args; + tf_type = basic.tbool; + tf_expr = { eexpr = TBlock(body); etype = t_dynamic; epos = pos } + } in + cf.cf_expr <- Some({ eexpr = TFunction(fn); etype = fun_type; epos = pos }); + cf + + let rec is_first_dynamic cl = + match cl.cl_super with + | Some(cl,_) -> + if is_some cl.cl_dynamic then false else is_first_dynamic cl + | None -> true + + let is_override cl = match cl.cl_super with + | Some (cl, _) when is_hxgen (TClassDecl cl) -> true + | _ -> false + + let get_args t = match follow t with + | TFun(args,ret) -> args,ret + | _ -> assert false + + (* WARNING: this will only work if overloading contructors is possible on target language *) + let implement_dynamic_object_ctor ctx cl = + let rec is_side_effects_free e = + match e.eexpr with + | TConst _ + | TLocal _ + | TFunction _ + | TTypeExpr _ -> + true + | TNew(clnew,[],params) when clnew == cl -> + List.for_all is_side_effects_free params + | TUnop(Increment,_,_) + | TUnop(Decrement,_,_) + | TBinop(OpAssign,_,_) + | TBinop(OpAssignOp _,_,_) -> + false + | TUnop(_,_,e) -> + is_side_effects_free e + | TArray(e1,e2) + | TBinop(_,e1,e2) -> + is_side_effects_free e1 && is_side_effects_free e2 + | TIf(cond,e1,Some e2) -> + is_side_effects_free cond && is_side_effects_free e1 && is_side_effects_free e2 + | TField(e,_) + | TParenthesis e | TMeta(_,e) -> is_side_effects_free e + | TArrayDecl el -> List.for_all is_side_effects_free el + | TCast(e,_) -> is_side_effects_free e + | _ -> false + in + + let pos = cl.cl_pos in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let hasht = if ctx.rcf_optimize then basic.tint else basic.tstring in + + let hashes_field = gen.gmk_internal_name "hx" "hashes", gen.gclasses.nativearray hasht in + let hashes_f_field = gen.gmk_internal_name "hx" "hashes_f", gen.gclasses.nativearray hasht in + let dynamics_field = gen.gmk_internal_name "hx" "dynamics", gen.gclasses.nativearray t_empty in + let dynamics_f_field = gen.gmk_internal_name "hx" "dynamics_f", gen.gclasses.nativearray basic.tfloat in + let fields = + [ + hashes_field; + dynamics_field; + hashes_f_field; + dynamics_f_field; + ] in + + let hashes_var = alloc_var (fst hashes_field) (snd hashes_field) in + let hashes_f_var = alloc_var (fst hashes_f_field) (snd hashes_f_field) in + let tf_args = [ + hashes_var, None; + alloc_var (fst dynamics_field) (snd dynamics_field), None; + hashes_f_var, None; + alloc_var (fst dynamics_f_field) (snd dynamics_f_field), None; + ] in + + let this = { eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + let fun_t = TFun(fun_args tf_args,basic.tvoid) in + let ctor = mk_class_field "new" fun_t true pos (Method MethNormal) [] in + ctor.cf_expr <- Some( + { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = + { + eexpr = TBlock( + List.map (fun (v,_) -> + { eexpr = TBinop(Ast.OpAssign, mk_this v.v_name v.v_type, mk_local v pos); etype = v.v_type; epos = pos } + ) tf_args + @ + [ + mk (TBinop(OpAssign, mk_this (gen.gmk_internal_name "hx" "length") basic.tint, gen.gclasses.nativearray_len (mk_local hashes_var pos) pos)) basic.tint pos; + mk (TBinop(OpAssign, mk_this (gen.gmk_internal_name "hx" "length_f") basic.tint, gen.gclasses.nativearray_len (mk_local hashes_f_var pos) pos)) basic.tint pos; + ] + ); + etype = basic.tvoid; + epos = pos + } + }); + etype = fun_t; + epos = pos + }); + + add_constructor cl ctor; + (* default ctor also *) + let ctor = mk_class_field "new" (TFun([],basic.tvoid)) false pos (Method MethNormal) [] in + ctor.cf_expr <- Some { + eexpr = TFunction { + tf_type = basic.tvoid; + tf_args = []; + tf_expr = { + eexpr = TBlock(List.map (fun (f,t) -> + { eexpr = TBinop(Ast.OpAssign, mk_this f t,{ eexpr = TCall(mk_local v_nativearray pos, []); etype = t; epos = pos; }); etype = t; epos = pos } + ) fields); + etype = basic.tvoid; + epos = pos; + } + }; + etype = ctor.cf_type; + epos = pos; + }; + add_constructor cl ctor; + (* and finally we will return a function that transforms a TObjectDecl into a new DynamicObject() call *) + let rec loop objdecl acc acc_f = + match objdecl with + | [] -> acc,acc_f + | (name,expr) :: tl -> + let real_t = gen.greal_type expr.etype in + match follow expr.etype with + | TInst ( { cl_path = ["haxe"], "Int64" }, [] ) -> + loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f + | _ -> + if like_float real_t && not (like_i64 real_t) then + loop tl acc ((name, gen.ghandle_cast basic.tfloat real_t expr) :: acc_f) + else + loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f + in + + let may_hash_field s = + if ctx.rcf_optimize then begin + (* let hash_field ctx f pos = *) + { eexpr = TConst(TInt (hash_field_i32 ctx pos s)); etype = basic.tint; epos = pos } + end else begin + { eexpr = TConst(TString s); etype = basic.tstring; epos = pos } + end + in + + let do_objdecl e objdecl = + let exprs_before = ref [] in + let rec change_exprs decl acc = match decl with + | (name,expr) :: tl -> + if is_side_effects_free expr then + change_exprs tl ((name,expr) :: acc) + else begin + let var = mk_temp gen "odecl" expr.etype in + exprs_before := { eexpr = TVar(var,Some expr); etype = basic.tvoid; epos = expr.epos } :: !exprs_before; + change_exprs tl ((name,mk_local var expr.epos) :: acc) + end + | [] -> acc + in + let objdecl = change_exprs objdecl [] in + + let odecl, odecl_f = loop objdecl [] [] in + let changed_expr = List.map (fun (s,e) -> (may_hash_field s,e)) in + let odecl, odecl_f = changed_expr odecl, changed_expr odecl_f in + let sort_fn (e1,_) (e2,_) = + 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 + in + + let odecl, odecl_f = List.sort sort_fn odecl, List.sort sort_fn odecl_f in + + let ret = { + e with eexpr = TNew(cl,[], + [ + mk_nativearray_decl gen hasht (List.map fst odecl) pos; + mk_nativearray_decl gen t_empty (List.map snd odecl) pos; + mk_nativearray_decl gen hasht (List.map fst odecl_f) pos; + mk_nativearray_decl gen basic.tfloat (List.map snd odecl_f) pos; + ]); + } in + match !exprs_before with + | [] -> ret + | block -> + { + eexpr = TBlock(List.rev block @ [ret]); + etype = ret.etype; + epos = ret.epos; + } + in + do_objdecl + + let implement_dynamics ctx cl = + let pos = cl.cl_pos in + let is_override = is_override cl in + if is_some cl.cl_dynamic then begin + if is_first_dynamic cl then begin + (* + * add hx_hashes, hx_hashes_f, hx_dynamics, hx_dynamics_f to class + * implement hx_deleteField + *) + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let hasht = if ctx.rcf_optimize then basic.tint else basic.tstring in + + let new_fields = + [ + mk_class_field (gen.gmk_internal_name "hx" "hashes") (gen.gclasses.nativearray hasht) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + mk_class_field (gen.gmk_internal_name "hx" "dynamics") (gen.gclasses.nativearray t_empty) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + mk_class_field (gen.gmk_internal_name "hx" "hashes_f") (gen.gclasses.nativearray hasht) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + mk_class_field (gen.gmk_internal_name "hx" "dynamics_f") (gen.gclasses.nativearray basic.tfloat) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + ] in + + (if cl.cl_path <> (["haxe"; "lang"], "DynamicObject") then + List.iter (fun cf -> cf.cf_expr <- Some { eexpr = TCall(mk_local v_nativearray pos, []); etype = cf.cf_type; epos = cf.cf_pos }) new_fields + ); + + let delete = get_delete_field ctx cl true in + + let new_fields = new_fields @ [ + mk_class_field (gen.gmk_internal_name "hx" "length") (basic.tint) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + mk_class_field (gen.gmk_internal_name "hx" "length_f") (basic.tint) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; + delete; + ] in + + List.iter (fun cf -> + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields + ) new_fields; + + (* + let rec last_ctor cl = + match cl.cl_constructor with + | None -> (match cl.cl_super with | None -> None | Some (cl,_) -> last_ctor cl) + | Some c -> Some c + in + *) + (* + in order for the next to work, we need to execute our script before InitFunction, so the expressions inside the variables are initialized by the constructor + *) + (* + Now we need to add their initialization. + This will consist of different parts: + Check if there are constructors. If not, create one and add initialization to it (calling super, ok) + If there are, add as first statement (or second if there is a super() call in the first) + If class has @:dynamicObject meta, also create another new() class with its parameters as constructor arguments + *) + + cl.cl_ordered_fields <- cl.cl_ordered_fields @ new_fields; + if is_override then cl.cl_overrides <- delete :: cl.cl_overrides + end + end else if not is_override then begin + let delete = get_delete_field ctx cl false in + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [delete]; + cl.cl_fields <- PMap.add delete.cf_name delete cl.cl_fields + end + + let implement_create_empty ctx cl = + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + let is_override = is_override cl in + let tparams = List.map (fun _ -> t_empty) cl.cl_params in + + let create = + let arr = alloc_var "arr" (basic.tarray t_dynamic) in + let tf_args = [ arr, None ] in + let t = TFun(fun_args tf_args, t_dynamic) in + let cf = mk_class_field (gen.gmk_internal_name "hx" "create") t false pos (Method MethNormal) [] in + let i = ref 0 in + + let arr_local = mk_local arr pos in + let ctor = if is_some cl.cl_constructor then cl.cl_constructor else get_last_ctor cl in + let params = match ctor with + | None -> [] + | Some ctor -> + List.map (fun (n,_,t) -> + let old = !i in + incr i; + { + eexpr = TArray(arr_local, { eexpr = TConst(TInt (Int32.of_int old)); etype = basic.tint; epos = pos } ); + etype = t_dynamic; + epos = pos + } + ) ( fst ( get_fun ctor.cf_type ) ) + in + let expr = mk_return { + eexpr = TNew(cl, tparams, params); + etype = TInst(cl, tparams); + epos = pos + } in + let fn = { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = t_dynamic; + tf_expr = mk_block expr + }); + etype = t; + epos = pos + } in + cf.cf_expr <- Some fn; + cf + in + + let create_empty = + let t = TFun([],t_dynamic) in + let cf = mk_class_field (gen.gmk_internal_name "hx" "createEmpty") t false pos (Method MethNormal) [] in + let fn = { + eexpr = TFunction({ + tf_args = []; + tf_type = t_dynamic; + tf_expr = mk_block (mk_return ( gen.gtools.rf_create_empty cl tparams pos )) + }); + etype = t; + epos = pos + } in + cf.cf_expr <- Some fn; + cf + in + + (* if rcf_handle_statics is false, there is no reason to make createEmpty/create not be static *) + if ctx.rcf_handle_statics then begin + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [create_empty; create]; + cl.cl_fields <- PMap.add create_empty.cf_name create_empty cl.cl_fields; + cl.cl_fields <- PMap.add create.cf_name create cl.cl_fields; + if is_override then begin + cl.cl_overrides <- create_empty :: create :: cl.cl_overrides + end + end else begin + cl.cl_ordered_statics <- cl.cl_ordered_statics @ [create_empty; create]; + cl.cl_statics <- PMap.add create_empty.cf_name create_empty cl.cl_statics; + cl.cl_statics <- PMap.add create.cf_name create cl.cl_statics + end + + + (* + Implements: + __hx_lookupField(field:String, throwErrors:Bool, isCheck:Bool, handleProperties:Bool, isFirst:Bool):Dynamic + + __hx_lookupField_f(field:String, throwErrors:Bool, handleProperties:Bool, isFirst:Bool):Float + + __hx_lookupSetField(field:String, value:Dynamic, handleProperties:Bool, isFirst:Bool):Dynamic; + + __hx_lookupSetField(field:String, value:Float, handleProperties:Bool, isFirst:Bool):Float; + *) + let implement_final_lookup ctx cl = + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + let is_override = is_override cl in + + let this = { eexpr = TConst(TThis); etype = TInst(cl, List.map snd cl.cl_params); epos = pos } in + + (* + this function will create the class fields and call callback for each version + + callback : is_float fields_args switch_var throw_errors_option is_check_option value_option : texpr list + *) + let create_cfs is_dynamic callback = + let create_cf is_float is_set = + let name = gen.gmk_internal_name "hx" ( (if is_set then "lookupSetField" else "lookupField") ^ (if is_float then "_f" else "") ) in + let field_args, switch_var = field_type_args ctx pos in + let ret_t = if is_float then basic.tfloat else t_dynamic in + let tf_args, throw_errors_opt = + if is_set then + field_args, None + else + let v = alloc_var "throwErrors" basic.tbool in + field_args @ [v,None], Some v + in + let tf_args, is_check_opt = + if is_set || is_float then + tf_args, None + else + let v = alloc_var "isCheck" basic.tbool in + tf_args @ [v,None], Some v + in + let tf_args, value_opt = + if not is_set then + tf_args, None + else + let v = alloc_var "value" ret_t in + field_args @ [v,None], Some v + in + + let fun_t = TFun(fun_args tf_args, ret_t) in + let cf = mk_class_field name fun_t false pos (Method MethNormal) [] in + let block = callback is_float field_args switch_var throw_errors_opt is_check_opt value_opt in + let block = if not is_set then let tl = begin + let throw_errors_local = mk_local (get throw_errors_opt) pos in + let mk_check_throw msg = + { + eexpr = TIf(throw_errors_local, mk_throw ctx msg pos, Some (mk_return (null ret_t pos))); + etype = ret_t; + epos = pos + } in + + let mk_may_check_throw msg = if is_dynamic then mk_return (null ret_t pos) else mk_check_throw msg in + if is_float then begin + [ + mk_may_check_throw "Field not found or incompatible field type."; + ] + end else begin + let is_check_local = mk_local (get is_check_opt) pos in + [ + { + eexpr = TIf(is_check_local, mk_return (undefined pos), Some( mk_may_check_throw "Field not found." )); + etype = ret_t; + epos = pos; + } + ] + end + end in block @ tl else block in + cf.cf_expr <- Some( + { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = ret_t; + tf_expr = { eexpr = TBlock(block); etype = ret_t; epos = pos } + }); + etype = fun_t; + epos = pos + } + ); + cf + in + let cfs = + [ + create_cf false false; + create_cf true false; + create_cf false true; + create_cf true true + ] in + cl.cl_ordered_fields <- cl.cl_ordered_fields @ cfs; + List.iter (fun cf -> + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; + if is_override then cl.cl_overrides <- cf :: cl.cl_overrides + ) cfs + in + + if is_some cl.cl_dynamic then begin + (* let abstract_dyn_lookup_implementation ctx this hash_local may_value is_float pos = *) + (* callback : is_float fields_args switch_var throw_errors_option is_check_option value_option : texpr list *) + if is_first_dynamic cl then + create_cfs true (fun is_float fields_args switch_var _ _ value_opt -> + abstract_dyn_lookup_implementation ctx this (mk_local switch_var pos) (Option.map (fun v -> mk_local v pos) value_opt) is_float pos + ) + end else if not is_override then begin + create_cfs false (fun is_float fields_args switch_var _ _ value_opt -> + match value_opt with + | None -> (* is not set *) + [] + | Some _ -> (* is set *) + if is_float then + [ mk_throw ctx "Cannot access field for writing or incompatible type." pos ] + else + [ mk_throw ctx "Cannot access field for writing." pos ] + ) + end + + (* *) + let implement_get_set ctx cl = + let gen = ctx.rcf_gen in + let mk_cfield is_set is_float = + let pos = cl.cl_pos in + let basic = ctx.rcf_gen.gcon.basic in + let tf_args, switch_var = field_type_args ctx pos in + let field_args = tf_args in + let local_switch_var = { eexpr = TLocal(switch_var); etype = switch_var.v_type; epos = pos } in + let is_static = alloc_var "isStatic" basic.tbool in + let is_static_local = { eexpr = TLocal(is_static); etype = basic.tbool; epos = pos } in + + let handle_prop = alloc_var "handleProperties" basic.tbool in + let handle_prop_local = mk_local handle_prop pos in + + let this = { eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = pos } in + let mk_this_call_raw name fun_t params = + { eexpr = TCall( { (mk_field_access gen this name pos) with etype = fun_t; }, params ); etype = snd (get_args fun_t); epos = pos } + in + + let tf_args = if ctx.rcf_handle_statics then tf_args @ [is_static, None] else tf_args in + + let fun_type = ref (TFun([], basic.tvoid)) in + let fun_name = ctx.rcf_gen.gmk_internal_name "hx" ( (if is_set then "setField" else "getField") ^ (if is_float then "_f" else "") ) in + let cfield = mk_class_field fun_name !fun_type false pos (Method MethNormal) [] in + + let maybe_cast e = e in + + let t = TInst(cl, List.map snd cl.cl_params) in + + (* if it's not latest hxgen class -> check super *) + let mk_do_default args do_default = + match cl.cl_super with + | None -> fun () -> maybe_cast (do_default ()) + | Some (super, sparams) when not (is_hxgen (TClassDecl super)) -> + fun () -> maybe_cast (do_default ()) + | _ -> + fun () -> + mk_return { + eexpr = TCall( + { eexpr = TField({ eexpr = TConst TSuper; etype = t; epos = pos }, FInstance(cl, List.map snd cl.cl_params, cfield)); etype = !fun_type; epos = pos }, + (List.map (fun (v,_) -> mk_local v pos) args) ); + etype = if is_float then basic.tfloat else t_dynamic; + epos = pos; + }; + in + + (* if it is set function, there are some different set fields to do *) + let do_default, do_default_static , do_field, tf_args = if is_set then begin + let value_var = alloc_var "value" (if is_float then basic.tfloat else t_dynamic) in + let value_local = { eexpr = TLocal(value_var); etype = value_var.v_type; epos = pos } in + let tf_args = tf_args @ [value_var,None; handle_prop, None; ] in + let lookup_name = gen.gmk_internal_name "hx" ("lookupSetField" ^ if is_float then "_f" else "") in + + let do_default = + fun () -> + mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [value_var,None]),value_var.v_type)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ value_local ] )) + in + + let do_field cf cf_type is_static = + let get_field ethis = { eexpr = TField (ethis, if is_static then FStatic (cl, cf) else FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf_type; epos = pos } in + let this = if is_static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in + let value_local = if is_float then match follow cf_type with + | TInst({ cl_kind = KTypeParameter _ }, _) -> + mk_cast t_dynamic value_local + | _ -> + value_local + else + value_local + in + + let ret = + { + eexpr = TBlock([ + { + eexpr = TBinop(Ast.OpAssign, + get_field this, + mk_cast cf_type value_local); + etype = cf_type; + epos = pos; + }; + mk_return value_local + ]); + etype = cf_type; + epos = pos; + } in + match cf.cf_kind with + | Var { v_write = AccCall } -> + let bl = + [ + mk_this_call_raw ("set_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ value_local ]; + mk_return value_local + ] in + if Type.is_extern_field cf then + { eexpr = TBlock bl; etype = value_local.etype; epos = pos } + else + { + eexpr = TIf( + handle_prop_local, + { eexpr = TBlock bl; etype = value_local.etype; epos = pos }, + Some ret); + etype = value_local.etype; + epos = pos; + } + | _ -> + ret + in + + (mk_do_default tf_args do_default, do_default, do_field, tf_args) + end else begin + (* (field, isStatic, throwErrors, isCheck):Dynamic *) + let throw_errors = alloc_var "throwErrors" basic.tbool in + let throw_errors_local = mk_local throw_errors pos in + let do_default, tf_args = if not is_float then begin + let is_check = alloc_var "isCheck" basic.tbool in + let is_check_local = mk_local is_check pos in + + let tf_args = tf_args @ [ throw_errors,None; ] in + + (* default: if (isCheck) return __undefined__ else if(throwErrors) throw "Field not found"; else return null; *) + let lookup_name = gen.gmk_internal_name "hx" "lookupField" in + let do_default = + fun () -> + mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [throw_errors,None;is_check,None; ]),t_dynamic)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ throw_errors_local; is_check_local; ] )) + in + + (do_default, tf_args @ [ is_check,None; handle_prop,None; ]) + end else begin + let tf_args = tf_args @ [ throw_errors,None; ] in + + let lookup_name = gen.gmk_internal_name "hx" "lookupField_f" in + let do_default = + fun () -> + mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [throw_errors,None; ]),basic.tfloat)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ throw_errors_local; ] )) + in + + (do_default, tf_args @ [ handle_prop,None; ]) + end in + + let get_field cf cf_type ethis cl name = + match cf.cf_kind with + | Var { v_read = AccCall } when Type.is_extern_field cf -> + mk_return (mk_this_call_raw ("get_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ ]) + | Var { v_read = AccCall } -> + { + eexpr = TIf( + handle_prop_local, + mk_return (mk_this_call_raw ("get_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ ]), + Some { eexpr = TField (ethis, FInstance(cl, List.map snd cl.cl_params, cf)); etype = cf_type; epos = pos } + ); + etype = cf_type; + epos = pos; + } + | Var _ + | Method MethDynamic -> { eexpr = TField (ethis, FInstance(cl,List.map snd cl.cl_params,cf)); etype = cf_type; epos = pos } + | _ -> + { eexpr = TField (this, FClosure(Some (cl,[]), cf)); etype = cf_type; epos = pos } (* TODO: FClosure change *) + in + + let do_field cf cf_type static = + let this = if static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in + match is_float, follow cf_type with + | true, TInst( { cl_kind = KTypeParameter _ }, _ ) -> + mk_return (mk_cast basic.tfloat (mk_cast t_dynamic (get_field cf cf_type this cl cf.cf_name))) + | _ -> + mk_return (maybe_cast (get_field cf cf_type this cl cf.cf_name )) + in + (mk_do_default tf_args do_default, do_default, do_field, tf_args) + end in + + let get_fields static = + let ret = collect_fields cl ( if is_float || is_set then Some (false) else None ) (Some static) in + let ret = if is_set then List.filter (fun (_,cf) -> + match cf.cf_kind with + (* | Var { v_write = AccNever } -> false *) + | _ -> not (Meta.has Meta.ReadOnly cf.cf_meta)) ret + else + List.filter (fun (_,cf) -> + match cf.cf_kind with + (* | Var { v_read = AccNever } -> false *) + | _ -> true) ret in + if is_float then + List.filter (fun (_,cf) -> (* TODO: maybe really apply_params in cf.cf_type. The benefits would be limited, though *) + match follow (ctx.rcf_gen.greal_type (ctx.rcf_gen.gfollow#run_f cf.cf_type)) with + | TDynamic _ | TMono _ + | TInst ({ cl_kind = KTypeParameter _ }, _) -> true + | t when like_float t && not (like_i64 t) -> true + | _ -> false + ) ret + else + (* dynamic will always contain all references *) + ret + in + + (* now we have do_default, do_field and tf_args *) + (* so create the switch expr *) + fun_type := TFun(List.map (fun (v,_) -> (v.v_name, false, v.v_type)) tf_args, if is_float then basic.tfloat else t_dynamic ); + let has_fields = ref false in + + let mk_switch static = + let fields = get_fields static in + let fields = List.filter (fun (_, cf) -> match is_set, cf.cf_kind with + | true, Var { v_write = AccCall } -> true + | false, Var { v_read = AccCall } -> true + | _ -> not (Type.is_extern_field cf)) fields + in + (if fields <> [] then has_fields := true); + let cases = List.map (fun (names, cf) -> + (if names = [] then assert false); + (List.map (switch_case ctx pos) names, do_field cf cf.cf_type static) + ) fields in + let default = Some(if static then do_default_static() else do_default()) in + + { eexpr = TSwitch(local_switch_var, cases, default); etype = basic.tvoid; epos = pos } + in + + let content = if ctx.rcf_handle_statics then + mk_block { eexpr = TIf(is_static_local, mk_switch true, Some(mk_switch false)); etype = basic.tvoid; epos = pos } + else + mk_block (mk_switch false) + in + + let is_override = match cl.cl_super with + | Some (cl, _) when is_hxgen (TClassDecl cl) -> true + | _ -> false + in + + if !has_fields || (not is_override) then begin + let func = + { + tf_args = tf_args; + tf_type = if is_float then basic.tfloat else t_dynamic; + tf_expr = content; + } in + + let func = { eexpr = TFunction(func); etype = !fun_type; epos = pos } in + + cfield.cf_type <- !fun_type; + cfield.cf_expr <- Some func; + + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cfield]; + cl.cl_fields <- PMap.add fun_name cfield cl.cl_fields; + + (if is_override then cl.cl_overrides <- cfield :: cl.cl_overrides) + end else () + in + (if ctx.rcf_float_special_case then mk_cfield true true); + mk_cfield true false; + mk_cfield false false; + (if ctx.rcf_float_special_case then mk_cfield false true) + + let mk_field_access_r ctx pos local field is_float is_static throw_errors set_option = + let is_set = is_some set_option in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + + let fun_name = ctx.rcf_gen.gmk_internal_name "hx" ( (if is_set then "setField" else "getField") ^ (if is_float then "_f" else "") ) in + let tf_args, _ = field_type_args ctx pos in + let tf_args, args = fun_args tf_args, field in + + let rett = if is_float then basic.tfloat else t_dynamic in + let tf_args, args = if ctx.rcf_handle_statics then tf_args @ [ "isStatic", false, basic.tbool ], args @ [is_static] else tf_args, args in + let tf_args, args = if is_set then tf_args @ [ "setVal", false, rett ], args @ [get set_option] else tf_args, args in + let tf_args, args = tf_args @ [ "throwErrors",false,basic.tbool ], args @ [throw_errors] in + let tf_args, args = if is_set || is_float then tf_args, args else tf_args @ [ "isCheck", false, basic.tbool ], args @ [{ eexpr = TConst(TBool false); etype = basic.tbool; epos = pos }] in + let tf_args, args = tf_args @ [ "handleProperties",false,basic.tbool; ], args @ [ mk_bool ctx false pos; ] in + + { + eexpr = TCall( + { (mk_field_access gen local fun_name pos) with etype = TFun(tf_args, rett) }, + args); + etype = rett; + epos = pos; + } + + + let implement_fields ctx cl = + (* + implement two kinds of fields get: + classFields + generic 'fields': receives a parameter isInstance + will receive an Array and start pushing the fields into it. + //add all common fields + if(isInstance) + { + //add methods + } else { + super.fields(isInstance, array); + } + *) + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + (* + let rec has_no_dynamic cl = + if is_some cl.cl_dynamic then + false + else match cl.cl_super with + | None -> true + | Some(cl,_) -> has_no_dynamic cl + in + *) + (* Type.getClassFields() *) + if ctx.rcf_handle_statics then begin + let name = gen.gmk_internal_name "hx" "classFields" in + let v_base_arr = alloc_var "baseArr" (basic.tarray basic.tstring) in + let base_arr = mk_local v_base_arr pos in + + let tf_args = [v_base_arr,None] in + let t = TFun(fun_args tf_args, basic.tvoid) in + let cf = mk_class_field name t false pos (Method MethNormal) [] in + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cf]; + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; + (if is_override cl then cl.cl_overrides <- cf :: cl.cl_overrides); + (* + var newarr = ["field1", "field2"] ...; + *) + let fields = collect_fields cl None (Some true) in + let mk_push value = + { eexpr = TCall({ (mk_field_access gen base_arr "push" pos) with etype = TFun(["x", false, basic.tstring], basic.tint) }, [value] ); etype = basic.tint; epos = pos } + in + + let new_arr_contents = + { + eexpr = TBlock( + List.map (fun (_,cf) -> mk_push { eexpr = TConst(TString(cf.cf_name)); etype = basic.tstring; epos = pos }) fields + ); + etype = basic.tvoid; + epos = pos + } in + + let expr = new_arr_contents in + let fn = + { + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = mk_block expr + } in + + cf.cf_expr <- Some { eexpr = TFunction(fn); etype = t; epos = pos } + end; + + let fields = + (* + function __hx_fields(baseArr:Array, isInstanceFields:Bool) + { + //add all variable fields + //then: + if (isInstanceFields) + { + //add all method fields as well + } else { + super.__hx_fields(baseArr, isInstanceFields); + } + } + *) + let name = gen.gmk_internal_name "hx" "getFields" in + let v_base_arr, v_is_inst = alloc_var "baseArr" (basic.tarray basic.tstring), alloc_var "isInstanceFields" basic.tbool in + let base_arr, is_inst = mk_local v_base_arr pos, mk_local v_is_inst pos in + + let tf_args = (v_base_arr,None) :: (if ctx.rcf_handle_statics then [v_is_inst, None] else []) in + let t = TFun(fun_args tf_args, basic.tvoid) in + let cf = mk_class_field name t false pos (Method MethNormal) [] in + + let mk_push value = + { eexpr = TCall({ (mk_field_access gen base_arr "push" pos) with etype = TFun(["x", false, basic.tstring], basic.tint); }, [value] ); etype = basic.tint; epos = pos } + in + + let has_value = ref false in + let map_fields = + List.map (fun (_,cf) -> + match cf.cf_kind with + | Var _ + | Method MethDynamic when not (List.memq cf cl.cl_overrides) -> + has_value := true; + mk_push { eexpr = TConst(TString(cf.cf_name)); etype = basic.tstring; epos = pos } + | _ -> null basic.tvoid pos + ) + in + + (* + if it is first_dynamic, then we need to enumerate the dynamic fields + *) + let if_not_inst = if is_some cl.cl_dynamic && is_first_dynamic cl then begin + has_value := true; + Some (enumerate_dynamic_fields ctx cl mk_push) + end else + None + in + + let if_not_inst = if is_override cl then + Some( + { + eexpr = TBlock( + (if is_some if_not_inst then get if_not_inst else []) @ + [{ + eexpr = TCall( + { eexpr = TField({ eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_params); epos = pos }, FInstance(cl, List.map snd cl.cl_params, cf)); etype = t; epos = pos }, + base_arr :: (if ctx.rcf_handle_statics then [is_inst] else []) + ); + etype = basic.tvoid; + epos = pos + }] + ); + etype = basic.tvoid; + epos = pos + } + ) else if is_some if_not_inst then + Some({ eexpr = TBlock(get if_not_inst); etype = basic.tvoid; epos = pos }) + else + None + in + + let expr_contents = map_fields (collect_fields cl (Some false) (Some false)) in + let expr_contents = if ctx.rcf_handle_statics then + expr_contents @ + [ { + eexpr = TIf(is_inst, + { eexpr = TBlock( map_fields (collect_fields cl (Some true) (Some false)) ); etype = basic.tvoid; epos = pos }, + if_not_inst + ); + etype = basic.tvoid; + epos = pos + } ] + else + expr_contents @ (if is_some if_not_inst then [ get if_not_inst ] else []) + in + + let expr = + { + eexpr = TBlock( expr_contents ); + etype = basic.tvoid; + epos = pos; + } in + + let fn = + { + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = expr + } in + + (if !has_value || (not (is_override cl)) then begin + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cf]; + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; + (if is_override cl then cl.cl_overrides <- cf :: cl.cl_overrides) + end); + cf.cf_expr <- Some { eexpr = TFunction(fn); etype = t; epos = pos } + in + ignore fields + + let implement_class_methods ctx cl = + ctx.rcf_class_cl <- Some cl; + + let pos = cl.cl_pos in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + (* + fields -> redirected to classFields + getField -> redirected to getField with isStatic true + setField -> isStatic true + invokeField -> isStatic true + getClass -> null + create -> proxy + createEmpty -> proxy + *) + let is_override = is_override cl in + let name = "classProxy" in + let t = (TInst(ctx.rcf_object_iface,[])) in + (* let cf = mk_class_field name t false pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in *) + let register_cf cf override = + cl.cl_ordered_fields <- cf :: cl.cl_ordered_fields; + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; + if override then cl.cl_overrides <- cf :: cl.cl_overrides + in + (* register_cf cf false; *) + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + let proxy = mk_this name t in + + (*let ctor = + let cls = alloc_var "cls" t in + let tf_args = [cls, None] in + let t = TFun(fun_args tf_args, basic.tvoid) in + let cf = mk_class_field "new" t true pos (Method MethNormal) [] in + cf.cf_expr <- Some({ + eexpr = TFunction({ + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = mk_block { + eexpr = TBinop(Ast.OpAssign, proxy, mk_local cls pos); + etype = cls.v_type; + epos = pos; + } + }); + etype = t; + epos = pos; + }); + cf + in + register_cf ctor false;*) + + (* setting it as DynamicObject makes getClass return null *) + let get_class = + cl.cl_meta <- (Meta.DynamicObject, [], pos) :: cl.cl_meta + in + ignore get_class; + + (* fields -> if isInstanceField, redir the method. If not, return classFields *) + let fields = + let name = gen.gmk_internal_name "hx" "getFields" in + let v_base_arr, v_is_inst = alloc_var "baseArr" (basic.tarray basic.tstring), alloc_var "isInstanceFields" basic.tbool in + let base_arr, is_inst = mk_local v_base_arr pos, mk_local v_is_inst pos in + + let tf_args = [ v_base_arr,None; v_is_inst, None ] in + let t = TFun(fun_args tf_args, basic.tvoid) in + let cf = mk_class_field name t false pos (Method MethNormal) [] in + cf.cf_expr <- Some({ + eexpr = TFunction({ + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = mk_block { + eexpr = TIf(is_inst, + { eexpr = TCall( { (mk_field_access gen proxy name pos) with etype = t }, [base_arr;is_inst]); etype = basic.tvoid; epos = pos }, + Some { eexpr = TCall(mk_this (gen.gmk_internal_name "hx" "classFields") (TFun(["baseArr",false,basic.tarray basic.tstring], basic.tvoid)), [base_arr]); etype = basic.tvoid; epos = pos }); + etype = basic.tvoid; + epos = pos + } + }); + etype = t; + epos = pos; + }); + cf + in + register_cf fields (is_override); + + let do_proxy field tf_args ret is_static_argnum = + let field = gen.gmk_internal_name "hx" field in + let t = TFun(fun_args tf_args, ret) in + let cf = mk_class_field field t false pos (Method MethNormal) [] in + let is_void = is_void ret in + let may_return e = if is_void then mk_block e else mk_block (mk_return e) in + let i = ref 0 in + cf.cf_expr <- Some({ + eexpr = TFunction({ + tf_args = tf_args; + tf_type = ret; + tf_expr = may_return { + eexpr = TCall( + { (mk_field_access gen proxy field pos) with etype = t }, + List.map (fun (v,_) -> + let lasti = !i in + incr i; + if lasti = is_static_argnum then + { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } + else + mk_local v pos + ) tf_args); + etype = ret; + epos = pos + } + }); + etype = t; + epos = pos; + }); + cf + in + + (* getClassFields -> redir *) + register_cf (do_proxy "classFields" [ alloc_var "baseArr" (basic.tarray basic.tstring), None ] basic.tvoid (-1)) true; + + (*register_cf (do_proxy "classFields" [ alloc_var "baseArr" (basic.tarray basic.tstring), None ] basic.tvoid (-1)) true;*) + + let fst_args, _ = field_type_args ctx pos in + let fst_args_len = List.length fst_args in + + (* getField -> redir the method with static = true *) + (* setField -> redir the methods with static = true *) + (if ctx.rcf_float_special_case then + register_cf (do_proxy "getField_f" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "throwErrors" basic.tbool, None ]) basic.tfloat fst_args_len) true; + register_cf (do_proxy "setField_f" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "value" basic.tfloat, None ]) basic.tfloat fst_args_len) true + ); + register_cf (do_proxy "getField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "throwErrors" basic.tbool, None; alloc_var "isCheck" basic.tbool, None; alloc_var "handleProperties" basic.tbool,None; ]) t_dynamic fst_args_len) true; + register_cf (do_proxy "setField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "value" t_dynamic, None; alloc_var "handleProperties" basic.tbool,None; ]) t_dynamic fst_args_len) true; + + (* invokeField -> redir the method with static = true *) + register_cf (do_proxy "invokeField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "dynArgs" (basic.tarray t_dynamic), None ]) t_dynamic fst_args_len) true; + + (* create / createEmpty -> redir the method *) + register_cf (do_proxy "create" [ alloc_var "arr" (basic.tarray t_dynamic), None ] t_dynamic (-1)) true; + register_cf (do_proxy "createEmpty" [ ] t_dynamic (-1)) true + + let implement_get_class ctx cl = + (* + if it is DynamicObject, return null; + if it is not, just do the following: + if (typehandle(this.class) == typehandle(MyClass)) + return (MyClass.__hx_class != null ? MyClass.__hx_class : MyClass.__hx_class = create_empty(MyClass)); + return MyClass.__hx_class = haxe.lang.Runtime.getClass(MyClass); + + implement both on static and non-static contexts. This way we can call without references. + *) + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + + let tclass = get_cl ( (Hashtbl.find gen.gtypes ([],"Class")) ) in + let cls = TInst(tclass, [ TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_params) ]) in + let cls_dyn = TInst(tclass, [t_dynamic]) in + + let expr, static_cfs = + if Meta.has Meta.DynamicObject cl.cl_meta then + mk_return (null t_dynamic pos), [] + else + let cache_name = (gen.gmk_internal_name "hx" "class") in + let cache = mk_class_field cache_name cls false pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in + cl.cl_ordered_statics <- cl.cl_ordered_statics @ [ cache ]; + cl.cl_statics <- PMap.add cache_name cache cl.cl_statics; + + let cache_access = mk_static_field_access cl cache_name cls pos in + + + let create_expr = { + eexpr = TNew(get ctx.rcf_class_cl, [], [gen.gtools.rf_create_empty cl (List.map (fun _ -> t_dynamic) cl.cl_params) pos]); + etype = cls; + epos = pos + } in + + (if ctx.rcf_class_eager_creation then cache.cf_expr <- Some(create_expr)); + + let expr = if ctx.rcf_class_eager_creation then + mk_return cache_access + else + mk_return { + eexpr = TIf( + { eexpr = TBinop(Ast.OpNotEq, cache_access, null cls pos); etype = basic.tbool; epos = pos }, + cache_access, + Some({ eexpr = TBinop(Ast.OpAssign, cache_access, create_expr); etype = cls; epos = pos }) + ); + etype = cls; + epos = pos + } + in + expr, [] + in + + let func = + { + eexpr = TFunction({ + tf_args = []; + tf_type = cls_dyn; + tf_expr = expr + }); + etype = TFun([],cls_dyn); + epos = pos + } in + + let get_cl_static = mk_class_field (gen.gmk_internal_name "hx" "getClassStatic") (TFun([],cls_dyn)) false pos (Method MethNormal) [] in + let get_cl = mk_class_field (gen.gmk_internal_name "hx" "getClass") (TFun([],cls_dyn)) false pos (Method MethNormal) [] in + + get_cl_static.cf_expr <- Some func; + get_cl.cf_expr <- Some func; + + let all_f = [get_cl] in + cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_f; + List.iter (fun cf -> cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields) all_f; + + let all_f = get_cl_static :: static_cfs in + cl.cl_ordered_statics <- cl.cl_ordered_statics @ all_f; + List.iter (fun cf -> cl.cl_statics <- PMap.add cf.cf_name cf cl.cl_statics) all_f; + + if is_override cl then cl.cl_overrides <- get_cl :: cl.cl_overrides + + let implement_invokeField ctx ~slow_invoke cl = + (* + There are two ways to implement an haxe reflection-enabled class: + When we extend a non-hxgen class, and when we extend the base HxObject class. + + Because of the added boiler plate we'd add every time we extend a non-hxgen class to implement a big IHxObject + interface, we'll handle the cases differently when implementing each interface. - type rcf_ctx = - { - rcf_gen : generator_ctx; - rcf_ft : ClosuresToClass.closures_ctx; - rcf_optimize : bool; - mutable rcf_float_special_case : bool; + At the IHxObject interface, there's only invokeDynamic(field, args[]), while at the HxObject class there are + the other, more optimized methods, that follow the Function class interface. - mutable rcf_object_iface : tclass; - - mutable rcf_create_getsetinvoke_fields : bool; - (* should we create the get type (get Class)? *) - mutable rcf_create_get_type : bool; - (* should we handle implements dynamic? *) - mutable rcf_handle_impl_dynamic : bool; - (* - create_dyn_overloading_ctor : - when creating the implements dynamic code, we can also create a special constructor for - the actual DynamicObject class, which will receive all its fields from the code outside. - Note that this will only work on targets that support overloading contrstuctors, as any class that extends - our DynamicObject will have an empty super() call - *) - mutable rcf_create_dyn_ctor : bool; - - mutable rcf_max_func_arity : int; - - (* - the hash lookup function. can be an inlined expr or simply a function call. - its only needed features is that it should return the index of the key if found, and the - complement of the index of where it should be inserted if not found (Ints). - - hash->hash_array->returning expression - *) - mutable rcf_hash_function : texpr->texpr->texpr; - - mutable rcf_lookup_function : texpr->texpr; - - (* - class_cl is the real class for Class<> instances. - In the current implementation, due to some targets' limitations, (in particular, Java), - we have to use an empty object so we can access its virtual mehtods. - FIXME find a better way to create Class<> objects in a performant way - *) - mutable rcf_class_cl : tclass option; - (* - Also about the Class<> type, should we crate all classes eagerly? - If false, it means that we should have a way at runtime to create the class when needed by - Type.resolveClass/Enum - *) - mutable rcf_class_eager_creation : bool; - - rcf_hash_fields : (int, string) Hashtbl.t; - - (* - main expr -> field expr -> field string -> possible hash int (if optimize) -> possible set expr -> should_throw_exceptions -> changed expression - - Changes a get / set field to the runtime resolution function - *) - mutable rcf_on_getset_field : texpr->texpr->string->int32 option->texpr option->bool->texpr; - - mutable rcf_on_call_field : texpr->texpr->string->int32 option->texpr list->texpr; - - mutable rcf_handle_statics : bool; - } - - let new_ctx gen ft object_iface optimize dynamic_getset_field dynamic_call_field hash_function lookup_function handle_statics = - { - rcf_gen = gen; - rcf_ft = ft; - - rcf_optimize = optimize; - - rcf_float_special_case = true; - - rcf_object_iface = object_iface; - - rcf_create_getsetinvoke_fields = true; - rcf_create_get_type = true; - - rcf_handle_impl_dynamic = true; - rcf_create_dyn_ctor = true; - - rcf_max_func_arity = 10; - - rcf_hash_function = hash_function; - rcf_lookup_function = lookup_function; - - rcf_class_cl = None; - rcf_class_eager_creation = false; - - rcf_hash_fields = Hashtbl.create 100; - - rcf_on_getset_field = dynamic_getset_field; - rcf_on_call_field = dynamic_call_field; - - rcf_handle_statics = handle_statics; - } - - (* - methods as a bool option is a little laziness of my part. - None means that methods are included with normal fields; - Some(true) means collect only methods - Some(false) means collect only fields (and MethDynamic fields) - *) - let collect_fields cl (methods : bool option) (statics : bool option) = - let collected = Hashtbl.create 0 in - let collect cf acc = - if Meta.has Meta.CompilerGenerated cf.cf_meta || Meta.has Meta.SkipReflection cf.cf_meta then - acc - else match methods, cf.cf_kind with - | None, _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc - | Some true, Method MethDynamic -> acc - | Some true, Method _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc - | Some false, Method MethDynamic - | Some false, Var _ when not (Hashtbl.mem collected cf.cf_name) -> Hashtbl.add collected cf.cf_name true; ([cf.cf_name], cf) :: acc - | _ -> acc - in - let collect_cfs cfs acc = - let rec loop cfs acc = - match cfs with - | [] -> acc - | hd :: tl -> loop tl (collect hd acc) - in - loop cfs acc - in - let rec loop cl acc = - let acc = match statics with - | None -> collect_cfs cl.cl_ordered_fields (collect_cfs cl.cl_ordered_statics acc) - | Some true -> collect_cfs cl.cl_ordered_statics acc - | Some false -> collect_cfs cl.cl_ordered_fields acc - in - match cl.cl_super with - | None -> acc - | Some(cl,_) -> - if not (is_hxgen (TClassDecl cl)) then loop cl acc else acc - in - - loop cl [] - - let hash f = - let h = ref 0 in - for i = 0 to String.length f - 1 do - h := !h * 223 + int_of_char (String.unsafe_get f i); - done; - if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h - - let hash_field ctx f pos = - let h = hash f in - (try - let f2 = Hashtbl.find ctx.rcf_hash_fields h in - if f <> f2 then ctx.rcf_gen.gcon.error ("Field conflict between " ^ f ^ " and " ^ f2) pos - with Not_found -> - Hashtbl.add ctx.rcf_hash_fields h f); - h - - (* ( tf_args, switch_var ) *) - let field_type_args ctx pos = - match ctx.rcf_optimize with - | true -> - let field_name, field_hash = alloc_var "field" ctx.rcf_gen.gcon.basic.tstring, alloc_var "hash" ctx.rcf_gen.gcon.basic.tint in - - [field_name, None; field_hash, None], field_hash - | false -> - let field_name = alloc_var "field" ctx.rcf_gen.gcon.basic.tstring in - [field_name, None], field_name - - let hash_field_i32 ctx pos field_name = - let i = hash_field ctx field_name pos in - let i = Int32.of_int (i) in - if i < Int32.zero then - Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30) - else i - - let switch_case ctx pos field_name = - match ctx.rcf_optimize with - | true -> - let i = hash_field_i32 ctx pos field_name in - { eexpr = TConst(TInt(i)); etype = ctx.rcf_gen.gcon.basic.tint; epos = pos } - | false -> - { eexpr = TConst(TString(field_name)); etype = ctx.rcf_gen.gcon.basic.tstring; epos = pos } - - (* - Will implement getField / setField which will follow the following rule: - function getField(field, isStatic, throwErrors, isCheck, handleProperty, isFirst):Dynamic - { - if (isStatic) - { - switch(field) - { - case "aStaticField": return ThisClass.aStaticField; - case "aDynamicField": return ThisClass.aDynamicField; - default: - if (isFirst) return getField_d(field, isStatic, throwErrors, handleProperty, false); - if(throwErrors) throw "Field not found"; else if (isCheck) return __undefined__ else return null; - } - } else { - switch(field) - { - case "aNormalField": return this.aNormalField; - case "aBoolField": return this.aBoolField; - case "aDoubleField": return this.aDoubleField; - default: return getField_d(field, isStatic, throwErrors, isCheck); - } - } - } - - function getField_d(field, isStatic, throwErrors, handleProperty, isFirst):Float - { - if (isStatic) - { - switch(field) - { - case "aDynamicField": return cast ThisClass.aDynamicField; - default: if (throwErrors) throw "Field not found"; else return null; - } - } - etc... - } - - function setField(field, value, isStatic):Dynamic {} - function setField_d(field, value:Float, isStatic):Float {} - *) - - let call_super ctx fn_args ret_t cf cl this_t pos = - { - eexpr = TCall({ - eexpr = TField({ eexpr = TConst(TSuper); etype = this_t; epos = pos }, FInstance(cl,cf)); - etype = TFun(fun_args fn_args, ret_t); - epos = pos; - }, List.map (fun (v,_) -> mk_local v pos) fn_args); - etype = ret_t; - epos = pos; - } - - let mk_string ctx str pos = - { eexpr = TConst(TString(str)); etype = ctx.rcf_gen.gcon.basic.tstring; epos = pos } - - let mk_int ctx i pos = - { eexpr = TConst(TInt(Int32.of_int i)); etype = ctx.rcf_gen.gcon.basic.tint; epos = pos } - - let mk_bool ctx b pos = - { eexpr = TConst(TBool(b)); etype = ctx.rcf_gen.gcon.basic.tbool; epos = pos } - - let mk_throw ctx str pos = { eexpr = TThrow (mk_string ctx str pos); etype = ctx.rcf_gen.gcon.basic.tvoid; epos = pos } - - let enumerate_dynamic_fields ctx cl when_found = - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in - - let mk_for arr = - let t = if ctx.rcf_optimize then basic.tint else basic.tstring in - let convert_str e = if ctx.rcf_optimize then ctx.rcf_lookup_function e else e in - let var = mk_temp gen "field" t in - { - eexpr = TFor(var, mk_iterator_access gen t arr, mk_block (when_found (convert_str (mk_local var pos)))); - etype = basic.tvoid; - epos = pos; - } - in - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - if ctx.rcf_optimize then - [ - mk_for (mk_this (gen.gmk_internal_name "hx" "hashes") (basic.tarray basic.tint)); - mk_for (mk_this (gen.gmk_internal_name "hx" "hashes_f") (basic.tarray basic.tint)); - ] else [ - mk_for (mk_this (gen.gmk_internal_name "hx" "hashes") (basic.tarray basic.tstring)); - mk_for (mk_this (gen.gmk_internal_name "hx" "hashes_f") (basic.tarray basic.tstring)); - ] - - (* ********************* - Dynamic lookup - ********************* - - This is the behavior of standard classes. It will replace the error throwing - if a field doesn't exists when looking it up. - - In order for it to work, an implementation for hash_function must be created. - hash_function is the function to be called/inlined that will allow us to lookup the hash into a sorted array of hashes. - A binary search or linear search algorithm may be implemented. The only need is that if not found, the NegBits of - the place where it should be inserted must be returned. - *) - let abstract_dyn_lookup_implementation ctx this hash_local may_value is_float pos = - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - let a_t = if ctx.rcf_optimize then basic.tint else basic.tstring in - let hx_hashes = mk_this (gen.gmk_internal_name "hx" "hashes") (basic.tarray a_t) in - let hx_hashes_f = mk_this (gen.gmk_internal_name "hx" "hashes_f") (basic.tarray a_t) in - let hx_dynamics = mk_this (gen.gmk_internal_name "hx" "dynamics") (basic.tarray t_empty) in - let hx_dynamics_f = mk_this (gen.gmk_internal_name "hx" "dynamics_f") (basic.tarray basic.tfloat) in - let res = alloc_var "res" basic.tint in - let fst_hash, snd_hash, fst_dynamics, snd_dynamics = - if is_float then hx_hashes_f, hx_hashes, hx_dynamics_f, hx_dynamics else hx_hashes, hx_hashes_f, hx_dynamics, hx_dynamics_f - in - let res_local = mk_local res pos in - let gte = { - eexpr = TBinop(Ast.OpGte, res_local, { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }); - etype = basic.tbool; - epos = pos; - } in - let get_array_t t = match follow t with | TInst({ cl_path = ([],"Array") },[arrtype]) -> arrtype | _ -> assert false in - let mk_tarray arr idx = - let t = get_array_t arr.etype in - { - eexpr = TArray(arr, idx); - etype = t; - epos = pos; - } - in - let ret_t = if is_float then basic.tfloat else t_dynamic in - - match may_value with - | None -> - (* - var res = lookup(this.__hx_hashes/f, hash); - if (res < 0) - { - res = lookup(this.__hx_hashes_f/_, hash); - if(res < 0) - return null; - else - return __hx_dynamics_f[res]; - } else { - return __hx_dynamics[res]; - } - *) - let block = - [ - { eexpr = TVars([res, Some(ctx.rcf_hash_function hash_local fst_hash)]); etype = basic.tvoid; epos = pos }; - { eexpr = TIf(gte, mk_return (mk_tarray fst_dynamics res_local), Some({ - eexpr = TBlock( - [ - { eexpr = TBinop(Ast.OpAssign, res_local, ctx.rcf_hash_function hash_local snd_hash); etype = basic.tint; epos = pos }; - { eexpr = TIf(gte, mk_return (mk_tarray snd_dynamics res_local), None); etype = ret_t; epos = pos } - ]); - etype = ret_t; - epos = pos; - })); etype = ret_t; epos = pos } - ] in - block - | Some value_local -> - (* - //if is not float: - //if (isNumber(value_local)) return this.__hx_setField_f(field, getNumber(value_local), false(not static)); - var res = lookup(this.__hx_hashes/f, hash); - if (res >= 0) - { - return __hx_dynamics/f[res] = value_local; - } else { - res = lookup(this.__hx_hashes_f/_, hash); - if (res >= 0) - { - __hx_dynamics_f/_.splice(res,1); - __hx_hashes_f/_.splice(res,1); - } - } - - __hx_hashses/_f.insert(~res, hash); - __hx_dynamics/_f.insert(~res, value_local); - return value_local; - *) - let mk_splice arr at_pos = { - eexpr = TCall( - mk_field_access gen arr "splice" pos, - [at_pos; { eexpr = TConst(TInt Int32.one); etype = basic.tint; epos = pos }] - ); - etype = arr.etype; - epos = pos - } in - - let mk_insert arr at_pos value = { - eexpr = TCall( - mk_field_access gen arr "insert" pos, - [at_pos; value]); - etype = basic.tvoid; - epos = pos - } in - - let neg_res = { eexpr = TUnop(Ast.NegBits, Ast.Prefix, res_local); etype = basic.tint; epos = pos } in - - let res2 = alloc_var "res2" basic.tint in - let res2_local = mk_local res2 pos in - - let block = - [ - { eexpr = TVars([res, Some(ctx.rcf_hash_function hash_local fst_hash)]); etype = basic.tvoid; epos = pos }; - { - eexpr = TIf(gte, - mk_return { eexpr = TBinop(Ast.OpAssign, mk_tarray fst_dynamics res_local, value_local); etype = value_local.etype; epos = pos }, - Some({ eexpr = TBlock([ - { eexpr = TVars([ res2, Some(ctx.rcf_hash_function hash_local snd_hash)]); etype = basic.tvoid; epos = pos }; - { - eexpr = TIf(gte, { eexpr = TBlock([ - mk_splice snd_hash res2_local; - mk_splice snd_dynamics res2_local - ]); etype = t_dynamic; epos = pos }, None); - etype = t_dynamic; - epos = pos; - } - ]); etype = t_dynamic; epos = pos })); - etype = t_dynamic; - epos = pos; - }; - mk_insert fst_hash neg_res hash_local; - mk_insert fst_dynamics neg_res value_local; - mk_return value_local - ] in - block - - let get_delete_field ctx cl is_dynamic = - let pos = cl.cl_pos in - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let tf_args, switch_var = field_type_args ctx pos in - let local_switch_var = mk_local switch_var pos in - let fun_type = TFun(fun_args tf_args,basic.tbool) in - let cf = mk_class_field (gen.gmk_internal_name "hx" "deleteField") fun_type false pos (Method MethNormal) [] in - let body = if is_dynamic then begin - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - let a_t = if ctx.rcf_optimize then basic.tint else basic.tstring in - let hx_hashes = mk_this (gen.gmk_internal_name "hx" "hashes") (basic.tarray a_t) in - let hx_hashes_f = mk_this (gen.gmk_internal_name "hx" "hashes_f") (basic.tarray a_t) in - let hx_dynamics = mk_this (gen.gmk_internal_name "hx" "dynamics") (basic.tarray t_empty) in - let hx_dynamics_f = mk_this (gen.gmk_internal_name "hx" "dynamics_f") (basic.tarray basic.tfloat) in - let res = alloc_var "res" basic.tint in - let res_local = mk_local res pos in - let gte = { - eexpr = TBinop(Ast.OpGte, res_local, { eexpr = TConst(TInt(Int32.zero)); etype = basic.tint; epos = pos }); - etype = basic.tbool; - epos = pos; - } in - let mk_splice arr at_pos = { - eexpr = TCall( - mk_field_access gen arr "splice" pos, - [at_pos; { eexpr = TConst(TInt Int32.one); etype = basic.tint; epos = pos }] - ); - etype = arr.etype; - epos = pos - } in - (* - var res = lookup(this.__hx_hashes, hash); - if (res >= 0) - { - __hx_dynamics.splice(res,1); - __hx_hashes.splice(res,1); - - return true; - } else { - res = lookup(this.__hx_hashes_f, hash); - if (res >= 0) - { - __hx_dynamics_f.splice(res,1); - __hx_hashes_f.splice(res,1); - - return true; - } - } - - return false; - *) - [ - { eexpr = TVars([res,Some(ctx.rcf_hash_function local_switch_var hx_hashes)]); etype = basic.tvoid; epos = pos }; - { - eexpr = TIf(gte, { eexpr = TBlock([ - mk_splice hx_hashes res_local; - mk_splice hx_dynamics res_local; - mk_return { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } - ]); etype = t_dynamic; epos = pos }, Some({ eexpr = TBlock([ - { eexpr = TBinop(Ast.OpAssign, res_local, ctx.rcf_hash_function local_switch_var hx_hashes_f); etype = basic.tint; epos = pos }; - { eexpr = TIf(gte, { eexpr = TBlock([ - mk_splice hx_hashes_f res_local; - mk_splice hx_dynamics_f res_local; - mk_return { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } - ]); etype = t_dynamic; epos = pos }, None); etype = t_dynamic; epos = pos } - ]); etype = t_dynamic; epos = pos })); - etype = t_dynamic; - epos = pos; - }; - mk_return { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } - ] - end else - [ - mk_return { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos } - ] in - - (* create function *) - let fn = - { - tf_args = tf_args; - tf_type = basic.tbool; - tf_expr = { eexpr = TBlock(body); etype = t_dynamic; epos = pos } - } in - cf.cf_expr <- Some({ eexpr = TFunction(fn); etype = fun_type; epos = pos }); - cf - - let rec is_first_dynamic cl = - match cl.cl_super with - | Some(cl,_) -> - if is_some cl.cl_dynamic then false else is_first_dynamic cl - | None -> true - - let is_override cl = match cl.cl_super with - | Some (cl, _) when is_hxgen (TClassDecl cl) -> true - | _ -> false - - let get_args t = match follow t with - | TFun(args,ret) -> args,ret - | _ -> assert false - - (* WARNING: this will only work if overloading contructors is possible on target language *) - let implement_dynamic_object_ctor ctx cl = - let rec is_side_effects_free e = - match e.eexpr with - | TConst _ - | TLocal _ - | TFunction _ - | TTypeExpr _ -> - true - | TNew(clnew,[],params) when clnew == cl -> - List.for_all is_side_effects_free params - | TUnop(Increment,_,_) - | TUnop(Decrement,_,_) - | TBinop(OpAssign,_,_) - | TBinop(OpAssignOp _,_,_) -> - false - | TUnop(_,_,e) -> - is_side_effects_free e - | TArray(e1,e2) - | TBinop(_,e1,e2) -> - is_side_effects_free e1 && is_side_effects_free e2 - | TIf(cond,e1,Some e2) -> - is_side_effects_free cond && is_side_effects_free e1 && is_side_effects_free e2 - | TField(e,_) - | TParenthesis e -> is_side_effects_free e - | TArrayDecl el -> List.for_all is_side_effects_free el - | TCast(e,_) -> is_side_effects_free e - | _ -> false - in - - let pos = cl.cl_pos in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let hasht = if ctx.rcf_optimize then basic.tint else basic.tstring in - - let fields = - [ - gen.gmk_internal_name "hx" "hashes", basic.tarray hasht; - gen.gmk_internal_name "hx" "dynamics", basic.tarray t_empty; - gen.gmk_internal_name "hx" "hashes_f", basic.tarray hasht; - gen.gmk_internal_name "hx" "dynamics_f", basic.tarray basic.tfloat; - ] in - let tf_args = List.map (fun (name, t) -> - alloc_var name t, None - ) fields in - - let this = { eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_types); epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - let fun_t = TFun(fun_args tf_args,basic.tvoid) in - let ctor = mk_class_field "new" fun_t true pos (Method MethNormal) [] in - ctor.cf_expr <- Some( - { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = - { - eexpr = TBlock(List.map (fun (v,_) -> - { eexpr = TBinop(Ast.OpAssign, mk_this v.v_name v.v_type, mk_local v pos); etype = v.v_type; epos = pos } - ) tf_args); - etype = basic.tvoid; - epos = pos - } - }); - etype = fun_t; - epos = pos - }); - - add_constructor cl ctor; - (* default ctor also *) - let ctor = mk_class_field "new" (TFun([],basic.tvoid)) false pos (Method MethNormal) [] in - ctor.cf_expr <- Some { - eexpr = TFunction { - tf_type = basic.tvoid; - tf_args = []; - tf_expr = { - eexpr = TBlock(List.map (fun (f,t) -> - { eexpr = TBinop(Ast.OpAssign, mk_this f t,{ eexpr = TArrayDecl([]); etype = t; epos = pos; }); etype = t; epos = pos } - ) fields); - etype = basic.tvoid; - epos = pos; - } - }; - etype = ctor.cf_type; - epos = pos; - }; - add_constructor cl ctor; - (* and finally we will return a function that transforms a TObjectDecl into a new DynamicObject() call *) - let rec loop objdecl acc acc_f = - match objdecl with - | [] -> acc,acc_f - | (name,expr) :: tl -> - let real_t = gen.greal_type expr.etype in - match follow expr.etype with - | TInst ( { cl_path = ["haxe"], "Int64" }, [] ) -> - loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f - | _ -> - if like_float real_t then - loop tl acc ((name, gen.ghandle_cast basic.tfloat real_t expr) :: acc_f) - else - loop tl ((name, gen.ghandle_cast t_dynamic real_t expr) :: acc) acc_f - in - - let may_hash_field s = - if ctx.rcf_optimize then begin - (* let hash_field ctx f pos = *) - { eexpr = TConst(TInt (hash_field_i32 ctx pos s)); etype = basic.tint; epos = pos } - end else begin - { eexpr = TConst(TString s); etype = basic.tstring; epos = pos } - end - in - - let do_objdecl e objdecl = - let exprs_before = ref [] in - let rec change_exprs decl acc = match decl with - | (name,expr) :: tl -> - if is_side_effects_free expr then - change_exprs tl ((name,expr) :: acc) - else begin - let var = mk_temp gen "odecl" expr.etype in - exprs_before := { eexpr = TVars([var,Some expr]); etype = basic.tvoid; epos = expr.epos } :: !exprs_before; - change_exprs tl ((name,mk_local var expr.epos) :: acc) - end - | [] -> acc - in - let objdecl = change_exprs objdecl [] in - - let odecl, odecl_f = loop objdecl [] [] in - let changed_expr = List.map (fun (s,e) -> (may_hash_field s,e)) in - let odecl, odecl_f = changed_expr odecl, changed_expr odecl_f in - let sort_fn (e1,_) (e2,_) = - 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 - in - - let odecl, odecl_f = List.sort sort_fn odecl, List.sort sort_fn odecl_f in - - let mk_arrdecl el t = { eexpr = TArrayDecl(el); etype = t; epos = pos } in - let ret = { - e with eexpr = TNew(cl,[], - [ - mk_arrdecl (List.map fst odecl) (basic.tarray hasht); - mk_arrdecl (List.map snd odecl) (basic.tarray t_empty); - mk_arrdecl (List.map fst odecl_f) (basic.tarray hasht); - mk_arrdecl (List.map snd odecl_f) (basic.tarray basic.tfloat) - ]); - } in - match !exprs_before with - | [] -> ret - | block -> - { - eexpr = TBlock(List.rev block @ [ret]); - etype = ret.etype; - epos = ret.epos; - } - in - do_objdecl - - let implement_dynamics ctx cl = - let pos = cl.cl_pos in - let is_override = is_override cl in - if is_some cl.cl_dynamic then begin - if is_first_dynamic cl then begin - (* - * add hx_hashes, hx_hashes_f, hx_dynamics, hx_dynamics_f to class - * implement hx_deleteField - *) - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let hasht = if ctx.rcf_optimize then basic.tint else basic.tstring in - - let new_fields = - [ - mk_class_field (gen.gmk_internal_name "hx" "hashes") (basic.tarray hasht) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - mk_class_field (gen.gmk_internal_name "hx" "dynamics") (basic.tarray t_empty) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - mk_class_field (gen.gmk_internal_name "hx" "hashes_f") (basic.tarray hasht) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - mk_class_field (gen.gmk_internal_name "hx" "dynamics_f") (basic.tarray basic.tfloat) false pos (Var { v_read = AccNormal; v_write = AccNormal }) []; - ] in - - (if cl.cl_path <> (["haxe"; "lang"], "DynamicObject") then - List.iter (fun cf -> cf.cf_expr <- Some { eexpr = TArrayDecl([]); etype = cf.cf_type; epos = cf.cf_pos }) new_fields - ); - - let delete = get_delete_field ctx cl true in - List.iter (fun cf -> - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields - ) (delete :: new_fields); + Since this will only be called by the Closure class, this conversion can be properly dealt with later. + TODO: create the faster version. By now only invokeDynamic will be implemented + *) + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let pos = cl.cl_pos in + + let has_method = ref false in + + let is_override = ref false in + let rec extends_hxobject cl = + match cl.cl_super with + | None -> true + | Some (cl,_) when is_hxgen (TClassDecl cl) -> is_override := true; extends_hxobject cl + | _ -> false + in + + let field_args, switch_var = field_type_args ctx cl.cl_pos in + let field_args_exprs = List.map (fun (v,_) -> mk_local v pos) field_args in + + let is_static = alloc_var "isStatic" basic.tbool in + let dynamic_arg = alloc_var "dynargs" (basic.tarray t_dynamic) in + let all_args = field_args @ (if ctx.rcf_handle_statics then [ is_static,None; dynamic_arg,None ] else [ dynamic_arg, None ] ) in + let fun_t = TFun(fun_args all_args, t_dynamic) in + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + let apply_object cf = apply_params cf.cf_params (List.map (fun _ -> t_dynamic) cf.cf_params) cf.cf_type in + + let mk_this_call_raw name fun_t params = + { eexpr = TCall( { (mk_field_access gen this name pos) with etype = fun_t }, params ); etype = snd (get_args fun_t); epos = pos } + in + + let mk_this_call cf params = + let t = apply_object cf in + (* the return type transformation into Dynamic *) + (* is meant to avoid return-type casting after functions with *) + (* type parameters are properly inferred at TypeParams.infer_params *) + (* e.g. function getArray(t:T):Array; after infer_params, *) + (* T will be inferred as SomeType, but the returned type will still be typed *) + (* as Array *) + let args, ret = get_args t in + let ret = match follow ret with + | TAbstract ({ a_path = ([], "Void") },[]) -> ret + | _ -> ret + in + mk_this_call_raw cf.cf_name (TFun(args, ret)) params + in + + let mk_static_call cf params = + let t = apply_object cf in + let _, ret = get_fun (follow t) in + { eexpr = TCall( mk_static_field_access cl cf.cf_name t pos, params ); etype = ret; epos = pos } + in + + let extends_hxobject = extends_hxobject cl in + ignore extends_hxobject; + (* creates a dynamicInvoke of the class fields listed here *) (* - let rec last_ctor cl = - match cl.cl_constructor with - | None -> (match cl.cl_super with | None -> None | Some (cl,_) -> last_ctor cl) - | Some c -> Some c - in + function dynamicInvoke(field, isStatic, dynargs) + { + switch(field) + { + case "a": this.a(dynargs[0], dynargs[1], dynargs[2]...); + default: super.dynamicInvoke //or this.getField(field).invokeField(dynargs) + } + } *) - (* - in order for the next to work, we need to execute our script before InitFunction, so the expressions inside the variables are initialized by the constructor - *) - (* - Now we need to add their initialization. - This will consist of different parts: - Check if there are constructors. If not, create one and add initialization to it (calling super, ok) - If there are, add as first statement (or second if there is a super() call in the first) - If class has @:$DynamicObject meta, also create another new() class with its parameters as constructor arguments - *) - - List.iter (fun cf -> - cf.cf_expr <- Some({ eexpr = TArrayDecl([]); etype = cf.cf_type; epos = cf.cf_pos }) - ) new_fields; - - cl.cl_ordered_fields <- cl.cl_ordered_fields @ (delete :: new_fields); - if is_override then cl.cl_overrides <- delete :: cl.cl_overrides - end - end else if not is_override then begin - let delete = get_delete_field ctx cl false in - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [delete]; - cl.cl_fields <- PMap.add delete.cf_name delete cl.cl_fields - end - - let implement_create_empty ctx cl = - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in - let is_override = is_override cl in - let tparams = List.map (fun _ -> t_empty) cl.cl_types in - - let create = - let arr = alloc_var "arr" (basic.tarray t_dynamic) in - let tf_args = [ arr, None ] in - let t = TFun(fun_args tf_args, t_dynamic) in - let cf = mk_class_field (gen.gmk_internal_name "hx" "create") t false pos (Method MethNormal) [] in - let i = ref 0 in - - let arr_local = mk_local arr pos in - let ctor = if is_some cl.cl_constructor then cl.cl_constructor else get_last_ctor cl in - let params = match ctor with - | None -> [] - | Some ctor -> - List.map (fun (n,_,t) -> - let old = !i in - incr i; - { - eexpr = TArray(arr_local, { eexpr = TConst(TInt (Int32.of_int old)); etype = basic.tint; epos = pos } ); - etype = t_dynamic; - epos = pos - } - ) ( fst ( get_fun ctor.cf_type ) ) - in - let expr = mk_return { - eexpr = TNew(cl, tparams, params); - etype = TInst(cl, tparams); - epos = pos - } in - let fn = { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = t_dynamic; - tf_expr = mk_block expr - }); - etype = t; - epos = pos - } in - cf.cf_expr <- Some fn; - cf - in - - let create_empty = - let t = TFun([],t_dynamic) in - let cf = mk_class_field (gen.gmk_internal_name "hx" "createEmpty") t false pos (Method MethNormal) [] in - let fn = { - eexpr = TFunction({ - tf_args = []; - tf_type = t_dynamic; - tf_expr = mk_block (mk_return ( gen.gtools.rf_create_empty cl tparams pos )) - }); - etype = t; - epos = pos - } in - cf.cf_expr <- Some fn; - cf - in - - (* if rcf_handle_statics is false, there is no reason to make createEmpty/create not be static *) - if ctx.rcf_handle_statics then begin - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [create_empty; create]; - cl.cl_fields <- PMap.add create_empty.cf_name create_empty cl.cl_fields; - cl.cl_fields <- PMap.add create.cf_name create cl.cl_fields; - if is_override then begin - cl.cl_overrides <- create_empty :: create :: cl.cl_overrides - end - end else begin - cl.cl_ordered_statics <- cl.cl_ordered_statics @ [create_empty; create]; - cl.cl_statics <- PMap.add create_empty.cf_name create_empty cl.cl_statics; - cl.cl_statics <- PMap.add create.cf_name create cl.cl_statics - end - - - (* - Implements: - __hx_lookupField(field:String, throwErrors:Bool, isCheck:Bool, handleProperties:Bool, isFirst:Bool):Dynamic - - __hx_lookupField_f(field:String, throwErrors:Bool, handleProperties:Bool, isFirst:Bool):Float - - __hx_lookupSetField(field:String, value:Dynamic, handleProperties:Bool, isFirst:Bool):Dynamic; - - __hx_lookupSetField(field:String, value:Float, handleProperties:Bool, isFirst:Bool):Float; - *) - let implement_final_lookup ctx cl = - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in - let is_override = is_override cl in - - let this = { eexpr = TConst(TThis); etype = TInst(cl, List.map snd cl.cl_types); epos = pos } in - - (* - this function will create the class fields and call callback for each version - - callback : is_float fields_args switch_var throw_errors_option is_check_option value_option : texpr list - *) - let create_cfs is_dynamic callback = - let create_cf is_float is_set = - let name = gen.gmk_internal_name "hx" ( (if is_set then "lookupSetField" else "lookupField") ^ (if is_float then "_f" else "") ) in - let field_args, switch_var = field_type_args ctx pos in - let ret_t = if is_float then basic.tfloat else t_dynamic in - let tf_args, throw_errors_opt = - if is_set then - field_args, None - else - let v = alloc_var "throwErrors" basic.tbool in - field_args @ [v,None], Some v - in - let tf_args, is_check_opt = - if is_set || is_float then - tf_args, None - else - let v = alloc_var "isCheck" basic.tbool in - tf_args @ [v,None], Some v - in - let tf_args, value_opt = - if not is_set then - tf_args, None - else - let v = alloc_var "value" ret_t in - field_args @ [v,None], Some v - in - - let fun_t = TFun(fun_args tf_args, ret_t) in - let cf = mk_class_field name fun_t false pos (Method MethNormal) [] in - let block = callback is_float field_args switch_var throw_errors_opt is_check_opt value_opt in - let block = if not is_set then let tl = begin - let throw_errors_local = mk_local (get throw_errors_opt) pos in - let mk_check_throw msg = - { - eexpr = TIf(throw_errors_local, mk_throw ctx msg pos, Some (mk_return (null ret_t pos))); - etype = ret_t; - epos = pos - } in - - let mk_may_check_throw msg = if is_dynamic then mk_return (null ret_t pos) else mk_check_throw msg in - if is_float then begin - [ - mk_may_check_throw "Field not found or incompatible field type."; - ] - end else begin - let undefined = alloc_var "__undefined__" t_dynamic in - let undefined_local = mk_local undefined pos in - let is_check_local = mk_local (get is_check_opt) pos in - [ - { - eexpr = TIf(is_check_local, mk_return undefined_local, Some( mk_may_check_throw "Field not found." )); - etype = ret_t; - epos = pos; - } - ] - end - end in block @ tl else block in - cf.cf_expr <- Some( - { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = ret_t; - tf_expr = { eexpr = TBlock(block); etype = ret_t; epos = pos } - }); - etype = fun_t; - epos = pos - } - ); - cf - in - let cfs = - [ - create_cf false false; - create_cf true false; - create_cf false true; - create_cf true true - ] in - cl.cl_ordered_fields <- cl.cl_ordered_fields @ cfs; - List.iter (fun cf -> - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; - if is_override then cl.cl_overrides <- cf :: cl.cl_overrides - ) cfs - in - - if is_some cl.cl_dynamic then begin - (* let abstract_dyn_lookup_implementation ctx this hash_local may_value is_float pos = *) - (* callback : is_float fields_args switch_var throw_errors_option is_check_option value_option : texpr list *) - if is_first_dynamic cl then - create_cfs true (fun is_float fields_args switch_var _ _ value_opt -> - abstract_dyn_lookup_implementation ctx this (mk_local switch_var pos) (Option.map (fun v -> mk_local v pos) value_opt) is_float pos - ) - end else if not is_override then begin - create_cfs false (fun is_float fields_args switch_var _ _ value_opt -> - match value_opt with - | None -> (* is not set *) - [] - | Some _ -> (* is set *) - if is_float then - [ mk_throw ctx "Cannot access field for writing or incompatible type." pos ] - else - [ mk_throw ctx "Cannot access field for writing." pos ] - ) - end - - (* *) - let implement_get_set ctx cl = - let gen = ctx.rcf_gen in - let mk_cfield is_set is_float = - let pos = cl.cl_pos in - let basic = ctx.rcf_gen.gcon.basic in - let tf_args, switch_var = field_type_args ctx pos in - let field_args = tf_args in - let local_switch_var = { eexpr = TLocal(switch_var); etype = switch_var.v_type; epos = pos } in - let is_static = alloc_var "isStatic" basic.tbool in - let is_static_local = { eexpr = TLocal(is_static); etype = basic.tbool; epos = pos } in - - let handle_prop = alloc_var "handleProperties" basic.tbool in - let handle_prop_local = mk_local handle_prop pos in - - let this = { eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_types); epos = pos } in - let mk_this_call_raw name fun_t params = - { eexpr = TCall( { (mk_field_access gen this name pos) with etype = fun_t; }, params ); etype = snd (get_args fun_t); epos = pos } - in - - let tf_args = if ctx.rcf_handle_statics then tf_args @ [is_static, None] else tf_args in - - let fun_type = ref (TFun([], basic.tvoid)) in - let fun_name = ctx.rcf_gen.gmk_internal_name "hx" ( (if is_set then "setField" else "getField") ^ (if is_float then "_f" else "") ) in - let cfield = mk_class_field fun_name !fun_type false pos (Method MethNormal) [] in - - let maybe_cast e = e in - - let t = TInst(cl, List.map snd cl.cl_types) in - - (* if it's not latest hxgen class -> check super *) - let mk_do_default args do_default = - match cl.cl_super with - | None -> fun () -> maybe_cast (do_default ()) - | Some (super, sparams) when not (is_hxgen (TClassDecl super)) -> - fun () -> maybe_cast (do_default ()) - | _ -> - fun () -> - mk_return { - eexpr = TCall( - { eexpr = TField({ eexpr = TConst TSuper; etype = t; epos = pos }, FInstance(cl, cfield)); etype = !fun_type; epos = pos }, - (List.map (fun (v,_) -> mk_local v pos) args) ); - etype = if is_float then basic.tfloat else t_dynamic; - epos = pos; - }; - in - - (* if it is set function, there are some different set fields to do *) - let do_default, do_default_static , do_field, tf_args = if is_set then begin - let value_var = alloc_var "value" (if is_float then basic.tfloat else t_dynamic) in - let value_local = { eexpr = TLocal(value_var); etype = value_var.v_type; epos = pos } in - let tf_args = tf_args @ [value_var,None; handle_prop, None; ] in - let lookup_name = gen.gmk_internal_name "hx" ("lookupSetField" ^ if is_float then "_f" else "") in - - let do_default = - fun () -> - mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [value_var,None]),value_var.v_type)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ value_local ] )) - in - - let do_field cf cf_type is_static = - let get_field ethis = { eexpr = TField (ethis, if is_static then FStatic (cl, cf) else FInstance(cl, cf)); etype = cf_type; epos = pos } in - let this = if is_static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in - - let ret = - { - eexpr = TBlock([ - { - eexpr = TBinop(Ast.OpAssign, - get_field this, - mk_cast cf_type value_local); - etype = cf_type; - epos = pos; - }; - mk_return value_local - ]); - etype = cf_type; - epos = pos; - } in - match cf.cf_kind with - | Var { v_write = AccCall } -> - let bl = - [ - mk_this_call_raw ("set_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ value_local ]; - mk_return value_local - ] in - if Type.is_extern_field cf then - { eexpr = TBlock bl; etype = value_local.etype; epos = pos } - else - { - eexpr = TIf( - handle_prop_local, - { eexpr = TBlock bl; etype = value_local.etype; epos = pos }, - Some ret); - etype = value_local.etype; - epos = pos; - } - | _ -> - ret - in - - (mk_do_default tf_args do_default, do_default, do_field, tf_args) - end else begin - (* (field, isStatic, throwErrors, isCheck):Dynamic *) - let throw_errors = alloc_var "throwErrors" basic.tbool in - let throw_errors_local = mk_local throw_errors pos in - let do_default, tf_args = if not is_float then begin - let is_check = alloc_var "isCheck" basic.tbool in - let is_check_local = mk_local is_check pos in - - let tf_args = tf_args @ [ throw_errors,None; ] in - - (* default: if (isCheck) return __undefined__ else if(throwErrors) throw "Field not found"; else return null; *) - let lookup_name = gen.gmk_internal_name "hx" "lookupField" in - let do_default = - fun () -> - mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [throw_errors,None;is_check,None; ]),t_dynamic)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ throw_errors_local; is_check_local; ] )) - in - - (do_default, tf_args @ [ is_check,None; handle_prop,None; ]) - end else begin - let tf_args = tf_args @ [ throw_errors,None; ] in - - let lookup_name = gen.gmk_internal_name "hx" "lookupField_f" in - let do_default = - fun () -> - mk_return (mk_this_call_raw lookup_name (TFun(fun_args (field_args @ [throw_errors,None; ]),basic.tfloat)) ( List.map (fun (v,_) -> mk_local v pos) field_args @ [ throw_errors_local; ] )) - in - - (do_default, tf_args @ [ handle_prop,None; ]) - end in - - let get_field cf cf_type ethis cl name = - match cf.cf_kind with - | Var { v_read = AccCall } when Type.is_extern_field cf -> - mk_return (mk_this_call_raw ("get_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ ]) - | Var { v_read = AccCall } -> - { - eexpr = TIf( - handle_prop_local, - mk_return (mk_this_call_raw ("get_" ^ cf.cf_name) (TFun(["value",false,cf.cf_type], cf.cf_type)) [ ]), - Some { eexpr = TField (ethis, FInstance(cl, cf)); etype = cf_type; epos = pos } - ); - etype = cf_type; - epos = pos; - } - | Var _ - | Method MethDynamic -> { eexpr = TField (ethis, FInstance(cl,cf)); etype = cf_type; epos = pos } - | _ -> - { eexpr = TField (this, FClosure(Some cl, cf)); etype = cf_type; epos = pos } - in - - let do_field cf cf_type static = - let this = if static then mk_classtype_access cl pos else { eexpr = TConst(TThis); etype = t; epos = pos } in - match is_float, follow cf_type with - | true, TInst( { cl_kind = KTypeParameter _ }, [] ) -> - mk_return (mk_cast basic.tfloat (mk_cast t_dynamic (get_field cf cf_type this cl cf.cf_name))) - | _ -> - mk_return (maybe_cast (get_field cf cf_type this cl cf.cf_name )) - in - (mk_do_default tf_args do_default, do_default, do_field, tf_args) - end in - - let get_fields static = - let ret = collect_fields cl ( if is_float || is_set then Some (false) else None ) (Some static) in - let ret = if is_set then List.filter (fun (_,cf) -> - match cf.cf_kind with - | Var { v_write = AccNever } -> false - | _ -> not (Meta.has Meta.ReadOnly cf.cf_meta)) ret - else - List.filter (fun (_,cf) -> - match cf.cf_kind with - | Var { v_read = AccNever } -> false - | _ -> true) ret in - if is_float then - List.filter (fun (_,cf) -> (* TODO: maybe really apply_params in cf.cf_type. The benefits would be limited, though *) - match follow (ctx.rcf_gen.greal_type (ctx.rcf_gen.gfollow#run_f cf.cf_type)) with - | TDynamic _ | TMono _ - | TInst ({ cl_kind = KTypeParameter _ }, _) -> true - | t when like_float t -> true - | _ -> false - ) ret - else - (* dynamic will always contain all references *) - ret - in - - (* now we have do_default, do_field and tf_args *) - (* so create the switch expr *) - fun_type := TFun(List.map (fun (v,_) -> (v.v_name, false, v.v_type)) tf_args, if is_float then basic.tfloat else t_dynamic ); - let has_fields = ref false in - - let mk_switch static = - let fields = get_fields static in - let fields = List.filter (fun (_, cf) -> match is_set, cf.cf_kind with - | true, Var { v_write = AccCall } -> true - | false, Var { v_read = AccCall } -> true - | _ -> not (Type.is_extern_field cf)) fields - in - (if fields <> [] then has_fields := true); - let cases = List.map (fun (names, cf) -> - (if names = [] then assert false); - (List.map (switch_case ctx pos) names, do_field cf cf.cf_type static) - ) fields in - let default = Some(if static then do_default_static() else do_default()) in - - { eexpr = TSwitch(local_switch_var, cases, default); etype = basic.tvoid; epos = pos } - in - - let content = if ctx.rcf_handle_statics then - mk_block { eexpr = TIf(is_static_local, mk_switch true, Some(mk_switch false)); etype = basic.tvoid; epos = pos } - else - mk_block (mk_switch false) - in - - let is_override = match cl.cl_super with - | Some (cl, _) when is_hxgen (TClassDecl cl) -> true - | _ -> false - in - - if !has_fields || (not is_override) then begin - let func = - { - tf_args = tf_args; - tf_type = if is_float then basic.tfloat else t_dynamic; - tf_expr = content; - } in - - let func = { eexpr = TFunction(func); etype = !fun_type; epos = pos } in - - cfield.cf_type <- !fun_type; - cfield.cf_expr <- Some func; - - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cfield]; - cl.cl_fields <- PMap.add fun_name cfield cl.cl_fields; - - (if is_override then cl.cl_overrides <- cfield :: cl.cl_overrides) - end else () - in - (if ctx.rcf_float_special_case then mk_cfield true true); - mk_cfield true false; - mk_cfield false false; - (if ctx.rcf_float_special_case then mk_cfield false true) - - let mk_field_access_r ctx pos local field is_float is_static throw_errors set_option = - let is_set = is_some set_option in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - - let fun_name = ctx.rcf_gen.gmk_internal_name "hx" ( (if is_set then "setField" else "getField") ^ (if is_float then "_f" else "") ) in - let tf_args, _ = field_type_args ctx pos in - let tf_args, args = fun_args tf_args, field in - - let rett = if is_float then basic.tfloat else t_dynamic in - let tf_args, args = if ctx.rcf_handle_statics then tf_args @ [ "isStatic", false, basic.tbool ], args @ [is_static] else tf_args, args in - let tf_args, args = if is_set then tf_args @ [ "setVal", false, rett ], args @ [get set_option] else tf_args, args in - let tf_args, args = tf_args @ [ "throwErrors",false,basic.tbool ], args @ [throw_errors] in - let tf_args, args = if is_set || is_float then tf_args, args else tf_args @ [ "isCheck", false, basic.tbool ], args @ [{ eexpr = TConst(TBool false); etype = basic.tbool; epos = pos }] in - let tf_args, args = tf_args @ [ "handleProperties",false,basic.tbool; ], args @ [ mk_bool ctx false pos; ] in - - { - eexpr = TCall( - { (mk_field_access gen local fun_name pos) with etype = TFun(tf_args, rett) }, - args); - etype = rett; - epos = pos; - } - - - let implement_fields ctx cl = - (* - implement two kinds of fields get: - classFields - generic 'fields': receives a parameter isInstance - will receive an Array and start pushing the fields into it. - //add all common fields - if(isInstance) - { - //add methods - } else { - super.fields(isInstance, array); - } - *) - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in + + let dyn_fun = mk_class_field (ctx.rcf_gen.gmk_internal_name "hx" "invokeField") fun_t false cl.cl_pos (Method MethNormal) [] in + + let mk_switch_dyn cfs static old = + (* mk_class_field name t public pos kind params = *) + + let get_case (names,cf) = + has_method := true; + let i = ref 0 in + let dyn_arg_local = mk_local dynamic_arg pos in + let cases = List.map (switch_case ctx pos) names in + (cases, + { eexpr = TReturn(Some ( (if static then mk_static_call else mk_this_call) cf (List.map (fun (name,_,t) -> + let ret = { eexpr = TArray(dyn_arg_local, mk_int ctx !i pos); etype = t_dynamic; epos = pos } in + incr i; + ret + ) (fst (get_args (cf.cf_type))) ) )); + etype = basic.tvoid; + epos = pos + } + ) + in + + let cfs = List.filter (fun (_,cf) -> match cf.cf_kind with + | Method _ -> if List.memq cf cl.cl_overrides then false else true + | _ -> true) cfs + in + + let cases = List.map get_case cfs in + let cases = match old with + | [] -> cases + | _ -> + let ncases = List.map (fun cf -> switch_case ctx pos cf.cf_name) old in + ( ncases, mk_return ((get slow_invoke) this (mk_local (fst (List.hd field_args)) pos) (mk_local dynamic_arg pos)) ) :: cases + in + + let default = if !is_override && not(static) then + (* let call_super ctx fn_args ret_t fn_name this_t pos = *) + { eexpr = TReturn(Some (call_super ctx all_args t_dynamic dyn_fun cl this_t pos) ); etype = basic.tvoid; epos = pos } + (*else if ctx.rcf_create_getsetinvoke_fields then (* we always need to run create_getset before *) + let get_field_name = gen.gmk_internal_name "hx" "getField" in + { eexpr = TReturn( Some (mk_this_call (PMap.find get_field_name cl.cl_fields) [mk_local dynamic_arg pos] ) ); etype = basic.tvoid; epos = pos }*) + else ( + (*let field = (gen.gtools.r_field false (TInst(ctx.rcf_ft.func_class,[])) this (mk_local (fst (List.hd all_args)) pos)) in*) + (* let mk_field_access ctx pos local field is_float is_static throw_errors set_option = *) + let field = mk_field_access_r ctx pos this field_args_exprs false {eexpr = TConst(TBool static); etype = basic.tbool; epos = pos} { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } None in + let field = mk_cast (TInst(ctx.rcf_ft.func_class,[])) field in + mk_return { + eexpr = TCall( + mk_field_access gen field (gen.gmk_internal_name "hx" "invokeDynamic") pos, + [mk_local dynamic_arg pos]); + etype = t_dynamic; + epos = pos + } ) + in + + { + eexpr = TSwitch(mk_local switch_var pos, cases, Some default); + etype = basic.tvoid; + epos = pos; + } + in + + let contents = + let statics = collect_fields cl (Some true) (Some true) in + let nonstatics = collect_fields cl (Some true) (Some false) in + + let old_nonstatics = ref [] in + + let nonstatics = match slow_invoke with + | None -> nonstatics + | Some _ -> + List.filter (fun (n,cf) -> + let is_old = not (PMap.mem cf.cf_name cl.cl_fields) || List.memq cf cl.cl_overrides in + (if is_old then old_nonstatics := cf :: !old_nonstatics); + not is_old + ) nonstatics + in + + if ctx.rcf_handle_statics then + { + eexpr = TIf(mk_local is_static pos, mk_switch_dyn statics true [], Some(mk_switch_dyn nonstatics false !old_nonstatics)); + etype = basic.tvoid; + epos = pos; + } else + mk_switch_dyn nonstatics false !old_nonstatics + in + + dyn_fun.cf_expr <- Some + { + eexpr = TFunction( + { + tf_args = all_args; + tf_type = t_dynamic; + tf_expr = mk_block contents; + }); + etype = TFun(fun_args all_args, t_dynamic); + epos = pos; + }; + if !is_override && not (!has_method) then () else begin + cl.cl_ordered_fields <- cl.cl_ordered_fields @ [dyn_fun]; + cl.cl_fields <- PMap.add dyn_fun.cf_name dyn_fun cl.cl_fields; + (if !is_override then cl.cl_overrides <- dyn_fun :: cl.cl_overrides) + end + + let implement_varargs_cl ctx cl = + let pos = cl.cl_pos in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + + let invokedyn = gen.gmk_internal_name "hx" "invokeDynamic" in + let idyn_t = TFun([gen.gmk_internal_name "fn" "dynargs", false, basic.tarray t_dynamic], t_dynamic) in + let this_idyn = mk_this invokedyn idyn_t in + + let map_fn arity ret vars api = + + let rec loop i acc = + if i < 0 then + acc + else + let obj = api i t_dynamic None in + loop (i - 1) (obj :: acc) + in + + let call_arg = if arity = (-1) then + api (-1) t_dynamic None + else if arity = 0 then + null (basic.tarray t_empty) pos + else + { eexpr = TArrayDecl(loop (arity - 1) []); etype = basic.tarray t_empty; epos = pos } + in + + let expr = { + eexpr = TCall( + this_idyn, + [ call_arg ] + ); + etype = t_dynamic; + epos = pos + } in + + let expr = if like_float ret && not (like_int ret) then mk_cast ret expr else expr in + + [], mk_return expr + in + + let all_cfs = List.filter (fun cf -> cf.cf_name <> "new" && cf.cf_name <> (invokedyn) && match cf.cf_kind with Method _ -> true | _ -> false) (ctx.rcf_ft.map_base_classfields cl true map_fn) in + + cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_cfs; + List.iter (fun cf -> + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields + ) all_cfs; + + List.iter (fun cf -> + cl.cl_overrides <- cf :: cl.cl_overrides + ) cl.cl_ordered_fields + + let implement_closure_cl ctx cl = + let pos = cl.cl_pos in + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + + let field_args, _ = field_type_args ctx pos in + let obj_arg = alloc_var "target" (TInst(ctx.rcf_object_iface, [])) in + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in + let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in + + let tf_args = field_args @ [obj_arg, None] in + let cfs, ctor_body = List.fold_left (fun (acc_cf,acc_expr) (v,_) -> + let cf = mk_class_field v.v_name v.v_type false pos (Var { v_read = AccNormal; v_write = AccNormal } ) [] in + let expr = { eexpr = TBinop(Ast.OpAssign, mk_this v.v_name v.v_type, mk_local v pos); etype = v.v_type; epos = pos } in + (cf :: acc_cf, expr :: acc_expr) + ) ([], []) tf_args in + + let map_fn arity ret vars api = + let this_obj = mk_this "target" (TInst(ctx.rcf_object_iface, [])) in + + let rec loop i acc = + if i < 0 then + acc + else + let obj = api i t_dynamic None in + loop (i - 1) (obj :: acc) + in + + let call_arg = if arity = (-1) then + api (-1) t_dynamic None + else if arity = 0 then + null (basic.tarray t_empty) pos + else + { eexpr = TArrayDecl(loop (arity - 1) []); etype = basic.tarray t_empty; epos = pos } + in + + let expr = { + eexpr = TCall( + mk_field_access gen this_obj (gen.gmk_internal_name "hx" "invokeField") pos, + (List.map (fun (v,_) -> mk_this v.v_name v.v_type) field_args) @ + (if ctx.rcf_handle_statics then + [ { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos }; call_arg ] + else + [ call_arg ] + ) + ); + etype = t_dynamic; + epos = pos + } in + + let expr = if like_float ret && not (like_int ret) then mk_cast ret expr else expr in + + [], mk_return expr + in + + let all_cfs = List.filter (fun cf -> cf.cf_name <> "new" && match cf.cf_kind with Method _ -> true | _ -> false) (ctx.rcf_ft.map_base_classfields cl true map_fn) in + + List.iter (fun cf -> + cl.cl_overrides <- cf :: cl.cl_overrides + ) all_cfs; + let all_cfs = cfs @ all_cfs in + + cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_cfs; + List.iter (fun cf -> + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields + ) all_cfs; + + let ctor_t = TFun(fun_args tf_args, basic.tvoid) in + let ctor_cf = mk_class_field "new" ctor_t true pos (Method MethNormal) [] in + ctor_cf.cf_expr <- Some { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = basic.tvoid; + tf_expr = { eexpr = TBlock({ + eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(cl,[]); epos = pos }, [mk_int ctx (-1) pos; mk_int ctx (-1) pos]); + etype = basic.tvoid; + epos = pos + } :: ctor_body); etype = basic.tvoid; epos = pos } + }); + etype = ctor_t; + epos = pos + }; + + cl.cl_constructor <- Some ctor_cf; + + let closure_fun eclosure e field is_static = + let f = { eexpr = TConst(TString field); etype = basic.tstring; epos = eclosure.epos } in + let args = if ctx.rcf_optimize then [ f; { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else [ f ] in + let args = args @ [ mk_cast (TInst(ctx.rcf_object_iface, [])) e ] in + + { eclosure with eexpr = TNew(cl,[],args) } + in + closure_fun + + let get_closure_func ctx closure_cl = + let gen = ctx.rcf_gen in + let basic = gen.gcon.basic in + let closure_func eclosure e field is_static = + mk_cast eclosure.etype { eclosure with + eexpr = TNew(closure_cl, [], [ + e; + { eexpr = TConst(TString field); etype = basic.tstring; epos = eclosure.epos } + ] @ ( + if ctx.rcf_optimize then [ { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else [] + )); + etype = TInst(closure_cl,[]) + } + in + closure_func + (* - let rec has_no_dynamic cl = - if is_some cl.cl_dynamic then - false - else match cl.cl_super with - | None -> true - | Some(cl,_) -> has_no_dynamic cl - in + main expr -> field expr -> field string -> possible set expr -> should_throw_exceptions -> changed expression + + Changes a get / set + * + mutable rcf_on_getset_field : texpr->texpr->string->texpr option->bool->texpr;*) + + let configure_dynamic_field_access ctx is_synf = + let gen = ctx.rcf_gen in + let is_dynamic expr fexpr field = + match (field_access_esp gen (gen.greal_type fexpr.etype) field) with + | FEnumField _ + | FClassField _ -> false + | _ -> true + in + + let configure = if is_synf then DynamicFieldAccess.configure_as_synf else DynamicFieldAccess.configure in + let maybe_hash = if ctx.rcf_optimize then fun str pos -> Some (hash_field_i32 ctx pos str) else fun str pos -> None in + configure gen (DynamicFieldAccess.abstract_implementation gen is_dynamic + (* print_endline *) + (fun expr fexpr field set is_unsafe -> + let hash = maybe_hash field fexpr.epos in + ctx.rcf_on_getset_field expr fexpr field hash set is_unsafe + ) + (fun ecall fexpr field call_list -> + let hash = maybe_hash field fexpr.epos in + ctx.rcf_on_call_field ecall fexpr field hash call_list + ) + ); + () + + let replace_reflection ctx cl = + let gen = ctx.rcf_gen in + let pos = cl.cl_pos in + + let this_t = TInst(cl, List.map snd cl.cl_params) in + let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in + + let last_fields = match cl.cl_super with + | None -> PMap.empty + | Some (super,_) -> super.cl_fields + in + + let new_fields = ref [] in + let process_cf static cf = + match cf.cf_kind with + | Var _ -> () + | _ when Meta.has Meta.ReplaceReflection cf.cf_meta -> + let name = if String.get cf.cf_name 0 = '_' then String.sub cf.cf_name 1 (String.length cf.cf_name - 1) else cf.cf_name in + let new_name = gen.gmk_internal_name "hx" name in + let new_cf = mk_class_field new_name cf.cf_type cf.cf_public cf.cf_pos cf.cf_kind cf.cf_params in + let fn_args, ret = get_fun (follow cf.cf_type) in + + let tf_args = List.map (fun (name,_,t) -> alloc_var name t, None) fn_args in + let is_void = is_void ret in + let expr = { + eexpr = TCall( + { + eexpr = (if static then TField(mk_classtype_access cl pos, FStatic(cl, cf)) else TField(this, FInstance(cl, List.map snd cl.cl_params, cf))); + etype = cf.cf_type; + epos = cf.cf_pos; + }, + List.map (fun (v,_) -> mk_local v cf.cf_pos) tf_args); + etype = ret; + epos = cf.cf_pos + } in + + let new_f = + { + tf_args = tf_args; + tf_type = ret; + tf_expr = { + eexpr = TBlock([if is_void then expr else mk_return expr]); + etype = ret; + epos = pos; + } + } in + + new_cf.cf_expr <- Some({ eexpr = TFunction(new_f); etype = cf.cf_type; epos = cf.cf_pos}); + + new_fields := new_cf :: !new_fields; + + (if static then cl.cl_statics <- PMap.add new_name new_cf cl.cl_statics else cl.cl_fields <- PMap.add new_name new_cf cl.cl_fields); + + if not static && PMap.mem new_name last_fields then cl.cl_overrides <- new_cf :: cl.cl_overrides + | _ -> () + in + + List.iter (process_cf false) cl.cl_ordered_fields; + cl.cl_ordered_fields <- cl.cl_ordered_fields @ !new_fields; + new_fields := []; + List.iter (process_cf true) cl.cl_ordered_statics; + cl.cl_ordered_statics <- cl.cl_ordered_statics @ !new_fields + + (* ******************************************* *) + (* UniversalBaseClass *) + (* ******************************************* *) + + (* + + Sets the universal base class for hxgen types (HxObject / IHxObject) + + dependencies: + As a rule, it should be one of the last module filters to run so any @:hxgen class created in the process + -Should- only run after TypeParams.RealTypeParams.Modf, since + *) - (* Type.getClassFields() *) - if ctx.rcf_handle_statics then begin - let name = gen.gmk_internal_name "hx" "classFields" in - let v_base_arr = alloc_var "baseArr" (basic.tarray basic.tstring) in - let base_arr = mk_local v_base_arr pos in - - let tf_args = [v_base_arr,None] in - let t = TFun(fun_args tf_args, basic.tvoid) in - let cf = mk_class_field name t false pos (Method MethNormal) [] in - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cf]; - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; - (if is_override cl then cl.cl_overrides <- cf :: cl.cl_overrides); - (* - var newarr = ["field1", "field2"] ...; - *) - let fields = collect_fields cl None (Some true) in - let mk_push value = - { eexpr = TCall({ (mk_field_access gen base_arr "push" pos) with etype = TFun(["x", false, basic.tstring], basic.tint) }, [value] ); etype = basic.tint; epos = pos } - in - - let new_arr_contents = - { - eexpr = TBlock( - List.map (fun (_,cf) -> mk_push { eexpr = TConst(TString(cf.cf_name)); etype = basic.tstring; epos = pos }) fields - ); - etype = basic.tvoid; - epos = pos - } in - - let expr = new_arr_contents in - let fn = - { - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = mk_block expr - } in - - cf.cf_expr <- Some { eexpr = TFunction(fn); etype = t; epos = pos } - end; - - let fields = - (* - function __hx_fields(baseArr:Array, isInstanceFields:Bool) - { - //add all variable fields - //then: - if (isInstanceFields) - { - //add all method fields as well - } else { - super.__hx_fields(baseArr, isInstanceFields); - } - } - *) - let name = gen.gmk_internal_name "hx" "getFields" in - let v_base_arr, v_is_inst = alloc_var "baseArr" (basic.tarray basic.tstring), alloc_var "isInstanceFields" basic.tbool in - let base_arr, is_inst = mk_local v_base_arr pos, mk_local v_is_inst pos in - - let tf_args = (v_base_arr,None) :: (if ctx.rcf_handle_statics then [v_is_inst, None] else []) in - let t = TFun(fun_args tf_args, basic.tvoid) in - let cf = mk_class_field name t false pos (Method MethNormal) [] in - - let mk_push value = - { eexpr = TCall({ (mk_field_access gen base_arr "push" pos) with etype = TFun(["x", false, basic.tstring], basic.tint); }, [value] ); etype = basic.tint; epos = pos } - in - - let has_value = ref false in - let map_fields = - List.map (fun (_,cf) -> - match cf.cf_kind with - | Var _ - | Method MethDynamic when not (List.memq cf cl.cl_overrides) -> - has_value := true; - mk_push { eexpr = TConst(TString(cf.cf_name)); etype = basic.tstring; epos = pos } - | _ -> null basic.tvoid pos - ) - in - - (* - if it is first_dynamic, then we need to enumerate the dynamic fields - *) - let if_not_inst = if is_some cl.cl_dynamic && is_first_dynamic cl then begin - has_value := true; - Some (enumerate_dynamic_fields ctx cl mk_push) - end else - None - in - - let if_not_inst = if is_override cl then - Some( - { - eexpr = TBlock( - (if is_some if_not_inst then get if_not_inst else []) @ - [{ - eexpr = TCall( - { eexpr = TField({ eexpr = TConst TSuper; etype = TInst(cl, List.map snd cl.cl_types); epos = pos }, FInstance(cl, cf)); etype = t; epos = pos }, - base_arr :: (if ctx.rcf_handle_statics then [is_inst] else []) - ); - etype = basic.tvoid; - epos = pos - }] - ); - etype = basic.tvoid; - epos = pos - } - ) else if is_some if_not_inst then - Some({ eexpr = TBlock(get if_not_inst); etype = basic.tvoid; epos = pos }) - else - None - in - - let expr_contents = map_fields (collect_fields cl (Some false) (Some false)) in - let expr_contents = if ctx.rcf_handle_statics then - expr_contents @ - [ { - eexpr = TIf(is_inst, - { eexpr = TBlock( map_fields (collect_fields cl (Some true) (Some false)) ); etype = basic.tvoid; epos = pos }, - if_not_inst - ); - etype = basic.tvoid; - epos = pos - } ] - else - expr_contents @ (if is_some if_not_inst then [ get if_not_inst ] else []) - in - - let expr = - { - eexpr = TBlock( expr_contents ); - etype = basic.tvoid; - epos = pos; - } in - - let fn = - { - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = expr - } in - - (if !has_value || (not (is_override cl)) then begin - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [cf]; - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; - (if is_override cl then cl.cl_overrides <- cf :: cl.cl_overrides) - end); - cf.cf_expr <- Some { eexpr = TFunction(fn); etype = t; epos = pos } - in - ignore fields - - let implement_class_methods ctx cl = - ctx.rcf_class_cl <- Some cl; - - let pos = cl.cl_pos in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - (* - fields -> redirected to classFields - getField -> redirected to getField with isStatic true - setField -> isStatic true - invokeField -> isStatic true - getClass -> null - create -> proxy - createEmpty -> proxy - *) - let is_override = is_override cl in - let name = "classProxy" in - let t = (TInst(ctx.rcf_object_iface,[])) in - (* let cf = mk_class_field name t false pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in *) - let register_cf cf override = - cl.cl_ordered_fields <- cf :: cl.cl_ordered_fields; - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields; - if override then cl.cl_overrides <- cf :: cl.cl_overrides - in - (* register_cf cf false; *) - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - let proxy = mk_this name t in - - (*let ctor = - let cls = alloc_var "cls" t in - let tf_args = [cls, None] in - let t = TFun(fun_args tf_args, basic.tvoid) in - let cf = mk_class_field "new" t true pos (Method MethNormal) [] in - cf.cf_expr <- Some({ - eexpr = TFunction({ - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = mk_block { - eexpr = TBinop(Ast.OpAssign, proxy, mk_local cls pos); - etype = cls.v_type; - epos = pos; - } - }); - etype = t; - epos = pos; - }); - cf - in - register_cf ctor false;*) - - (* setting it as DynamicObject makes getClass return null *) - let get_class = - cl.cl_meta <- (Meta.DynamicObject, [], pos) :: cl.cl_meta - in - ignore get_class; - - (* fields -> if isInstanceField, redir the method. If not, return classFields *) - let fields = - let name = gen.gmk_internal_name "hx" "getFields" in - let v_base_arr, v_is_inst = alloc_var "baseArr" (basic.tarray basic.tstring), alloc_var "isInstanceFields" basic.tbool in - let base_arr, is_inst = mk_local v_base_arr pos, mk_local v_is_inst pos in - - let tf_args = [ v_base_arr,None; v_is_inst, None ] in - let t = TFun(fun_args tf_args, basic.tvoid) in - let cf = mk_class_field name t false pos (Method MethNormal) [] in - cf.cf_expr <- Some({ - eexpr = TFunction({ - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = mk_block { - eexpr = TIf(is_inst, - { eexpr = TCall( { (mk_field_access gen proxy name pos) with etype = t }, [base_arr;is_inst]); etype = basic.tvoid; epos = pos }, - Some { eexpr = TCall(mk_this (gen.gmk_internal_name "hx" "classFields") (TFun(["baseArr",false,basic.tarray basic.tstring], basic.tvoid)), [base_arr]); etype = basic.tvoid; epos = pos }); - etype = basic.tvoid; - epos = pos - } - }); - etype = t; - epos = pos; - }); - cf - in - register_cf fields (is_override); - - let do_proxy field tf_args ret is_static_argnum = - let field = gen.gmk_internal_name "hx" field in - let t = TFun(fun_args tf_args, ret) in - let cf = mk_class_field field t false pos (Method MethNormal) [] in - let is_void = is_void ret in - let may_return e = if is_void then mk_block e else mk_block (mk_return e) in - let i = ref 0 in - cf.cf_expr <- Some({ - eexpr = TFunction({ - tf_args = tf_args; - tf_type = ret; - tf_expr = may_return { - eexpr = TCall( - { (mk_field_access gen proxy field pos) with etype = t }, - List.map (fun (v,_) -> - let lasti = !i in - incr i; - if lasti = is_static_argnum then - { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } - else - mk_local v pos - ) tf_args); - etype = ret; - epos = pos - } - }); - etype = t; - epos = pos; - }); - cf - in - - (* getClassFields -> redir *) - register_cf (do_proxy "classFields" [ alloc_var "baseArr" (basic.tarray basic.tstring), None ] basic.tvoid (-1)) true; - - (*register_cf (do_proxy "classFields" [ alloc_var "baseArr" (basic.tarray basic.tstring), None ] basic.tvoid (-1)) true;*) - - let fst_args, _ = field_type_args ctx pos in - let fst_args_len = List.length fst_args in - - (* getField -> redir the method with static = true *) - (* setField -> redir the methods with static = true *) - (if ctx.rcf_float_special_case then - register_cf (do_proxy "getField_f" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "throwErrors" basic.tbool, None ]) basic.tfloat fst_args_len) true; - register_cf (do_proxy "setField_f" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "value" basic.tfloat, None ]) basic.tfloat fst_args_len) true - ); - register_cf (do_proxy "getField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "throwErrors" basic.tbool, None; alloc_var "isCheck" basic.tbool, None; alloc_var "handleProperties" basic.tbool,None; ]) t_dynamic fst_args_len) true; - register_cf (do_proxy "setField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "value" t_dynamic, None; alloc_var "handleProperties" basic.tbool,None; ]) t_dynamic fst_args_len) true; - - (* invokeField -> redir the method with static = true *) - register_cf (do_proxy "invokeField" (fst_args @ [ alloc_var "isStatic" basic.tbool, None; alloc_var "dynArgs" (basic.tarray t_dynamic), None ]) t_dynamic fst_args_len) true; - - (* create / createEmpty -> redir the method *) - register_cf (do_proxy "create" [ alloc_var "arr" (basic.tarray t_dynamic), None ] t_dynamic (-1)) true; - register_cf (do_proxy "createEmpty" [ ] t_dynamic (-1)) true - - let implement_get_class ctx cl = - (* - if it is DynamicObject, return null; - if it is not, just do the following: - if (typehandle(this.class) == typehandle(MyClass)) - return (MyClass.__hx_class != null ? MyClass.__hx_class : MyClass.__hx_class = create_empty(MyClass)); - return MyClass.__hx_class = haxe.lang.Runtime.getClass(MyClass); - - implement both on static and non-static contexts. This way we can call without references. - *) - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in - - let tclass = get_cl ( (Hashtbl.find gen.gtypes ([],"Class")) ) in - let cls = TInst(tclass, [ TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_types) ]) in - let cls_dyn = TInst(tclass, [t_dynamic]) in - - let expr, static_cfs = - if Meta.has Meta.DynamicObject cl.cl_meta then - mk_return (null t_dynamic pos), [] - else - let cache_name = (gen.gmk_internal_name "hx" "class") in - let cache = mk_class_field cache_name cls false pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in - cl.cl_ordered_statics <- cl.cl_ordered_statics @ [ cache ]; - cl.cl_statics <- PMap.add cache_name cache cl.cl_statics; - - let cache_access = mk_static_field_access cl cache_name cls pos in - - - let create_expr = { - eexpr = TNew(get ctx.rcf_class_cl, [], [gen.gtools.rf_create_empty cl (List.map (fun _ -> t_dynamic) cl.cl_types) pos]); - etype = cls; - epos = pos - } in - - (if ctx.rcf_class_eager_creation then cache.cf_expr <- Some(create_expr)); - - let expr = if ctx.rcf_class_eager_creation then - mk_return cache_access - else - mk_return { - eexpr = TIf( - { eexpr = TBinop(Ast.OpNotEq, cache_access, null cls pos); etype = basic.tbool; epos = pos }, - cache_access, - Some({ eexpr = TBinop(Ast.OpAssign, cache_access, create_expr); etype = cls; epos = pos }) - ); - etype = cls; - epos = pos - } - in - expr, [] - in - - let func = - { - eexpr = TFunction({ - tf_args = []; - tf_type = cls_dyn; - tf_expr = expr - }); - etype = TFun([],cls_dyn); - epos = pos - } in - - let get_cl_static = mk_class_field (gen.gmk_internal_name "hx" "getClassStatic") (TFun([],cls_dyn)) false pos (Method MethNormal) [] in - let get_cl = mk_class_field (gen.gmk_internal_name "hx" "getClass") (TFun([],cls_dyn)) false pos (Method MethNormal) [] in - - get_cl_static.cf_expr <- Some func; - get_cl.cf_expr <- Some func; - - let all_f = [get_cl] in - cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_f; - List.iter (fun cf -> cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields) all_f; - - let all_f = get_cl_static :: static_cfs in - cl.cl_ordered_statics <- cl.cl_ordered_statics @ all_f; - List.iter (fun cf -> cl.cl_statics <- PMap.add cf.cf_name cf cl.cl_statics) all_f; - - if is_override cl then cl.cl_overrides <- get_cl :: cl.cl_overrides - - let implement_invokeField ctx ~slow_invoke cl = - (* - There are two ways to implement an haxe reflection-enabled class: - When we extend a non-hxgen class, and when we extend the base HxObject class. - - Because of the added boiler plate we'd add every time we extend a non-hxgen class to implement a big IHxObject - interface, we'll handle the cases differently when implementing each interface. - - At the IHxObject interface, there's only invokeDynamic(field, args[]), while at the HxObject class there are - the other, more optimized methods, that follow the Function class interface. - - Since this will only be called by the Closure class, this conversion can be properly dealt with later. - - TODO: create the faster version. By now only invokeDynamic will be implemented - *) - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let pos = cl.cl_pos in - - let has_method = ref false in - - let is_override = ref false in - let rec extends_hxobject cl = - match cl.cl_super with - | None -> true - | Some (cl,_) when is_hxgen (TClassDecl cl) -> is_override := true; extends_hxobject cl - | _ -> false - in - - let field_args, switch_var = field_type_args ctx cl.cl_pos in - let field_args_exprs = List.map (fun (v,_) -> mk_local v pos) field_args in - - let is_static = alloc_var "isStatic" basic.tbool in - let dynamic_arg = alloc_var "dynargs" (basic.tarray t_dynamic) in - let all_args = field_args @ (if ctx.rcf_handle_statics then [ is_static,None; dynamic_arg,None ] else [ dynamic_arg, None ] ) in - let fun_t = TFun(fun_args all_args, t_dynamic) in - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - let apply_object cf = apply_params cf.cf_params (List.map (fun _ -> t_dynamic) cf.cf_params) cf.cf_type in - - let mk_this_call_raw name fun_t params = - { eexpr = TCall( { (mk_field_access gen this name pos) with etype = fun_t }, params ); etype = snd (get_args fun_t); epos = pos } - in - - let mk_this_call cf params = - let t = apply_object cf in - (* the return type transformation into Dynamic *) - (* is meant to avoid return-type casting after functions with *) - (* type parameters are properly inferred at TypeParams.infer_params *) - (* e.g. function getArray(t:T):Array; after infer_params, *) - (* T will be inferred as SomeType, but the returned type will still be typed *) - (* as Array *) - let args, ret = get_args t in - let ret = match follow ret with - | TEnum({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> ret - | _ -> ret - in - mk_this_call_raw cf.cf_name (TFun(args, ret)) params - in - - let mk_static_call cf params = - let t = apply_object cf in - let _, ret = get_fun (follow t) in - { eexpr = TCall( mk_static_field_access cl cf.cf_name t pos, params ); etype = ret; epos = pos } - in - - let extends_hxobject = extends_hxobject cl in - ignore extends_hxobject; - (* creates a dynamicInvoke of the class fields listed here *) - (* - function dynamicInvoke(field, isStatic, dynargs) - { - switch(field) - { - case "a": this.a(dynargs[0], dynargs[1], dynargs[2]...); - default: super.dynamicInvoke //or this.getField(field).invokeField(dynargs) - } - } - *) - - let dyn_fun = mk_class_field (ctx.rcf_gen.gmk_internal_name "hx" "invokeField") fun_t false cl.cl_pos (Method MethNormal) [] in - - let mk_switch_dyn cfs static old = - (* mk_class_field name t public pos kind params = *) - - let get_case (names,cf) = - has_method := true; - let i = ref 0 in - let dyn_arg_local = mk_local dynamic_arg pos in - let cases = List.map (switch_case ctx pos) names in - (cases, - { eexpr = TReturn(Some ( (if static then mk_static_call else mk_this_call) cf (List.map (fun (name,_,t) -> - let ret = { eexpr = TArray(dyn_arg_local, mk_int ctx !i pos); etype = t_dynamic; epos = pos } in - incr i; - ret - ) (fst (get_args (cf.cf_type))) ) )); - etype = basic.tvoid; - epos = pos - } - ) - in - - let cfs = List.filter (fun (_,cf) -> match cf.cf_kind with - | Method _ -> if List.memq cf cl.cl_overrides then false else true - | _ -> true) cfs - in - - let cases = List.map get_case cfs in - let cases = match old with - | [] -> cases - | _ -> - let ncases = List.map (fun cf -> switch_case ctx pos cf.cf_name) old in - ( ncases, mk_return ((get slow_invoke) this (mk_local (fst (List.hd field_args)) pos) (mk_local dynamic_arg pos)) ) :: cases - in - - let default = if !is_override && not(static) then - (* let call_super ctx fn_args ret_t fn_name this_t pos = *) - { eexpr = TReturn(Some (call_super ctx all_args t_dynamic dyn_fun cl this_t pos) ); etype = basic.tvoid; epos = pos } - (*else if ctx.rcf_create_getsetinvoke_fields then (* we always need to run create_getset before *) - let get_field_name = gen.gmk_internal_name "hx" "getField" in - { eexpr = TReturn( Some (mk_this_call (PMap.find get_field_name cl.cl_fields) [mk_local dynamic_arg pos] ) ); etype = basic.tvoid; epos = pos }*) - else ( - (*let field = (gen.gtools.r_field false (TInst(ctx.rcf_ft.func_class,[])) this (mk_local (fst (List.hd all_args)) pos)) in*) - (* let mk_field_access ctx pos local field is_float is_static throw_errors set_option = *) - let field = mk_field_access_r ctx pos this field_args_exprs false {eexpr = TConst(TBool static); etype = basic.tbool; epos = pos} { eexpr = TConst(TBool true); etype = basic.tbool; epos = pos } None in - let field = mk_cast (TInst(ctx.rcf_ft.func_class,[])) field in - mk_return { - eexpr = TCall( - mk_field_access gen field (gen.gmk_internal_name "hx" "invokeDynamic") pos, - [mk_local dynamic_arg pos]); - etype = t_dynamic; - epos = pos - } ) - in - - { - eexpr = TSwitch(mk_local switch_var pos, cases, Some default); - etype = basic.tvoid; - epos = pos; - } - in - - let contents = - let statics = collect_fields cl (Some true) (Some true) in - let nonstatics = collect_fields cl (Some true) (Some false) in - - let old_nonstatics = ref [] in - - let nonstatics = match slow_invoke with - | None -> nonstatics - | Some _ -> - List.filter (fun (n,cf) -> - let is_old = not (PMap.mem cf.cf_name cl.cl_fields) || List.memq cf cl.cl_overrides in - (if is_old then old_nonstatics := cf :: !old_nonstatics); - not is_old - ) nonstatics - in - - if ctx.rcf_handle_statics then - { - eexpr = TIf(mk_local is_static pos, mk_switch_dyn statics true [], Some(mk_switch_dyn nonstatics false !old_nonstatics)); - etype = basic.tvoid; - epos = pos; - } else - mk_switch_dyn nonstatics false !old_nonstatics - in - - dyn_fun.cf_expr <- Some - { - eexpr = TFunction( - { - tf_args = all_args; - tf_type = t_dynamic; - tf_expr = mk_block contents; - }); - etype = TFun(fun_args all_args, t_dynamic); - epos = pos; - }; - if !is_override && not (!has_method) then () else begin - cl.cl_ordered_fields <- cl.cl_ordered_fields @ [dyn_fun]; - cl.cl_fields <- PMap.add dyn_fun.cf_name dyn_fun cl.cl_fields; - (if !is_override then cl.cl_overrides <- dyn_fun :: cl.cl_overrides) - end - - let implement_varargs_cl ctx cl = - let pos = cl.cl_pos in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - - let invokedyn = gen.gmk_internal_name "hx" "invokeDynamic" in - let idyn_t = TFun([gen.gmk_internal_name "fn" "dynargs", false, basic.tarray t_dynamic], t_dynamic) in - let this_idyn = mk_this invokedyn idyn_t in - - let map_fn arity ret vars api = - - let rec loop i acc = - if i < 0 then - acc - else - let obj = api i t_dynamic None in - loop (i - 1) (obj :: acc) - in - - let call_arg = if arity = (-1) then - api (-1) t_dynamic None - else if arity = 0 then - null (basic.tarray t_empty) pos - else - { eexpr = TArrayDecl(loop (arity - 1) []); etype = basic.tarray t_empty; epos = pos } - in - - let expr = { - eexpr = TCall( - this_idyn, - [ call_arg ] - ); - etype = t_dynamic; - epos = pos - } in - - let expr = if like_float ret && not (like_int ret) then mk_cast ret expr else expr in - - [], mk_return expr - in - - let all_cfs = List.filter (fun cf -> cf.cf_name <> "new" && cf.cf_name <> (invokedyn) && match cf.cf_kind with Method _ -> true | _ -> false) (ctx.rcf_ft.map_base_classfields cl true map_fn) in - - cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_cfs; - List.iter (fun cf -> - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields - ) all_cfs; - - List.iter (fun cf -> - cl.cl_overrides <- cf :: cl.cl_overrides - ) cl.cl_ordered_fields - - let implement_closure_cl ctx cl = - let pos = cl.cl_pos in - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - - let field_args, _ = field_type_args ctx pos in - let obj_arg = alloc_var "target" (TInst(ctx.rcf_object_iface, [])) in - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t ; epos = pos } in - let mk_this field t = { (mk_field_access gen this field pos) with etype = t } in - - let tf_args = field_args @ [obj_arg, None] in - let cfs, ctor_body = List.fold_left (fun (acc_cf,acc_expr) (v,_) -> - let cf = mk_class_field v.v_name v.v_type false pos (Var { v_read = AccNormal; v_write = AccNormal } ) [] in - let expr = { eexpr = TBinop(Ast.OpAssign, mk_this v.v_name v.v_type, mk_local v pos); etype = v.v_type; epos = pos } in - (cf :: acc_cf, expr :: acc_expr) - ) ([], []) tf_args in - - let map_fn arity ret vars api = - let this_obj = mk_this "target" (TInst(ctx.rcf_object_iface, [])) in - - let rec loop i acc = - if i < 0 then - acc - else - let obj = api i t_dynamic None in - loop (i - 1) (obj :: acc) - in - - let call_arg = if arity = (-1) then - api (-1) t_dynamic None - else if arity = 0 then - null (basic.tarray t_empty) pos - else - { eexpr = TArrayDecl(loop (arity - 1) []); etype = basic.tarray t_empty; epos = pos } - in - - let expr = { - eexpr = TCall( - mk_field_access gen this_obj (gen.gmk_internal_name "hx" "invokeField") pos, - (List.map (fun (v,_) -> mk_this v.v_name v.v_type) field_args) @ - (if ctx.rcf_handle_statics then - [ { eexpr = TConst(TBool false); etype = basic.tbool; epos = pos }; call_arg ] - else - [ call_arg ] - ) - ); - etype = t_dynamic; - epos = pos - } in - - let expr = if like_float ret && not (like_int ret) then mk_cast ret expr else expr in - - [], mk_return expr - in - - let all_cfs = List.filter (fun cf -> cf.cf_name <> "new" && match cf.cf_kind with Method _ -> true | _ -> false) (ctx.rcf_ft.map_base_classfields cl true map_fn) in - - List.iter (fun cf -> - cl.cl_overrides <- cf :: cl.cl_overrides - ) all_cfs; - let all_cfs = cfs @ all_cfs in - - cl.cl_ordered_fields <- cl.cl_ordered_fields @ all_cfs; - List.iter (fun cf -> - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields - ) all_cfs; - - let ctor_t = TFun(fun_args tf_args, basic.tvoid) in - let ctor_cf = mk_class_field "new" ctor_t true pos (Method MethNormal) [] in - ctor_cf.cf_expr <- Some { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = { eexpr = TBlock({ - eexpr = TCall({ eexpr = TConst(TSuper); etype = TInst(cl,[]); epos = pos }, [mk_int ctx (-1) pos; mk_int ctx (-1) pos]); - etype = basic.tvoid; - epos = pos - } :: ctor_body); etype = basic.tvoid; epos = pos } - }); - etype = ctor_t; - epos = pos - }; - - cl.cl_constructor <- Some ctor_cf; - - let closure_fun eclosure e field is_static = - let f = { eexpr = TConst(TString field); etype = basic.tstring; epos = eclosure.epos } in - let args = if ctx.rcf_optimize then [ f; { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else [ f ] in - let args = args @ [ mk_cast (TInst(ctx.rcf_object_iface, [])) e ] in - - { eclosure with eexpr = TNew(cl,[],args) } - in - closure_fun - - let get_closure_func ctx closure_cl = - let gen = ctx.rcf_gen in - let basic = gen.gcon.basic in - let closure_func eclosure e field is_static = - mk_cast eclosure.etype { eclosure with - eexpr = TNew(closure_cl, [], [ - e; - { eexpr = TConst(TString field); etype = basic.tstring; epos = eclosure.epos } - ] @ ( - if ctx.rcf_optimize then [ { eexpr = TConst(TInt (hash_field_i32 ctx eclosure.epos field)); etype = basic.tint; epos = eclosure.epos } ] else [] - )); - etype = TInst(closure_cl,[]) - } - in - closure_func - - (* - main expr -> field expr -> field string -> possible set expr -> should_throw_exceptions -> changed expression - - Changes a get / set - * - mutable rcf_on_getset_field : texpr->texpr->string->texpr option->bool->texpr;*) - - let configure_dynamic_field_access ctx is_synf = - let gen = ctx.rcf_gen in - let is_dynamic expr fexpr field = match field_access gen (gen.greal_type fexpr.etype) field with - | FEnumField _ - | FClassField _ -> false - | _ -> true - in - - let configure = if is_synf then DynamicFieldAccess.configure_as_synf else DynamicFieldAccess.configure in - let maybe_hash = if ctx.rcf_optimize then fun str pos -> Some (hash_field_i32 ctx pos str) else fun str pos -> None in - configure gen (DynamicFieldAccess.abstract_implementation gen is_dynamic - (fun expr fexpr field set is_unsafe -> - let hash = maybe_hash field fexpr.epos in - ctx.rcf_on_getset_field expr fexpr field hash set is_unsafe - ) - (fun ecall fexpr field call_list -> - let hash = maybe_hash field fexpr.epos in - ctx.rcf_on_call_field ecall fexpr field hash call_list - ) - ); - () - - let replace_reflection ctx cl = - let gen = ctx.rcf_gen in - let pos = cl.cl_pos in - - let this_t = TInst(cl, List.map snd cl.cl_types) in - let this = { eexpr = TConst(TThis); etype = this_t; epos = pos } in - - let last_fields = match cl.cl_super with - | None -> PMap.empty - | Some (super,_) -> super.cl_fields - in - - let new_fields = ref [] in - let process_cf static cf = - match cf.cf_kind with - | Var _ -> () - | _ when Meta.has Meta.ReplaceReflection cf.cf_meta -> - let name = if String.get cf.cf_name 0 = '_' then String.sub cf.cf_name 1 (String.length cf.cf_name - 1) else cf.cf_name in - let new_name = gen.gmk_internal_name "hx" name in - let new_cf = mk_class_field new_name cf.cf_type cf.cf_public cf.cf_pos cf.cf_kind cf.cf_params in - let fn_args, ret = get_fun (follow cf.cf_type) in - - let tf_args = List.map (fun (name,_,t) -> alloc_var name t, None) fn_args in - let is_void = is_void ret in - let expr = { - eexpr = TCall( - { - eexpr = (if static then TField(mk_classtype_access cl pos, FStatic(cl, cf)) else TField(this, FInstance(cl, cf))); - etype = cf.cf_type; - epos = cf.cf_pos; - }, - List.map (fun (v,_) -> mk_local v cf.cf_pos) tf_args); - etype = ret; - epos = cf.cf_pos - } in - - let new_f = - { - tf_args = tf_args; - tf_type = ret; - tf_expr = { - eexpr = TBlock([if is_void then expr else mk_return expr]); - etype = ret; - epos = pos; - } - } in - - new_cf.cf_expr <- Some({ eexpr = TFunction(new_f); etype = cf.cf_type; epos = cf.cf_pos}); - - new_fields := new_cf :: !new_fields; - - (if static then cl.cl_statics <- PMap.add new_name new_cf cl.cl_statics else cl.cl_fields <- PMap.add new_name new_cf cl.cl_fields); - - if not static && PMap.mem new_name last_fields then cl.cl_overrides <- new_cf :: cl.cl_overrides - | _ -> () - in - - List.iter (process_cf false) cl.cl_ordered_fields; - cl.cl_ordered_fields <- cl.cl_ordered_fields @ !new_fields; - new_fields := []; - List.iter (process_cf true) cl.cl_ordered_statics; - cl.cl_ordered_statics <- cl.cl_ordered_statics @ !new_fields - - (* ******************************************* *) - (* UniversalBaseClass *) - (* ******************************************* *) - - (* - - Sets the universal base class for hxgen types (HxObject / IHxObject) - - dependencies: - As a rule, it should be one of the last module filters to run so any @:hxgen class created in the process - -Should- only run after TypeParams.RealTypeParams.Modf, since - - *) - - module UniversalBaseClass = - struct - - let name = "rcf_universal_base_class" - - let priority = min_dep +. 10. - - let default_implementation gen baseclass baseinterface basedynamic = - (* baseinterface.cl_meta <- (Meta.BaseInterface, [], baseinterface.cl_pos) :: baseinterface.cl_meta; *) - let rec run md = - (if is_hxgen md then - match md with - | TClassDecl ( { cl_interface = true } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && cl.cl_path <> basedynamic.cl_path -> - cl.cl_implements <- (baseinterface, []) :: cl.cl_implements - | TClassDecl ( { cl_super = None } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && cl.cl_path <> basedynamic.cl_path -> - if is_some cl.cl_dynamic then - cl.cl_super <- Some (basedynamic,[]) - else - cl.cl_super <- Some (baseclass,[]) - | TClassDecl ( { cl_super = Some(super,_) } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && not ( is_hxgen (TClassDecl super) ) -> - cl.cl_implements <- (baseinterface, []) :: cl.cl_implements - | _ -> () - ); - md - in - run - - let configure gen mapping_func = - let map e = Some(mapping_func e) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map - - let default_config gen baseclass baseinterface basedynamic = - let impl = (default_implementation gen baseclass baseinterface basedynamic) in - configure gen impl - - end;; - - (* - Priority: must run AFTER UniversalBaseClass - *) - let priority = solve_deps name [DAfter UniversalBaseClass.priority] - - let configure ?slow_invoke ctx baseinterface = - let gen = ctx.rcf_gen in - let run = (fun md -> match md with - | TClassDecl cl when is_hxgen md && ( not cl.cl_interface || cl.cl_path = baseinterface.cl_path ) -> - (if Meta.has Meta.ReplaceReflection cl.cl_meta then replace_reflection ctx cl); - (implement_dynamics ctx cl); - (if not (PMap.mem (gen.gmk_internal_name "hx" "lookupField") cl.cl_fields) then implement_final_lookup ctx cl); - (if not (PMap.mem (gen.gmk_internal_name "hx" "getField") cl.cl_fields) then implement_get_set ctx cl); - (if not (PMap.mem (gen.gmk_internal_name "hx" "invokeField") cl.cl_fields) then implement_invokeField ctx ~slow_invoke:slow_invoke cl); - (if not (PMap.mem (gen.gmk_internal_name "hx" "classFields") cl.cl_fields) then implement_fields ctx cl); - (if ctx.rcf_handle_statics && not (PMap.mem (gen.gmk_internal_name "hx" "getClassStatic") cl.cl_statics) then implement_get_class ctx cl); - (if not cl.cl_interface && not (PMap.mem (gen.gmk_internal_name "hx" "create") cl.cl_fields) then implement_create_empty ctx cl); - None - | _ -> None) - in - - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) run + + module UniversalBaseClass = + struct + + let name = "rcf_universal_base_class" + + let priority = min_dep +. 10. + + let default_implementation gen baseclass baseinterface basedynamic = + (* baseinterface.cl_meta <- (Meta.BaseInterface, [], baseinterface.cl_pos) :: baseinterface.cl_meta; *) + let rec run md = + (if is_hxgen md then + match md with + | TClassDecl ( { cl_interface = true } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && cl.cl_path <> basedynamic.cl_path -> + cl.cl_implements <- (baseinterface, []) :: cl.cl_implements + | TClassDecl ({ cl_kind = KAbstractImpl _ } as cl) -> + (* + TODO: probably here is not the best place to add @:final to KAbstractImpl, also: + Doesn't it make sense to add @:final to KAbstractImpls on all platforms? + *) + if not (Meta.has Meta.Final cl.cl_meta) then cl.cl_meta <- (Meta.Final, [], cl.cl_pos) :: cl.cl_meta + | TClassDecl ( { cl_super = None } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && cl.cl_path <> basedynamic.cl_path -> + if is_some cl.cl_dynamic then + cl.cl_super <- Some (basedynamic,[]) + else + cl.cl_super <- Some (baseclass,[]) + | TClassDecl ( { cl_super = Some(super,_) } as cl ) when cl.cl_path <> baseclass.cl_path && cl.cl_path <> baseinterface.cl_path && not ( is_hxgen (TClassDecl super) ) -> + cl.cl_implements <- (baseinterface, []) :: cl.cl_implements + | _ -> () + ); + md + in + run + + let configure gen mapping_func = + let map e = Some(mapping_func e) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + + let default_config gen baseclass baseinterface basedynamic = + let impl = (default_implementation gen baseclass baseinterface basedynamic) in + configure gen impl + + end;; + + (* + Priority: must run AFTER UniversalBaseClass + *) + let priority = solve_deps name [DAfter UniversalBaseClass.priority] + + let configure ?slow_invoke ctx baseinterface = + let gen = ctx.rcf_gen in + let run = (fun md -> match md with + | TClassDecl cl when is_hxgen md && ( not cl.cl_interface || cl.cl_path = baseinterface.cl_path ) && (match cl.cl_kind with KAbstractImpl _ -> false | _ -> true) -> + (if Meta.has Meta.ReplaceReflection cl.cl_meta then replace_reflection ctx cl); + (implement_dynamics ctx cl); + (if not (PMap.mem (gen.gmk_internal_name "hx" "lookupField") cl.cl_fields) then implement_final_lookup ctx cl); + (if not (PMap.mem (gen.gmk_internal_name "hx" "getField") cl.cl_fields) then implement_get_set ctx cl); + (if not (PMap.mem (gen.gmk_internal_name "hx" "invokeField") cl.cl_fields) then implement_invokeField ctx ~slow_invoke:slow_invoke cl); + (if not (PMap.mem (gen.gmk_internal_name "hx" "classFields") cl.cl_fields) then implement_fields ctx cl); + (if ctx.rcf_handle_statics && not (PMap.mem (gen.gmk_internal_name "hx" "getClassStatic") cl.cl_statics) then implement_get_class ctx cl); + (if not cl.cl_interface && not (PMap.mem (gen.gmk_internal_name "hx" "create") cl.cl_fields) then implement_create_empty ctx cl); + None + | _ -> None) + in + + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) run end;; @@ -8255,10 +9078,10 @@ end;; (* - A simple Object Declaration Mapper. By default it will be a syntax filter, which only runs - after + A simple Object Declaration Mapper. By default it will be a syntax filter, which only runs + after - dependencies: + dependencies: *) @@ -8266,23 +9089,23 @@ end;; module ObjectDeclMap = struct - let name = "object_decl_map" + let name = "object_decl_map" - let priority = solve_deps name [] + let priority = solve_deps name [] - let traverse gen map_fn = - let rec run e = - 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) - | _ -> Type.map_expr run e - in - run + let traverse gen map_fn = + let rec run e = + 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) + | _ -> Type.map_expr run e + in + run - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -8293,346 +9116,311 @@ end;; (* - For languages that don't support parameterized enums and/or metadata in enums, we need to transform - enums into normal classes. This is done at the first module pass by creating new classes with the same - path inside the modules, and removing the actual enum module by setting it as en extern. + For languages that don't support parameterized enums and/or metadata in enums, we need to transform + enums into normal classes. This is done at the first module pass by creating new classes with the same + path inside the modules, and removing the actual enum module by setting it as en extern. - Later, on the last expression pass, it will transform the TMatch codes into TSwitch. it will introduce a new - dependency, though: - * The target must create its own strategy to deal with reflection. As it is right now, we will have a base class - which the class will extend, create @:$IsEnum metadata for the class, and create @:alias() metadatas for the fields, - with their tag order (as a string) as their alias. If you are using ReflectionCFs, then you don't have to worry - about that, as it's already generating all information needed by the haxe runtime. - so they can be + Later, on the last expression pass, it will transform the TMatch codes into TSwitch. it will introduce a new + dependency, though: + * The target must create its own strategy to deal with reflection. As it is right now, we will have a base class + which the class will extend, create @:$IsEnum metadata for the class, and create @:alias() metadatas for the fields, + with their tag order (as a string) as their alias. If you are using ReflectionCFs, then you don't have to worry + about that, as it's already generating all information needed by the haxe runtime. + so they can be - dependencies: - The MatchToSwitch part must run after ExprStatementUnwrap as modified expressions might confuse it (not so true anymore) + dependencies: + The MatchToSwitch part must run after ExprStatementUnwrap as modified expressions might confuse it (not so true anymore) *) module EnumToClass = struct - let name = "enum_to_class" - - let priority = solve_deps name [] - - type t = { - ec_tbl : (path, tclass) Hashtbl.t; - } - - let new_t () = - { - ec_tbl = Hashtbl.create 10 - } - - (* ******************************************* *) - (* EnumToClassModf *) - (* ******************************************* *) - - (* - - The actual Module Filter that will transform the enum into a class - - dependencies: - Should run before ReflectionCFs, in order to enable proper reflection access. - Should run before TypeParams.RealTypeParams.RealTypeParamsModf, since generic enums must be first converted to generic classes - *) - - module EnumToClassModf = - struct - - let name = "enum_to_class_mod" - - let priority = solve_deps name [DBefore ReflectionCFs.priority; DBefore TypeParams.RealTypeParams.RealTypeParamsModf.priority] - - let pmap_exists fn pmap = try PMap.iter (fun a b -> if fn a b then raise Exit) pmap; false with | Exit -> true - - let has_any_meta en = - let has_meta meta = List.exists (fun (m,_,_) -> match m with Meta.Custom _ -> true | _ -> false) meta in - has_meta en.e_meta || pmap_exists (fun _ ef -> has_meta ef.ef_meta) en.e_constrs - - let has_parameters e = - try - (PMap.iter (fun _ ef -> match follow ef.ef_type with | TFun _ -> raise Exit | _ -> ()) e.e_constrs); - false - with | Exit -> true - - let convert gen t base_class en should_be_hxgen handle_type_params = - let basic = gen.gcon.basic in - let pos = en.e_pos in - - (* create the class *) - let cl = mk_class en.e_module en.e_path pos in - Hashtbl.add t.ec_tbl en.e_path cl; - - (match Codegen.build_metadata gen.gcon (TEnumDecl en) with - | Some expr -> - let cf = mk_class_field "__meta__" expr.etype false expr.epos (Var { v_read = AccNormal; v_write = AccNormal }) [] in - cf.cf_expr <- Some expr; - cl.cl_statics <- PMap.add "__meta__" cf cl.cl_statics; - cl.cl_ordered_statics <- cf :: cl.cl_ordered_statics - | _ -> () - ); - - cl.cl_super <- Some(base_class,[]); - cl.cl_extern <- en.e_extern; - en.e_extern <- true; - en.e_meta <- (Meta.Class, [], pos) :: en.e_meta; - cl.cl_module <- en.e_module; - cl.cl_meta <- ( Meta.Enum, [], pos ) :: cl.cl_meta; - let c_types = - if handle_type_params then - List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_types - else - [] - in - - cl.cl_types <- c_types; - - let i = ref 0 in - let cfs = List.map (fun name -> - let ef = PMap.find name en.e_constrs in - let pos = ef.ef_pos in - let old_i = !i in - incr i; - - let cf = match follow ef.ef_type with - | TFun(params,ret) -> - let dup_types = - if handle_type_params then - List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_types - else - [] - in - - let ef_type = - let fn, types = if handle_type_params then snd, dup_types else (fun _ -> t_dynamic), en.e_types in - let t = apply_params en.e_types (List.map fn types) ef.ef_type in - apply_params ef.ef_params (List.map fn ef.ef_params) t - in - - let params, ret = get_fun ef_type in - let cf_params = if handle_type_params then dup_types @ ef.ef_params else [] in - - let cf = mk_class_field name ef_type true pos (Method MethNormal) cf_params in - cf.cf_meta <- []; - - let tf_args = List.map (fun (name,opt,t) -> (alloc_var name t, if opt then Some TNull else None) ) params in - let arr_decl = { eexpr = TArrayDecl(List.map (fun (v,_) -> mk_local v pos) tf_args); etype = basic.tarray t_empty; epos = pos } in - let expr = { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = ret; - tf_expr = mk_block ( mk_return { eexpr = TNew(cl,List.map snd dup_types, [mk_int gen old_i pos; arr_decl] ); etype = TInst(cl, List.map snd dup_types); epos = pos } ); - }); - etype = ef_type; - epos = pos - } in - cf.cf_expr <- Some expr; - cf - | _ -> - let actual_t = match follow ef.ef_type with - | TEnum(e, p) -> TEnum(e, List.map (fun _ -> t_dynamic) p) - | _ -> assert false - in - let cf = mk_class_field name actual_t true pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in - cf.cf_meta <- []; - cf.cf_expr <- Some { - eexpr = TNew(cl, List.map (fun _ -> t_empty) cl.cl_types, [mk_int gen old_i pos; { eexpr = TArrayDecl []; etype = basic.tarray t_empty; epos = pos }]); - etype = TInst(cl, List.map (fun _ -> t_empty) cl.cl_types); - epos = pos; - }; - cf - in - cl.cl_statics <- PMap.add cf.cf_name cf cl.cl_statics; - cf - ) en.e_names in - let constructs_cf = mk_class_field "constructs" (basic.tarray basic.tstring) true pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in - constructs_cf.cf_meta <- []; - constructs_cf.cf_expr <- Some { - eexpr = TArrayDecl (List.map (fun s -> { eexpr = TConst(TString s); etype = basic.tstring; epos = pos }) en.e_names); - etype = basic.tarray basic.tstring; - epos = pos; - }; - - cl.cl_ordered_statics <- constructs_cf :: cfs @ cl.cl_ordered_statics ; - cl.cl_statics <- PMap.add "constructs" constructs_cf cl.cl_statics; - - (if should_be_hxgen then - cl.cl_meta <- (Meta.HxGen,[],cl.cl_pos) :: cl.cl_meta - else begin - (* create the constructor *) - let tf_args = [ alloc_var "index" basic.tint, None; alloc_var "params" (basic.tarray t_empty), None ] in - let ftype = TFun(fun_args tf_args, basic.tvoid) in - let ctor = mk_class_field "new" ftype true pos (Method MethNormal) [] in - let me = TInst(cl, List.map snd cl.cl_types) in - ctor.cf_expr <- - Some { - eexpr = TFunction( - { - tf_args = tf_args; - tf_type = basic.tvoid; - tf_expr = mk_block { - eexpr = TCall({ eexpr = TConst TSuper; etype = me; epos = pos }, List.map (fun (v,_) -> mk_local v pos) tf_args); - etype = basic.tvoid; - epos = pos; - } - }); - etype = ftype; - epos = pos - }; - - cl.cl_constructor <- Some ctor - end); - gen.gadd_to_module (TClassDecl cl) (max_dep); - - TEnumDecl en - - (* - traverse - gen - gen context - convert_all : bool - should we convert all enums? If set, convert_if_has_meta will be ignored. - convert_if_has_meta : bool - should we convert only if it has meta? - enum_base_class : tclass - the enum base class. - should_be_hxgen : bool - should the created enum be hxgen? - *) - let traverse gen t convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams = - let convert e = convert gen t enum_base_class e should_be_hxgen handle_tparams in - let run md = match md with - | TEnumDecl e when is_hxgen md -> - if convert_all then - convert e - else if convert_if_has_meta && has_any_meta e then - convert e - else if has_parameters e then - convert e - else begin - (* take off the :hxgen meta from it, if there's any *) - e.e_meta <- List.filter (fun (n,_,_) -> not (n = Meta.HxGen)) e.e_meta; - md - end - | _ -> md - in - run - - let configure gen (mapping_func:module_type->module_type) = - let map md = Some(mapping_func md) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map - - end;; - - (* ******************************************* *) - (* EnumToClassExprf *) - (* ******************************************* *) - - (* - - Enum to class Expression Filter - - will convert TMatch into TSwitch - - dependencies: - Should run before TArrayTransform, since it generates array access expressions - - *) - - module EnumToClassExprf = - struct - - let name = "enum_to_class_exprf" - - let priority = solve_deps name [DBefore TArrayTransform.priority] - - let ensure_local gen cond = - let exprs_before, new_cond = match cond.eexpr with - | TLocal v -> - [], cond - | _ -> - let v = mk_temp gen "cond" cond.etype in - [ { eexpr = TVars([v, Some cond]); etype = gen.gcon.basic.tvoid; epos = cond.epos } ], mk_local v cond.epos - in - exprs_before, new_cond - - let get_index gen cond cls tparams = - { (mk_field_access gen { cond with etype = TInst(cls, tparams) } "index" cond.epos) with etype = gen.gcon.basic.tint } - - (* stolen from Hugh's hxcpp sources *) - let tmatch_params_to_vars params = - (match params with - | None | Some [] -> [] - | Some l -> - let n = ref (-1) in - List.fold_left - (fun acc v -> incr n; match v with None -> acc | Some v -> (v,!n) :: acc) [] l) - - let tmatch_params_to_exprs gen params cond_local = - let vars = tmatch_params_to_vars params in - let cond_array = { (mk_field_access gen cond_local "params" cond_local.epos) with etype = gen.gcon.basic.tarray t_empty } in - let tvars = List.map (fun (v, n) -> - (v, Some({ eexpr = TArray(cond_array, mk_int gen n cond_array.epos); etype = t_dynamic; epos = cond_array.epos })) - ) vars in - match vars with - | [] -> - [] - | _ -> - [ { eexpr = TVars(tvars); etype = gen.gcon.basic.tvoid; epos = cond_local.epos } ] - - let traverse gen t opt_get_native_enum_tag = - let rec run e = - match e.eexpr with - | TMatch(cond,(en,eparams),cases,default) -> - let cond = run cond in (* being safe *) - (* check if en was converted to class *) - (* if it was, switch on tag field and change cond type *) - let exprs_before, cond_local, cond = try - let cl = Hashtbl.find t.ec_tbl en.e_path in - let cond = { cond with etype = TInst(cl, eparams) } in - let exprs_before, new_cond = ensure_local gen cond in - exprs_before, new_cond, get_index gen new_cond cl eparams - with | Not_found -> - (* - if it's not a class, we'll either use get_native_enum_tag or in a last resource, - call Type.getEnumIndex - *) - match opt_get_native_enum_tag with - | Some get_native_etag -> - [], cond, get_native_etag cond - | None -> - [], cond, { eexpr = TCall(mk_static_field_access_infer gen.gclasses.cl_type "enumIndex" e.epos [], [cond]); etype = gen.gcon.basic.tint; epos = cond.epos } - in - - (* for each case, change cases to expr int, and see if there is any var create *) - let change_case (il, params, expr) = - let expr = run expr in - (* if there are, set var with tarray *) - let exprs = tmatch_params_to_exprs gen params cond_local in - let expr = match expr.eexpr with - | TBlock(bl) -> { expr with eexpr = TBlock(exprs @ bl) } - | _ -> { expr with eexpr = TBlock ( exprs @ [expr] ) } - in - (List.map (fun i -> mk_int gen i e.epos) il, expr) - in - - let tswitch = { e with eexpr = TSwitch(cond, List.map change_case cases, Option.map run default) } in - (match exprs_before with - | [] -> tswitch - | _ -> { e with eexpr = TBlock(exprs_before @ [tswitch]) }) - | _ -> Type.map_expr run e - in - - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map - - end;; - - let configure gen opt_get_native_enum_tag convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams = - let t = new_t () in - EnumToClassModf.configure gen (EnumToClassModf.traverse gen t convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams); - EnumToClassExprf.configure gen (EnumToClassExprf.traverse gen t opt_get_native_enum_tag) + let name = "enum_to_class" + + let priority = solve_deps name [] + + type t = { + ec_tbl : (path, tclass) Hashtbl.t; + } + + let new_t () = + { + ec_tbl = Hashtbl.create 10 + } + + (* ******************************************* *) + (* EnumToClassModf *) + (* ******************************************* *) + + (* + + The actual Module Filter that will transform the enum into a class + + dependencies: + Should run before ReflectionCFs, in order to enable proper reflection access. + Should run before TypeParams.RealTypeParams.RealTypeParamsModf, since generic enums must be first converted to generic classes + It needs that the target platform implements __array__() as a shortcut to declare haxe.ds.Vector + *) + + module EnumToClassModf = + struct + + let name = "enum_to_class_mod" + + let priority = solve_deps name [DBefore ReflectionCFs.priority; DBefore TypeParams.RealTypeParams.RealTypeParamsModf.priority] + + let pmap_exists fn pmap = try PMap.iter (fun a b -> if fn a b then raise Exit) pmap; false with | Exit -> true + + let has_any_meta en = + let has_meta meta = List.exists (fun (m,_,_) -> match m with Meta.Custom _ -> true | _ -> false) meta in + has_meta en.e_meta || pmap_exists (fun _ ef -> has_meta ef.ef_meta) en.e_constrs + + let convert gen t base_class base_param_class en should_be_hxgen handle_type_params = + let basic = gen.gcon.basic in + let pos = en.e_pos in + + (* create the class *) + let cl = mk_class en.e_module en.e_path pos in + Hashtbl.add t.ec_tbl en.e_path cl; + + (match Codegen.build_metadata gen.gcon (TEnumDecl en) with + | Some expr -> + let cf = mk_class_field "__meta__" expr.etype false expr.epos (Var { v_read = AccNormal; v_write = AccNormal }) [] in + cf.cf_expr <- Some expr; + cl.cl_statics <- PMap.add "__meta__" cf cl.cl_statics; + cl.cl_ordered_statics <- cf :: cl.cl_ordered_statics + | _ -> () + ); + + let super, has_params = if Meta.has Meta.FlatEnum en.e_meta then base_class, false else base_param_class, true in + + cl.cl_super <- Some(super,[]); + cl.cl_extern <- en.e_extern; + en.e_meta <- (Meta.Class, [], pos) :: en.e_meta; + cl.cl_module <- en.e_module; + cl.cl_meta <- ( Meta.Enum, [], pos ) :: cl.cl_meta; + + (match gen.gcon.platform with + | Cs when Common.defined gen.gcon Define.CoreApiSerialize -> + cl.cl_meta <- ( Meta.Meta, [ (EField( (EConst (Ident "System"), null_pos ), "Serializable" ), null_pos) ], null_pos ) :: cl.cl_meta + | _ -> ()); + let c_types = + if handle_type_params then + List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_params + else + [] + in + + cl.cl_params <- c_types; + + let i = ref 0 in + let cfs = List.map (fun name -> + let ef = PMap.find name en.e_constrs in + let pos = ef.ef_pos in + let old_i = !i in + incr i; + + let cf = match follow ef.ef_type with + | TFun(params,ret) -> + let dup_types = + if handle_type_params then + List.map (fun (s,t) -> (s, TInst (map_param (get_cl_t t), []))) en.e_params + else + [] + in + + let ef_type = + let fn, types = if handle_type_params then snd, dup_types else (fun _ -> t_dynamic), en.e_params in + let t = apply_params en.e_params (List.map fn types) ef.ef_type in + apply_params ef.ef_params (List.map fn ef.ef_params) t + in + + let params, ret = get_fun ef_type in + let cf_params = if handle_type_params then dup_types @ ef.ef_params else [] in + + let cf = mk_class_field name ef_type true pos (Method MethNormal) cf_params in + cf.cf_meta <- []; + + let tf_args = List.map (fun (name,opt,t) -> (alloc_var name t, if opt then Some TNull else None) ) params in + let arr_decl = mk_nativearray_decl gen t_dynamic (List.map (fun (v,_) -> mk_local v pos) tf_args) pos in + let expr = { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = ret; + tf_expr = mk_block ( mk_return { eexpr = TNew(cl,List.map snd dup_types, [mk_int gen old_i pos; arr_decl] ); etype = TInst(cl, List.map snd dup_types); epos = pos } ); + }); + etype = ef_type; + epos = pos + } in + cf.cf_expr <- Some expr; + cf + | _ -> + let actual_t = match follow ef.ef_type with + | TEnum(e, p) -> TEnum(e, List.map (fun _ -> t_dynamic) p) + | _ -> assert false + 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 + [mk_int gen old_i pos; null (gen.gclasses.nativearray t_dynamic) pos] + else + [mk_int gen old_i pos] + in + cf.cf_meta <- [Meta.ReadOnly,[],pos]; + cf.cf_expr <- Some { + eexpr = TNew(cl, List.map (fun _ -> t_empty) cl.cl_params, args); + etype = TInst(cl, List.map (fun _ -> t_empty) cl.cl_params); + epos = pos; + }; + cf + in + cl.cl_statics <- PMap.add cf.cf_name cf cl.cl_statics; + cf + ) en.e_names in + let constructs_cf = mk_class_field "__hx_constructs" (gen.gclasses.nativearray basic.tstring) true pos (Var { v_read = AccNormal; v_write = AccNever }) [] in + constructs_cf.cf_meta <- [Meta.ReadOnly,[],pos]; + constructs_cf.cf_expr <- Some (mk_nativearray_decl gen basic.tstring (List.map (fun s -> { eexpr = TConst(TString s); etype = basic.tstring; epos = pos }) en.e_names) pos); + + cl.cl_ordered_statics <- constructs_cf :: cfs @ cl.cl_ordered_statics ; + cl.cl_statics <- PMap.add "__hx_constructs" constructs_cf cl.cl_statics; + + let getTag_cf_type = tfun [] basic.tstring in + let getTag_cf = mk_class_field "getTag" getTag_cf_type true pos (Method MethNormal) [] in + getTag_cf.cf_meta <- [(Meta.Final, [], pos)]; + getTag_cf.cf_expr <- Some { + eexpr = TFunction { + tf_args = []; + tf_type = basic.tstring; + tf_expr = { + eexpr = TReturn (Some ( + let e_constructs = mk_static_field_access_infer cl "__hx_constructs" pos [] in + let e_this = mk (TConst TThis) (TInst (cl,[])) pos in + let e_index = mk_field_access gen e_this "index" pos in + { + eexpr = TArray(e_constructs,e_index); + etype = basic.tstring; + epos = pos; + } + )); + epos = pos; + etype = basic.tvoid; + } + }; + etype = getTag_cf_type; + epos = pos; + }; + + cl.cl_ordered_fields <- getTag_cf :: cl.cl_ordered_fields ; + cl.cl_fields <- PMap.add "getTag" getTag_cf cl.cl_fields; + cl.cl_overrides <- getTag_cf :: cl.cl_overrides; + + if should_be_hxgen then + cl.cl_meta <- (Meta.HxGen,[],cl.cl_pos) :: cl.cl_meta + else + cl.cl_meta <- (Meta.NativeGen,[],cl.cl_pos) :: cl.cl_meta; + gen.gadd_to_module (TClassDecl cl) (max_dep); + + TEnumDecl en + + (* + traverse + gen - gen context + convert_all : bool - should we convert all enums? If set, convert_if_has_meta will be ignored. + convert_if_has_meta : bool - should we convert only if it has meta? + enum_base_class : tclass - the enum base class. + should_be_hxgen : bool - should the created enum be hxgen? + *) + let traverse gen t convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams = + let convert e = convert gen t enum_base_class param_enum_class e should_be_hxgen handle_tparams in + let run md = match md with + | TEnumDecl e when is_hxgen md -> + if convert_all then + convert e + else if convert_if_has_meta && has_any_meta e then + convert e + else if not (Meta.has Meta.FlatEnum e.e_meta) then + convert e + else begin + (* take off the :hxgen meta from it, if there's any *) + e.e_meta <- List.filter (fun (n,_,_) -> not (n = Meta.HxGen)) e.e_meta; + md + end + | _ -> md + in + run + + let configure gen (mapping_func:module_type->module_type) = + let map md = Some(mapping_func md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + + end;; + + (* ******************************************* *) + (* EnumToClassExprf *) + (* ******************************************* *) + + (* + + Enum to class Expression Filter + + will convert TMatch into TSwitch + + dependencies: + Should run before TArrayTransform, since it generates array access expressions + + *) + + module EnumToClassExprf = + struct + + let name = "enum_to_class_exprf" + + let priority = solve_deps name [DBefore TArrayTransform.priority] + + let traverse gen t opt_get_native_enum_tag = + let rec run e = + let get_converted_enum_type et = + let en, eparams = match follow (gen.gfollow#run_f et) with + | TEnum(en,p) -> en, p + | _ -> raise Not_found + in + let cl = Hashtbl.find t.ec_tbl en.e_path in + TInst(cl, eparams) + in + + match e.eexpr with + | TCall (({eexpr = TField(_, FStatic({cl_path=[],"Type"},{cf_name="enumIndex"}))} as left), [f]) -> + let f = run f in + (try + mk_field_access gen {f with etype = get_converted_enum_type f.etype} "index" e.epos + with Not_found -> + { e with eexpr = TCall(left, [f]) }) + | TEnumParameter(f, _,i) -> + let f = run f in + (* check if en was converted to class *) + (* if it was, switch on tag field and change cond type *) + let f = try + { f with etype = get_converted_enum_type f.etype } + with Not_found -> + f + in + let cond_array = { (mk_field_access gen f "params" f.epos) with etype = gen.gclasses.nativearray t_dynamic } in + { e with eexpr = TArray(cond_array, mk_int gen i cond_array.epos); } + | _ -> Type.map_expr run e + in + + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map + + end;; + + let configure gen opt_get_native_enum_tag convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams = + let t = new_t () in + EnumToClassModf.configure gen (EnumToClassModf.traverse gen t convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams); + EnumToClassExprf.configure gen (EnumToClassExprf.traverse gen t opt_get_native_enum_tag) end;; @@ -8642,215 +9430,215 @@ end;; (* - This module will handle with Iterators, Iterables and TFor() expressions. - At first, a module filter will receive a Iterator and Iterable interface, which will be implemented - if hasNext(), next() or iterator() fields are detected with the correct type. - At this part a custom function will be called which can adequate the class fields so they are compatible with - native Iterators as well + This module will handle with Iterators, Iterables and TFor() expressions. + At first, a module filter will receive a Iterator and Iterable interface, which will be implemented + if hasNext(), next() or iterator() fields are detected with the correct type. + At this part a custom function will be called which can adequate the class fields so they are compatible with + native Iterators as well - The expression filter part of this module will look for TFor() expressions, and transform like that: - for (anInt in value.iterator()) - { + The expression filter part of this module will look for TFor() expressions, and transform like that: + for (anInt in value.iterator()) + { - } + } - { - var s:haxe.lang.Iterator = ExternalFunction.getIterator(value.iterator()); - while (s.hasNext()) - { - var anInt:Int = s.next(); + { + var s:haxe.lang.Iterator = ExternalFunction.getIterator(value.iterator()); + while (s.hasNext()) + { + var anInt:Int = s.next(); - } - } + } + } - dependencies: - None. + dependencies: + None. *) module IteratorsInterface = struct - let name = "iterators_interface" - (* TODO later - (* ******************************************* *) - (* IteratorsInterfaceModf *) - (* ******************************************* *) - - (* - - The module filter for Iterators Interface, which will implement the iterator/iterable interface on each - class that conforms with the typedefs Iterator<> and Iterable<> - - It's a very simple module and it will rely on cast detection to work correctly. This is so that - when the - - dependencies: - Must run at the Module Filters, so cast detection can detect a cast to the interface and we can - - *) - - module IteratorsInterfaceModf = - struct - - let name = "iterators_interface_modf" - - let conforms_cfs has_next next = - try (match follow has_next.cf_type with - | TFun([],ret) when - (match follow ret with | TEnum({ e_path = ([], "Bool") }, []) -> () | _ -> raise Not_found) -> - () - | _ -> raise Not_found); - (match follow next.cf_type with - | TFun([], ret) -> ret - | _ -> raise Not_found - ) - - let conforms_type_iterator t = - try match follow t with - | TInst(cl,params) -> - let has_next = PMap.find "hasNext" cl.cl_fields in - let next = PMap.find "next" cl.cl_fields in - Some (conforms_cfs has_next next) - | TAnon(anon) -> - let has_next = PMap.find "hasNext" anon.a_fields in - let next = PMap.find "next" anon.a_fields in - Some (conforms_cfs has_next next) - | _ -> None - with | Not_found -> None - - let conforms_as_iterable cl = - try - let iterator = PMap.find "iterator" cl.cl_fields in - match follow iterator.cf_type with - | TFun([], ret) -> conforms_type_iterator ret - | _ -> None - with | Not_found -> None - - let conforms_as_iterator cl = - try - let has_next = PMap.find "hasNext" cl.cl_fields in - let next = PMap.find "next" cl.cl_fields in - Some (conforms_cfs has_next next) - with | Not_found -> None - - let priority = solve_deps name [] - - let traverse gen iterator_iface iterable_iface on_found_iterator on_found_iterable = - let rec run md = - match md with - | TClassDecl cl when not cl.cl_extern && is_hxgen cl -> - let conforms_iterator = conforms_as_iterator cl in - let conforms_iterable = conforms_as_iterable cl in - if is_some conforms_iterator then begin - let it_t = get conforms_iterator in - cl.cl_interfaces <- (iterator_iface, [it_t]); - on_found_iterator cl - end; - if is_some conforms_iterable then begin - let it_t = get conforms_iterable in - cl.cl_interfaces <- (iterable_iface, [it_t]); - on_found_iterable cl - end; - - md - | _ -> md - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map - - end;; - *) - - (* ******************************************* *) - (* IteratorsInterfaceExprf *) - (* ******************************************* *) - - (* - - The expression filter for Iterators. Will look for TFor, transform it into - { - var iterator = // in expression here - while (iterator.hasNext()) - { - var varName = iterator.next(); - } - } - - dependencies: - Must run before Dynamic fields access is run - - *) - - module IteratorsInterfaceExprf = - struct - - let name = "iterators_interface_exprf" - - let priority = solve_deps name [DBefore DynamicFieldAccess.priority] - - let priority_as_synf = solve_deps name [DBefore DynamicFieldAccess.priority_as_synf] - - let mk_access gen v name pos = - let field_t = - try match follow v.v_type with - | TInst(cl, params) -> - let field = PMap.find name cl.cl_fields in - apply_params cl.cl_types params field.cf_type - | TAnon(anon) -> - let field = PMap.find name anon.a_fields in - field.cf_type - | _ -> t_dynamic - with | Not_found -> t_dynamic - in - { (mk_field_access gen (mk_local v pos) name pos) with etype = field_t } - - let traverse gen change_in_expr = - let basic = gen.gcon.basic in - let rec run e = - match e.eexpr with - | TFor(var, in_expr, block) -> - let in_expr = change_in_expr (run in_expr) in - let temp = mk_temp gen "iterator" in_expr.etype in - let block = - [ - { eexpr = TVars([temp, Some(in_expr)]); etype = basic.tvoid; epos = in_expr.epos }; - { - eexpr = TWhile( - { eexpr = TCall(mk_access gen temp "hasNext" in_expr.epos, []); etype = basic.tbool; epos = in_expr.epos }, - Codegen.concat ({ - eexpr = TVars([var, Some({ eexpr = TCall(mk_access gen temp "next" in_expr.epos, []); etype = var.v_type; epos = in_expr.epos })]); - etype = basic.tvoid; - epos = in_expr.epos - }) ( run block ), - Ast.NormalWhile); - etype = basic.tvoid; - epos = e.epos - } - ] in - { eexpr = TBlock(block); etype = e.etype; epos = e.epos } - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map - - let configure_as_synf gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority_as_synf) map - - end;; - - let configure gen change_in_expr = - IteratorsInterfaceExprf.configure gen (IteratorsInterfaceExprf.traverse gen change_in_expr) - - let configure_as_synf gen change_in_expr = - IteratorsInterfaceExprf.configure_as_synf gen (IteratorsInterfaceExprf.traverse gen change_in_expr) + let name = "iterators_interface" + (* TODO later + (* ******************************************* *) + (* IteratorsInterfaceModf *) + (* ******************************************* *) + + (* + + The module filter for Iterators Interface, which will implement the iterator/iterable interface on each + class that conforms with the typedefs Iterator<> and Iterable<> + + It's a very simple module and it will rely on cast detection to work correctly. This is so that + when the + + dependencies: + Must run at the Module Filters, so cast detection can detect a cast to the interface and we can + + *) + + module IteratorsInterfaceModf = + struct + + let name = "iterators_interface_modf" + + let conforms_cfs has_next next = + try (match follow has_next.cf_type with + | TFun([],ret) when + (match follow ret with | TAbstract({ a_path = ([], "Bool") }, []) -> () | _ -> raise Not_found) -> + () + | _ -> raise Not_found); + (match follow next.cf_type with + | TFun([], ret) -> ret + | _ -> raise Not_found + ) + + let conforms_type_iterator t = + try match follow t with + | TInst(cl,params) -> + let has_next = PMap.find "hasNext" cl.cl_fields in + let next = PMap.find "next" cl.cl_fields in + Some (conforms_cfs has_next next) + | TAnon(anon) -> + let has_next = PMap.find "hasNext" anon.a_fields in + let next = PMap.find "next" anon.a_fields in + Some (conforms_cfs has_next next) + | _ -> None + with | Not_found -> None + + let conforms_as_iterable cl = + try + let iterator = PMap.find "iterator" cl.cl_fields in + match follow iterator.cf_type with + | TFun([], ret) -> conforms_type_iterator ret + | _ -> None + with | Not_found -> None + + let conforms_as_iterator cl = + try + let has_next = PMap.find "hasNext" cl.cl_fields in + let next = PMap.find "next" cl.cl_fields in + Some (conforms_cfs has_next next) + with | Not_found -> None + + let priority = solve_deps name [] + + let traverse gen iterator_iface iterable_iface on_found_iterator on_found_iterable = + let rec run md = + match md with + | TClassDecl cl when not cl.cl_extern && is_hxgen cl -> + let conforms_iterator = conforms_as_iterator cl in + let conforms_iterable = conforms_as_iterable cl in + if is_some conforms_iterator then begin + let it_t = get conforms_iterator in + cl.cl_interfaces <- (iterator_iface, [it_t]); + on_found_iterator cl + end; + if is_some conforms_iterable then begin + let it_t = get conforms_iterable in + cl.cl_interfaces <- (iterable_iface, [it_t]); + on_found_iterable cl + end; + + md + | _ -> md + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map + + end;; + *) + + (* ******************************************* *) + (* IteratorsInterfaceExprf *) + (* ******************************************* *) + + (* + + The expression filter for Iterators. Will look for TFor, transform it into + { + var iterator = // in expression here + while (iterator.hasNext()) + { + var varName = iterator.next(); + } + } + + dependencies: + Must run before Dynamic fields access is run + + *) + + module IteratorsInterfaceExprf = + struct + + let name = "iterators_interface_exprf" + + let priority = solve_deps name [DBefore DynamicFieldAccess.priority] + + let priority_as_synf = solve_deps name [DBefore DynamicFieldAccess.priority_as_synf] + + let mk_access gen v name pos = + let field_t = + try match follow v.v_type with + | TInst(cl, params) -> + let field = PMap.find name cl.cl_fields in + apply_params cl.cl_params params field.cf_type + | TAnon(anon) -> + let field = PMap.find name anon.a_fields in + field.cf_type + | _ -> t_dynamic + with | Not_found -> t_dynamic + in + { (mk_field_access gen (mk_local v pos) name pos) with etype = field_t } + + let traverse gen change_in_expr = + let basic = gen.gcon.basic in + let rec run e = + match e.eexpr with + | TFor(var, in_expr, block) -> + let in_expr = change_in_expr (run in_expr) in + let temp = mk_temp gen "iterator" in_expr.etype in + let block = + [ + { eexpr = TVar(temp, Some(in_expr)); etype = basic.tvoid; epos = in_expr.epos }; + { + eexpr = TWhile( + { eexpr = TCall(mk_access gen temp "hasNext" in_expr.epos, []); etype = basic.tbool; epos = in_expr.epos }, + Type.concat ({ + eexpr = TVar(var, Some({ eexpr = TCall(mk_access gen temp "next" in_expr.epos, []); etype = var.v_type; epos = in_expr.epos })); + etype = basic.tvoid; + epos = in_expr.epos + }) ( run block ), + Ast.NormalWhile); + etype = basic.tvoid; + epos = e.epos + } + ] in + { eexpr = TBlock(block); etype = e.etype; epos = e.epos } + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map + + let configure_as_synf gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority_as_synf) map + + end;; + + let configure gen change_in_expr = + IteratorsInterfaceExprf.configure gen (IteratorsInterfaceExprf.traverse gen change_in_expr) + + let configure_as_synf gen change_in_expr = + IteratorsInterfaceExprf.configure_as_synf gen (IteratorsInterfaceExprf.traverse gen change_in_expr) end;; @@ -8860,9 +9648,9 @@ end;; (* - Just a syntax filter which changes switch expressions to if() else if() else if() ... - It can be also an expression filter - dependencies: + Just a syntax filter which changes switch expressions to if() else if() else if() ... + It can be also an expression filter + dependencies: *) @@ -8870,81 +9658,111 @@ end;; module SwitchToIf = struct - let name = "switch_to_if" - - let priority = solve_deps name [] - - let traverse gen (should_convert:texpr->bool) (handle_nullables:bool) = - let basic = gen.gcon.basic in - let rec run e = - match e.eexpr with - | TSwitch(cond,cases,default) when should_convert e -> - let cond_etype, should_cache = match handle_nullables, gen.gfollow#run_f cond.etype with - | true, TType({ t_path = ([], "Null") }, [t]) -> - let rec take_off_nullable t = match gen.gfollow#run_f t with - | TType({ t_path = ([], "Null") }, [t]) -> take_off_nullable t - | _ -> t - in - - take_off_nullable t, true - | _, _ -> cond.etype, false - in - - if should_cache && not (should_convert { e with eexpr = TSwitch({ cond with etype = cond_etype }, cases, default) }) then begin - { e with eexpr = TSwitch(mk_cast cond_etype (run cond), List.map (fun (cs,e) -> (List.map run cs, run e)) cases, Option.map run default) } - end else begin - let local, fst_block = match cond.eexpr, should_cache with - | TLocal _, false -> cond, [] - | _ -> - let var = mk_temp gen "switch" cond_etype in - let cond = run cond in - let cond = if should_cache then mk_cast cond_etype cond else cond in - - mk_local var cond.epos, [ { eexpr = TVars([var,Some(cond)]); etype = basic.tvoid; epos = cond.epos } ] - in - - let mk_eq cond = - { eexpr = TBinop(Ast.OpEq, local, cond); etype = basic.tbool; epos = cond.epos } - in - - let rec mk_many_cond conds = - match conds with - | cond :: [] -> - mk_eq cond - | cond :: tl -> - { eexpr = TBinop(Ast.OpBoolOr, mk_eq (run cond), mk_many_cond tl); etype = basic.tbool; epos = cond.epos } - | [] -> assert false - in - - let mk_many_cond conds = - let ret = mk_many_cond conds in - (* - this might be considered a hack. But since we're on a syntax filter and - the condition is guaranteed to not have run twice, we can really run the - expr filters again for it (so to change e.g. OpEq accordingly - *) - gen.gexpr_filters#run_f ret - in - - let rec loop cases = match cases with - | (conds,e) :: [] -> - { eexpr = TIf(mk_many_cond conds, run e, Option.map run default); etype = e.etype; epos = e.epos } - | (conds,e) :: tl -> - { eexpr = TIf(mk_many_cond conds, run e, Some(loop tl)); etype = e.etype; epos = e.epos } - | [] -> match default with - | None -> gen.gcon.error "Empty switch" e.epos; assert false - | Some d -> run d - in - - { e with eexpr = TBlock(fst_block @ [loop cases]) } - end - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "switch_to_if" + + let priority = solve_deps name [] + + let rec simplify_expr e = match e.eexpr with + | TParenthesis e + | TMeta(_,e) -> simplify_expr e + | _ -> e + + let traverse gen (should_convert:texpr->bool) (handle_nullables:bool) = + let basic = gen.gcon.basic in + let rec run e = + match e.eexpr with + | TSwitch(cond,cases,default) when should_convert e -> + let cond_etype, should_cache = match handle_nullables, gen.gfollow#run_f cond.etype with + | true, TType({ t_path = ([], "Null") }, [t]) -> + let rec take_off_nullable t = match gen.gfollow#run_f t with + | TType({ t_path = ([], "Null") }, [t]) -> take_off_nullable t + | _ -> t + in + + take_off_nullable t, true + | _, _ -> cond.etype, false + in + + if should_cache && not (should_convert { e with eexpr = TSwitch({ cond with etype = cond_etype }, cases, default) }) then begin + { e with eexpr = TSwitch(mk_cast cond_etype (run cond), List.map (fun (cs,e) -> (List.map run cs, run e)) cases, Option.map run default) } + end else begin + let local, fst_block = match cond.eexpr, should_cache with + | TLocal _, false -> cond, [] + | _ -> + let var = mk_temp gen "switch" cond_etype in + let cond = run cond in + let cond = if should_cache then mk_cast cond_etype cond else cond in + + mk_local var cond.epos, [ { eexpr = TVar(var,Some(cond)); etype = basic.tvoid; epos = cond.epos } ] + in + + let mk_eq cond = + { eexpr = TBinop(Ast.OpEq, local, cond); etype = basic.tbool; epos = cond.epos } + in + + let rec mk_many_cond conds = + match conds with + | cond :: [] -> + mk_eq cond + | cond :: tl -> + { eexpr = TBinop(Ast.OpBoolOr, mk_eq (run cond), mk_many_cond tl); etype = basic.tbool; epos = cond.epos } + | [] -> assert false + in + + let mk_many_cond conds = + let ret = mk_many_cond conds in + (* + this might be considered a hack. But since we're on a syntax filter and + the condition is guaranteed to not have run twice, we can really run the + expr filters again for it (so to change e.g. OpEq accordingly + *) + gen.gexpr_filters#run_f ret + in + + let rec loop cases = match cases with + | (conds,e) :: [] -> + { eexpr = TIf(mk_many_cond conds, run e, Option.map run default); etype = e.etype; epos = e.epos } + | (conds,e) :: tl -> + { eexpr = TIf(mk_many_cond conds, run e, Some(loop tl)); etype = e.etype; epos = e.epos } + | [] -> match default with + | None -> + raise Exit + | Some d -> run d + in + + try + { e with eexpr = TBlock(fst_block @ [loop cases]) } + with | Exit -> + { e with eexpr = TBlock [] } + end + | TSwitch(cond,cases,default) -> (try + match (simplify_expr cond).eexpr with + | TCall( { eexpr = TField(_,FStatic({ cl_path = [],"Type" }, { cf_name = "enumIndex" })) }, [enum] ) -> + let real_enum = match enum.etype with + | TEnum(e,_) -> e + | _ -> raise Not_found + in + if Meta.has Meta.Class real_enum.e_meta then raise Not_found; + let enum_expr = mk_mt_access (TEnumDecl(real_enum)) e.epos in + let fields = Hashtbl.create (List.length real_enum.e_names) in + PMap.iter (fun _ ef -> Hashtbl.add fields ef.ef_index ef) real_enum.e_constrs; + let cases = List.map (fun (el,e) -> + List.map (fun e -> match e.eexpr with + | TConst(TInt i) -> + let ef = Hashtbl.find fields (Int32.to_int i) in + { e with eexpr = TField(enum_expr, FEnum(real_enum,ef)); etype = TEnum(real_enum,List.map (fun _ -> t_dynamic) real_enum.e_params) } + | _ -> raise Not_found) el, run e + ) cases in + { e with eexpr = TSwitch(enum,cases,Option.map run default) } + | _ -> raise Not_found + with Not_found -> Type.map_expr run e) + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -8954,56 +9772,56 @@ end;; (* - (syntax) - When we pass a class as an object, in some languages we will need a special construct to be able to - access its statics as if they were normal object fields. On C# and Java the way found to do that is - by handling statics reflection also by a normal instance. This also happens in hxcpp and neko, so I - guess it's a valid practice. - So if we want to handle the reflection of the static MyClass, here's roughly how it will be done: + (syntax) + When we pass a class as an object, in some languages we will need a special construct to be able to + access its statics as if they were normal object fields. On C# and Java the way found to do that is + by handling statics reflection also by a normal instance. This also happens in hxcpp and neko, so I + guess it's a valid practice. + So if we want to handle the reflection of the static MyClass, here's roughly how it will be done: - var x = MyClass; - gets converted into - Haxe.Lang.Class x = Haxe.Lang.Runtime.GetType(typeof(MyClass).RuntimeHandle); + var x = MyClass; + gets converted into + Haxe.Lang.Class x = Haxe.Lang.Runtime.GetType(typeof(MyClass).RuntimeHandle); - which will in turn look in its cache but roughly would do: - Haxe.Lang.Class x = new Haxe.Lang.Class(new MyClass(EmptyObject.EMPTY)); + which will in turn look in its cache but roughly would do: + Haxe.Lang.Class x = new Haxe.Lang.Class(new MyClass(EmptyObject.EMPTY)); - This module will of course let the caller choose how this will be implemented. It will just identify all - uses of class that will require it to be cast as an object. + This module will of course let the caller choose how this will be implemented. It will just identify all + uses of class that will require it to be cast as an object. - dependencies: + dependencies: *) module ClassInstance = struct - let priority = solve_deps "class_instance" [] - - let traverse gen (change_expr:texpr->module_type->texpr) = - let rec run e = - match e.eexpr with - | TCall( ({ eexpr = TLocal(v) } as local), calls ) when String.get v.v_name 0 = '_' && Hashtbl.mem gen.gspecial_vars v.v_name -> - { e with eexpr = TCall(local, List.map (fun e -> - match e.eexpr with - | TTypeExpr _ -> e - | _ -> run e) calls) } - | TField({ eexpr = TTypeExpr(mt) }, f) -> - e - | TField(ef, f) -> - (match anon_class ef.etype with - | None -> Type.map_expr run e - | Some t -> - { e with eexpr = TField( { ef with eexpr = TTypeExpr(t) }, f) } - ) - | TTypeExpr(mt) -> change_expr e mt - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:"class_instance" ~priority:(PCustom priority) map + let priority = solve_deps "class_instance" [] + + let traverse gen (change_expr:texpr->module_type->texpr) = + let rec run e = + match e.eexpr with + | TCall( ({ eexpr = TLocal({ v_name = ("__is__" | "__as__" | "__typeof__") } as v) } as local), calls ) when Hashtbl.mem gen.gspecial_vars v.v_name -> + { e with eexpr = TCall(local, List.map (fun e -> + match e.eexpr with + | TTypeExpr _ -> e + | _ -> run e) calls) } + | TField({ eexpr = TTypeExpr(mt) }, f) -> + e + | TField(ef, f) -> + (match anon_class ef.etype with + | None -> Type.map_expr run e + | Some t -> + { e with eexpr = TField( { ef with eexpr = TTypeExpr(t) }, f) } + ) + | TTypeExpr(mt) -> change_expr e mt + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:"class_instance" ~priority:(PCustom priority) map end;; @@ -9013,21 +9831,21 @@ end;; (* - This module will handle Null types for languages that offer a way of dealing with - stack-allocated structures or tuples and generics. Essentialy on those targets a Null - will be a tuple ( 'a * bool ), where bool is whether the value is null or not. + This module will handle Null types for languages that offer a way of dealing with + stack-allocated structures or tuples and generics. Essentialy on those targets a Null + will be a tuple ( 'a * bool ), where bool is whether the value is null or not. - At first (configure-time), we will modify the follow function so it can follow correctly nested Null>, - and do not follow Null to its underlying type + At first (configure-time), we will modify the follow function so it can follow correctly nested Null>, + and do not follow Null to its underlying type - Then we will run a syntax filter, which will look for casts to Null and replace them by - a call to the new Null creation; - Also casts from Null to T or direct uses of Null (call, field access, array access, closure) - will result in the actual value being accessed - For compatibility with the C# target, HardNullable will accept both Null and haxe.lang.Null types + Then we will run a syntax filter, which will look for casts to Null and replace them by + a call to the new Null creation; + Also casts from Null to T or direct uses of Null (call, field access, array access, closure) + will result in the actual value being accessed + For compatibility with the C# target, HardNullable will accept both Null and haxe.lang.Null types - dependencies: - Needs to be run after all cast detection modules + dependencies: + Needs to be run after all cast detection modules *) @@ -9035,186 +9853,260 @@ end;; module HardNullableSynf = struct - let name = "hard_nullable" - - let priority = solve_deps name [DAfter CastDetect.ReturnCast.priority] - - let rec is_null_t gen t = match gen.greal_type t with - | TType( { t_path = ([], "Null") }, [of_t]) - | TInst( { cl_path = (["haxe";"lang"], "Null") }, [of_t]) -> - let rec take_off_null t = - match is_null_t gen t with | None -> t | Some s -> take_off_null s - in - - Some (take_off_null of_t) - | TMono r -> (match !r with | Some t -> is_null_t gen t | None -> None) - | TLazy f -> is_null_t gen (!f()) - | TType (t, tl) -> - is_null_t gen (apply_params t.t_types tl t.t_type) - | _ -> None - - let follow_addon gen t = - let rec strip_off_nullable t = - let t = gen.gfollow#run_f t in - match t with - (* haxe.lang.Null> wouldn't be a valid construct, so only follow Null<> *) - | TType ( { t_path = ([], "Null") }, [of_t] ) -> strip_off_nullable of_t - | _ -> t - in - - match t with - | TType( ({ t_path = ([], "Null") } as tdef), [of_t]) -> - Some( TType(tdef, [ strip_off_nullable of_t ]) ) - | _ -> None - - let traverse gen unwrap_null wrap_val null_to_dynamic has_value opeq_handler handle_opeq handle_cast = - let handle_unwrap to_t e = - let e_null_t = get (is_null_t gen e.etype) in - match gen.greal_type to_t with - | TDynamic _ | TMono _ | TAnon _ -> - (match e_null_t with - | TDynamic _ | TMono _ | TAnon _ -> - gen.ghandle_cast to_t e_null_t (unwrap_null e) - | _ -> null_to_dynamic e - ) - | _ -> - gen.ghandle_cast to_t e_null_t (unwrap_null e) - in - - let handle_wrap e t = - match e.eexpr with - | TConst(TNull) -> - wrap_val e t false - | _ -> - wrap_val e t true - in - - let is_null_t = is_null_t gen in - let rec run e = - match e.eexpr with - | TCast(v, _) -> - let null_et = is_null_t e.etype in - let null_vt = is_null_t v.etype in - (match null_vt, null_et with - | Some(vt), None -> - (match v.eexpr with - (* is there an unnecessary cast to Nullable? *) - | TCast(v2, _) -> - run { v with etype = e.etype } - | _ -> - handle_unwrap e.etype (run v) - ) - | None, Some(et) -> - handle_wrap (run v) et - | Some(vt), Some(et) when handle_cast -> - handle_wrap (gen.ghandle_cast et vt (handle_unwrap vt (run v))) et - | _ -> - Type.map_expr run e - ) - | TField(ef, field) when is_some (is_null_t ef.etype) -> - let to_t = get (is_null_t ef.etype) in - { e with eexpr = TField(handle_unwrap to_t (run ef), field) } - | TCall(ecall, params) when is_some (is_null_t ecall.etype) -> - let to_t = get (is_null_t ecall.etype) in - { e with eexpr = TCall(handle_unwrap to_t (run ecall), List.map run params) } - | TArray(earray, p) when is_some (is_null_t earray.etype) -> - let to_t = get (is_null_t earray.etype) in - { e with eexpr = TArray(handle_unwrap to_t (run earray), p) } - | TBinop(op, e1, e2) -> - let e1_t = is_null_t e1.etype in - let e2_t = is_null_t e2.etype in - - (match op with - | Ast.OpAssign - | Ast.OpAssignOp _ -> - (match e1_t, e2_t with - | Some t1, Some t2 -> - (match op with - | Ast.OpAssign -> - { e with eexpr = TBinop( op, run e1, handle_wrap ( handle_unwrap t2 (run e2) ) t1 ) } - | Ast.OpAssignOp op -> - (match e1.eexpr with - | TLocal _ -> - { e with eexpr = TBinop( Ast.OpAssign, e1, handle_wrap { e with eexpr = TBinop (op, handle_unwrap t1 e1, handle_unwrap t2 (run e2) ) } t1 ) } - | _ -> - let v, e1, evars = match e1.eexpr with - | TField(ef, f) -> - let v = mk_temp gen "nullbinop" ef.etype in - v, { e1 with eexpr = TField(mk_local v ef.epos, f) }, ef - | _ -> - let v = mk_temp gen "nullbinop" e1.etype in - v, mk_local v e1.epos, e1 - in - { e with eexpr = TBlock([ - { eexpr = TVars([v, Some evars ]); etype = gen.gcon.basic.tvoid; epos = e.epos }; - { 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 - ) - - | _ -> - Type.map_expr run e (* casts are already dealt with normal CastDetection module *) - ) - | Ast.OpEq | Ast.OpNotEq when not handle_opeq -> - Type.map_expr run e - | Ast.OpEq | Ast.OpNotEq -> - (match e1.eexpr, e2.eexpr with - | TConst(TNull), _ when is_some e2_t -> - let e = has_value e2 in - if op = Ast.OpEq then - { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } - else - e - | _, TConst(TNull) when is_some e1_t -> - let e = has_value e1 in - if op = Ast.OpEq then - { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } - else - e - | _ when is_some e1_t || is_some e2_t -> - let e1, e2 = - if not (is_some e1_t) then - run e2, handle_wrap (run e1) (get e2_t) - else if not (is_some e2_t) then - run e1, handle_wrap (run e2) (get e1_t) - else - run e1, run e2 - in - let e = opeq_handler e1 e2 in - if op = Ast.OpEq then - { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } - else - e - | _ -> - Type.map_expr run e - ) - | _ -> - let e1 = if is_some e1_t then - handle_unwrap (get e1_t) (run e1) - else run e1 in - let e2 = if is_some e2_t then - handle_unwrap (get e2_t) (run e2) - else - run e2 in - - (* if it is Null, we need to convert the result again to null *) - let e_t = (is_null_t e.etype) in - if is_some e_t then - wrap_val { eexpr = TBinop(op, e1, e2); etype = get e_t; epos = e.epos } (get e_t) true - else - { e with eexpr = TBinop(op, e1, e2) } - ) - (*| TUnop( (Ast.Increment as op)*) - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - gen.gfollow#add ~name:(name ^ "_follow") (follow_addon gen); - - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "hard_nullable" + + let priority = solve_deps name [DAfter CastDetect.ReturnCast.priority] + + let rec is_null_t gen t = match gen.greal_type t with + | TType( { t_path = ([], "Null") }, [of_t]) + | TInst( { cl_path = (["haxe";"lang"], "Null") }, [of_t]) -> + let rec take_off_null t = + match is_null_t gen t with | None -> t | Some s -> take_off_null s + in + + Some (take_off_null of_t) + | TMono r -> (match !r with | Some t -> is_null_t gen t | None -> None) + | TLazy f -> is_null_t gen (!f()) + | TType (t, tl) -> + is_null_t gen (apply_params t.t_params tl t.t_type) + | _ -> None + + let follow_addon gen t = + let rec strip_off_nullable t = + let t = gen.gfollow#run_f t in + match t with + (* haxe.lang.Null> wouldn't be a valid construct, so only follow Null<> *) + | TType ( { t_path = ([], "Null") }, [of_t] ) -> strip_off_nullable of_t + | _ -> t + in + + match t with + | TType( ({ t_path = ([], "Null") } as tdef), [of_t]) -> + Some( TType(tdef, [ strip_off_nullable of_t ]) ) + | _ -> None + + let traverse gen unwrap_null wrap_val null_to_dynamic has_value opeq_handler handle_opeq handle_cast = + (* let unwrap_null e = *) + (* let ret = unwrap_null e in *) + (* { ret with eexpr = TParenthesis(ret) } *) + (* in *) + (* let wrap_val e t b = *) + (* let ret = wrap_val e t b in *) + (* { ret with eexpr = TParenthesis(ret) } *) + (* in *) + let is_string t = match gen.greal_type t with + | TInst({ cl_path=([],"String") },_) -> true + | _ -> false + in + let handle_unwrap to_t e = + let e_null_t = get (is_null_t gen e.etype) in + match gen.greal_type to_t with + | TDynamic _ | TMono _ | TAnon _ -> + (match e_null_t with + | TDynamic _ | TMono _ | TAnon _ -> + gen.ghandle_cast to_t e_null_t (unwrap_null e) + | _ -> null_to_dynamic e + ) + | _ -> + gen.ghandle_cast to_t e_null_t (unwrap_null e) + in + + let handle_wrap e t = + match e.eexpr with + | TConst(TNull) -> + wrap_val e t false + | _ -> + wrap_val e t true + in + + let is_null_t = is_null_t gen in + let cur_block = ref [] in + let add_tmp v e p = + cur_block := { eexpr = TVar(v,e); etype = gen.gcon.basic.tvoid; epos = p } :: !cur_block + in + let get_local e = match e.eexpr with + | TLocal _ -> + e, e + | _ -> + let v = mk_temp gen "nulltmp" e.etype in + add_tmp v (Some (null e.etype e.epos)) e.epos; + let local = { e with eexpr = TLocal(v) } in + mk_paren { e with eexpr = TBinop(Ast.OpAssign, local, e) }, local + in + let rec run e = + match e.eexpr with + | TBlock(bl) -> + let lst = !cur_block in + cur_block := []; + List.iter (fun e -> + let e = run e in + cur_block := (e :: !cur_block) + ) bl; + let ret = !cur_block in + cur_block := lst; + { e with eexpr = TBlock(List.rev ret) } + | TCast(v, _) -> + let null_et = is_null_t e.etype in + let null_vt = is_null_t v.etype in + (match null_vt, null_et with + | Some(vt), None when is_string e.etype -> + let v = run v in + { e with eexpr = TCast(null_to_dynamic v,None) } + | Some(vt), None -> + (match v.eexpr with + (* is there an unnecessary cast to Nullable? *) + | TCast(v2, _) -> + run { v with etype = e.etype } + | _ -> + handle_unwrap e.etype (run v) + ) + | None, Some(et) -> + handle_wrap (run v) et + | Some(vt), Some(et) when handle_cast -> + handle_wrap (gen.ghandle_cast et vt (handle_unwrap vt (run v))) et + | Some(vt), Some(et) when not (type_iseq (run_follow gen vt) (run_follow gen et)) -> + (* check if has value and convert *) + let vlocal_fst, vlocal = get_local (run v) in + { + eexpr = TIf( + has_value vlocal_fst, + handle_wrap (mk_cast et (unwrap_null vlocal)) et, + Some( handle_wrap (null et e.epos) et )); + etype = e.etype; + epos = e.epos + } + | _ -> + Type.map_expr run e + ) + | TField(ef, field) when is_some (is_null_t ef.etype) -> + let to_t = get (is_null_t ef.etype) in + { e with eexpr = TField(handle_unwrap to_t (run ef), field) } + | TCall(ecall, params) when is_some (is_null_t ecall.etype) -> + let to_t = get (is_null_t ecall.etype) in + { e with eexpr = TCall(handle_unwrap to_t (run ecall), List.map run params) } + | TArray(earray, p) when is_some (is_null_t earray.etype) -> + let to_t = get (is_null_t earray.etype) in + { e with eexpr = TArray(handle_unwrap to_t (run earray), p) } + | TBinop(op, e1, e2) -> + let e1_t = is_null_t e1.etype in + let e2_t = is_null_t e2.etype in + + (match op with + | Ast.OpAssign + | Ast.OpAssignOp _ -> + (match e1_t, e2_t with + | Some t1, Some t2 -> + (match op with + | Ast.OpAssign -> + Type.map_expr run e + | Ast.OpAssignOp op -> + (match e1.eexpr with + | TLocal _ -> + { e with eexpr = TBinop( Ast.OpAssign, e1, handle_wrap { e with eexpr = TBinop (op, handle_unwrap t1 e1, handle_unwrap t2 (run e2) ) } t1 ) } + | _ -> + let v, e1, evars = match e1.eexpr with + | TField(ef, f) -> + let v = mk_temp gen "nullbinop" ef.etype in + v, { e1 with eexpr = TField(mk_local v ef.epos, f) }, ef + | _ -> + let v = mk_temp gen "nullbinop" e1.etype in + v, mk_local v e1.epos, e1 + in + { e with eexpr = TBlock([ + { eexpr = TVar(v, Some evars); etype = gen.gcon.basic.tvoid; epos = e.epos }; + { 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 + ) + + | _ -> + Type.map_expr run e (* casts are already dealt with normal CastDetection module *) + ) + | Ast.OpEq | Ast.OpNotEq when not handle_opeq -> + Type.map_expr run e + | Ast.OpEq | Ast.OpNotEq -> + (match e1.eexpr, e2.eexpr with + | TConst(TNull), _ when is_some e2_t -> + let e = has_value (run e2) in + if op = Ast.OpEq then + { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } + else + e + | _, TConst(TNull) when is_some e1_t -> + let e = has_value (run e1) in + if op = Ast.OpEq then + { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } + else + e + | _ when is_some e1_t || is_some e2_t -> + let e1, e2 = + if not (is_some e1_t) then + run e2, handle_wrap (run e1) (get e2_t) + else if not (is_some e2_t) then + run e1, handle_wrap (run e2) (get e1_t) + else + run e1, run e2 + in + let e = opeq_handler e1 e2 in + if op = Ast.OpEq then + { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } + else + e + | _ -> + Type.map_expr run e + ) + | Ast.OpAdd when is_string e1.etype || is_string e2.etype -> + let e1 = if is_some e1_t then + null_to_dynamic (run e1) + else + run e1 + in + let e2 = if is_some e2_t then + null_to_dynamic (run e2) + else + run e2 + in + let e_t = is_null_t e.etype in + if is_some e_t then + wrap_val { eexpr = TBinop(op,e1,e2); etype = get e_t; epos = e.epos } (get e_t) true + else + { e with eexpr = TBinop(op,e1,e2) } + | _ -> + let e1 = if is_some e1_t then + handle_unwrap (get e1_t) (run e1) + else run e1 in + let e2 = if is_some e2_t then + handle_unwrap (get e2_t) (run e2) + else + run e2 in + + (* if it is Null, we need to convert the result again to null *) + let e_t = (is_null_t e.etype) in + if is_some e_t then + wrap_val { eexpr = TBinop(op, e1, e2); etype = get e_t; epos = e.epos } (get e_t) true + else + { e with eexpr = TBinop(op, e1, e2) } + ) + (*| TUnop( (Ast.Increment as op)*) + | _ -> Type.map_expr run e + in + let run e = match e.eexpr with + | TFunction tf -> + run { e with eexpr = TFunction { tf with tf_expr = mk_block tf.tf_expr } } + | TBlock _ -> + run e + | _ -> match run (mk_block e) with + | { eexpr = TBlock([e]) } -> e + | e -> e + in + run + + let configure gen (mapping_func:texpr->texpr) = + gen.gfollow#add ~name:(name ^ "_follow") (follow_addon gen); + + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9224,40 +10116,40 @@ end;; (* - A syntax filter that will change array declarations to the actual native array declarations plus - the haxe array initialization + A syntax filter that will change array declarations to the actual native array declarations plus + the haxe array initialization - dependencies: - Must run after ObjectDeclMap since it can add TArrayDecl expressions + dependencies: + Must run after ObjectDeclMap since it can add TArrayDecl expressions *) module ArrayDeclSynf = struct - let name = "array_decl_synf" + let name = "array_decl_synf" - let priority = solve_deps name [DAfter ObjectDeclMap.priority] + let priority = solve_deps name [DAfter ObjectDeclMap.priority] - let default_implementation gen native_array_cl = - let rec run e = - match e.eexpr with - | TArrayDecl el -> - 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 - in + let default_implementation gen native_array_cl = + let rec run e = + match e.eexpr with + | TArrayDecl el -> + 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 + in - let changed_params = gen.greal_type_param (TClassDecl cl) params in - { e with eexpr = TNew(cl, changed_params, [ { e with eexpr = TArrayDecl(List.map run el); etype = TInst(native_array_cl, changed_params) } ] ); } - | _ -> Type.map_expr run e - in - run + let changed_params = gen.greal_type_param (TClassDecl cl) params in + { e with eexpr = TNew(cl, changed_params, [ { e with eexpr = TArrayDecl(List.map run el); etype = TInst(native_array_cl, changed_params) } ] ); } + | _ -> Type.map_expr run e + in + run - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9267,106 +10159,105 @@ end;; (* - In most languages, 'break' is used as a statement also to break from switch statements. - This generates an incompatibility with haxe code, as we can use break to break from loops from inside a switch + In most languages, 'break' is used as a statement also to break from switch statements. + This generates an incompatibility with haxe code, as we can use break to break from loops from inside a switch - This script will detect 'breaks' inside switch statements, and will offer the opportunity to change both - when this pattern is found. + This script will detect 'breaks' inside switch statements, and will offer the opportunity to change both + when this pattern is found. - Some options are possible: - On languages that support goto, 'break' may mean goto " after the loop ". There also can be special labels for - loops, so you can write "break label" (javascript, java, d) - On languages that do not support goto, a custom solution must be enforced + Some options are possible: + On languages that support goto, 'break' may mean goto " after the loop ". There also can be special labels for + loops, so you can write "break label" (javascript, java, d) + On languages that do not support goto, a custom solution must be enforced - dependencies: - Since UnreachableCodeElimination must run before it, and Unreachable should be one of the - very last filters to run, we will make a fixed value which runs after UnreachableCodeElimination - (meaning: it's the very last filter) + dependencies: + Since UnreachableCodeElimination must run before it, and Unreachable should be one of the + very last filters to run, we will make a fixed value which runs after UnreachableCodeElimination + (meaning: it's the very last filter) *) module SwitchBreakSynf = struct - let name = "switch_break_synf" - - let priority = min_dep -. 150.0 - - type add_to_block_api = texpr->bool->unit - - let traverse gen (change_loop:texpr->int->add_to_block_api->texpr) (change_break:texpr->int->add_to_block_api->texpr) = - let in_switch = ref false in - let cur_block = ref [] in - let to_add = ref [] in - let did_found = ref (-1) in - - let api expr before = - if before then cur_block := expr :: !cur_block else to_add := expr :: !to_add - in - let num = ref 0 in - let cur_num = ref 0 in - - let rec run e = - match e.eexpr with - | TFunction _ -> - let old_num = !num in - num := 0; - let ret = Type.map_expr run e in - num := old_num; - ret - | TFor _ - | TWhile _ -> - let last_switch = !in_switch in - let last_found = !did_found in - let last_num = !cur_num in - in_switch := false; - incr num; - cur_num := !num; - did_found := -1; - let new_e = Type.map_expr run e in (* assuming that no loop will be found in the condition *) - let new_e = if !did_found <> -1 then change_loop new_e !did_found api else new_e in - did_found := last_found; - in_switch := last_switch; - cur_num := last_num; - - new_e - | TSwitch _ - | TMatch _ -> - let last_switch = !in_switch in - in_switch := true; - - let new_e = Type.map_expr run e in - - in_switch := last_switch; - new_e - | TBlock bl -> - let last_block = !cur_block in - let last_toadd = !to_add in - to_add := []; - cur_block := []; - - List.iter (fun e -> - let new_e = run e in - cur_block := new_e :: !cur_block; - match !to_add with - | [] -> () - | _ -> cur_block := !to_add @ !cur_block; to_add := [] - ) bl; - - let ret = List.rev !cur_block in - cur_block := last_block; - to_add := last_toadd; - - { e with eexpr = TBlock(ret) } - | TBreak -> - if !in_switch then (did_found := !cur_num; change_break e !cur_num api) else e - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "switch_break_synf" + + let priority = min_dep -. 150.0 + + type add_to_block_api = texpr->bool->unit + + let traverse gen (change_loop:texpr->int->add_to_block_api->texpr) (change_break:texpr->int->add_to_block_api->texpr) = + let in_switch = ref false in + let cur_block = ref [] in + let to_add = ref [] in + let did_found = ref (-1) in + + let api expr before = + if before then cur_block := expr :: !cur_block else to_add := expr :: !to_add + in + let num = ref 0 in + let cur_num = ref 0 in + + let rec run e = + match e.eexpr with + | TFunction _ -> + let old_num = !num in + num := 0; + let ret = Type.map_expr run e in + num := old_num; + ret + | TFor _ + | TWhile _ -> + let last_switch = !in_switch in + let last_found = !did_found in + let last_num = !cur_num in + in_switch := false; + incr num; + cur_num := !num; + did_found := -1; + let new_e = Type.map_expr run e in (* assuming that no loop will be found in the condition *) + let new_e = if !did_found <> -1 then change_loop new_e !did_found api else new_e in + did_found := last_found; + in_switch := last_switch; + cur_num := last_num; + + new_e + | TSwitch _ -> + let last_switch = !in_switch in + in_switch := true; + + let new_e = Type.map_expr run e in + + in_switch := last_switch; + new_e + | TBlock bl -> + let last_block = !cur_block in + let last_toadd = !to_add in + to_add := []; + cur_block := []; + + List.iter (fun e -> + let new_e = run e in + cur_block := new_e :: !cur_block; + match !to_add with + | [] -> () + | _ -> cur_block := !to_add @ !cur_block; to_add := [] + ) bl; + + let ret = List.rev !cur_block in + cur_block := last_block; + to_add := last_toadd; + + { e with eexpr = TBlock(ret) } + | TBreak -> + if !in_switch then (did_found := !cur_num; change_break e !cur_num api) else e + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9376,215 +10267,215 @@ end;; (* - In some source code platforms, the code won't compile if there is Unreachable code, so this filter will take off any unreachable code. - If the parameter "handle_switch_break" is set to true, it will already add a "break" statement on switch cases when suitable; - in order to not confuse with while break, it will be a special expression __sbreak__ - If the parameter "handle_not_final_returns" is set to true, it will also add final returns when functions are detected to be lacking of them. - (Will respect __fallback__ expressions) - If the parameter "java_mode" is set to true, some additional checks following the java unreachable specs - (http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21) will be added + In some source code platforms, the code won't compile if there is Unreachable code, so this filter will take off any unreachable code. + If the parameter "handle_switch_break" is set to true, it will already add a "break" statement on switch cases when suitable; + in order to not confuse with while break, it will be a special expression __sbreak__ + If the parameter "handle_not_final_returns" is set to true, it will also add final returns when functions are detected to be lacking of them. + (Will respect __fallback__ expressions) + If the parameter "java_mode" is set to true, some additional checks following the java unreachable specs + (http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21) will be added - dependencies: - This must run before SwitchBreakSynf (see SwitchBreakSynf dependecy value) - This must be the LAST syntax filter to run. It expects ExpressionUnwrap to have run correctly, since this will only work for source-code based targets + dependencies: + This must run before SwitchBreakSynf (see SwitchBreakSynf dependecy value) + This must be the LAST syntax filter to run. It expects ExpressionUnwrap to have run correctly, since this will only work for source-code based targets *) module UnreachableCodeEliminationSynf = struct - let name = "unreachable_synf" - - let priority = min_dep -. 100.0 - - type uexpr_kind = - | Normal - | BreaksLoop - | BreaksFunction - - let aggregate_kind e1 e2 = - match e1, e2 with - | Normal, _ - | _, Normal -> Normal - | BreaksLoop, _ - | _, BreaksLoop -> BreaksLoop - | BreaksFunction, BreaksFunction -> BreaksFunction - - let aggregate_constant op c1 c2= - match op, c1, c2 with - | OpEq, Some v1, Some v2 -> Some (TBool (v1 = v2)) - | OpNotEq, Some v1, Some v2 -> Some (TBool (v1 <> v2)) - | OpBoolOr, Some (TBool v1) , Some (TBool v2) -> Some (TBool (v1 || v2)) - | OpBoolAnd, Some (TBool v1) , Some (TBool v2) -> Some (TBool (v1 && v2)) - | OpAssign, _, Some v2 -> Some v2 - | _ -> None - - let rec get_constant_expr e = - match e.eexpr with - | TConst (v) -> Some v - | TBinop(op, v1, v2) -> aggregate_constant op (get_constant_expr v1) (get_constant_expr v2) - | TParenthesis(e) -> get_constant_expr e - | _ -> None - - let traverse gen should_warn handle_switch_break handle_not_final_returns java_mode = - let basic = gen.gcon.basic in - - let do_warn = - if should_warn then gen.gcon.warning "Unreachable code" else (fun pos -> ()) - in - - let return_loop expr kind = - match kind with - | Normal | BreaksLoop -> expr, Normal - | _ -> expr, kind - in - - let sbreak = alloc_var "__sbreak__" t_dynamic in - let mk_sbreak = mk_local sbreak in - - let rec has_fallback expr = match expr.eexpr with - | TBlock(bl) -> (match List.rev bl with - | { eexpr = TLocal { v_name = "__fallback__" } } :: _ -> true - | ({ eexpr = TBlock(_) } as bl) :: _ -> has_fallback bl - | _ -> false) - | TLocal { v_name = "__fallback__" } -> true - | _ -> false - in - - let handle_case = if handle_switch_break then - (fun (expr,kind) -> - match kind with - | Normal when has_fallback expr -> expr - | Normal -> Codegen.concat expr (mk_sbreak expr.epos) - | BreaksLoop | BreaksFunction -> expr - ) - else - fst - in - - let has_break = ref false in - - let rec process_expr expr = - match expr.eexpr with - | TReturn _ | TThrow _ -> expr, BreaksFunction - | TContinue -> expr, BreaksLoop - | TBreak -> has_break := true; expr, BreaksLoop - | TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> expr, BreaksLoop - - | TBlock bl -> - let new_block = ref [] in - let is_unreachable = ref false in - let ret_kind = ref Normal in - - List.iter (fun e -> - if !is_unreachable then - do_warn e.epos - else begin - let changed_e, kind = process_expr e in - new_block := changed_e :: !new_block; - match kind with - | BreaksLoop | BreaksFunction -> - ret_kind := kind; - is_unreachable := true - | _ -> () - end - ) bl; - - { expr with eexpr = TBlock(List.rev !new_block) }, !ret_kind - | TFunction tf -> - let changed, kind = process_expr tf.tf_expr in - let changed = if handle_not_final_returns && not (is_void tf.tf_type) && kind <> BreaksFunction then - Codegen.concat changed { eexpr = TReturn( Some (null tf.tf_type expr.epos) ); etype = basic.tvoid; epos = expr.epos } - else - changed - in - - { expr with eexpr = TFunction({ tf with tf_expr = changed }) }, Normal - | TFor(var, cond, block) -> - let last_has_break = !has_break in - has_break := false; - - let changed_block, _ = process_expr block in - has_break := last_has_break; - let expr = { expr with eexpr = TFor(var, cond, changed_block) } in - return_loop expr Normal - | TIf(cond, eif, None) -> - if java_mode then - match get_constant_expr cond with - | Some (TBool true) -> - process_expr eif - | _ -> - { expr with eexpr = TIf(cond, fst (process_expr eif), None) }, Normal - else - { expr with eexpr = TIf(cond, fst (process_expr eif), None) }, Normal - | TIf(cond, eif, Some eelse) -> - let eif, eif_k = process_expr eif in - let eelse, eelse_k = process_expr eelse in - let k = aggregate_kind eif_k eelse_k in - { expr with eexpr = TIf(cond, eif, Some eelse) }, k - | TWhile(cond, block, flag) -> - let last_has_break = !has_break in - has_break := false; - - let block, k = process_expr block in - if java_mode then - match get_constant_expr cond, !has_break with - | Some (TBool true), false -> - has_break := last_has_break; - { expr with eexpr = TWhile(cond, block, flag) }, BreaksFunction - | Some (TBool false), _ -> - has_break := last_has_break; - do_warn expr.epos; - null expr.etype expr.epos, Normal - | _ -> - has_break := last_has_break; - return_loop { expr with eexpr = TWhile(cond,block,flag) } Normal - else begin - has_break := last_has_break; - return_loop { expr with eexpr = TWhile(cond,block,flag) } Normal - end - | TSwitch(cond, el_e_l, None) -> - { expr with eexpr = TSwitch(cond, List.map (fun (el, e) -> (el, handle_case (process_expr e))) el_e_l, None) }, Normal - | TSwitch(cond, el_e_l, Some def) -> - let def, k = process_expr def in - let def = handle_case (def, k) in - let k = ref k in - let ret = { expr with eexpr = TSwitch(cond, List.map (fun (el, e) -> - let e, ek = process_expr e in - k := aggregate_kind !k ek; - (el, handle_case (e, ek)) - ) el_e_l, Some def) } in - ret, !k - | TMatch(cond, ep, il_vopt_e_l, None) -> - { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> (il, vopt, handle_case (process_expr e))) il_vopt_e_l, None) }, Normal - | TMatch(cond, ep, il_vopt_e_l, Some def) -> - let def, k = process_expr def in - let def = handle_case (def, k) in - let k = ref k in - let ret = { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> - let e, ek = process_expr e in - k := aggregate_kind !k ek; - (il, vopt, handle_case (e, ek)) - ) il_vopt_e_l, Some def) } in - ret, !k - | TTry (e, catches) -> - let e, k = process_expr e in - let k = ref k in - let ret = { expr with eexpr = TTry(e, List.map (fun (v, e) -> - let e, ek = process_expr e in - k := aggregate_kind !k ek; - (v, e) - ) catches) } in - ret, !k - | _ -> expr, Normal - in - - let run e = fst (process_expr e) in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "unreachable_synf" + + let priority = min_dep -. 100.0 + + type uexpr_kind = + | Normal + | BreaksLoop + | BreaksFunction + + let aggregate_kind e1 e2 = + match e1, e2 with + | Normal, _ + | _, Normal -> Normal + | BreaksLoop, _ + | _, BreaksLoop -> BreaksLoop + | BreaksFunction, BreaksFunction -> BreaksFunction + + let aggregate_constant op c1 c2= + match op, c1, c2 with + | OpEq, Some v1, Some v2 -> Some (TBool (v1 = v2)) + | OpNotEq, Some v1, Some v2 -> Some (TBool (v1 <> v2)) + | OpBoolOr, Some (TBool v1) , Some (TBool v2) -> Some (TBool (v1 || v2)) + | OpBoolAnd, Some (TBool v1) , Some (TBool v2) -> Some (TBool (v1 && v2)) + | OpAssign, _, Some v2 -> Some v2 + | _ -> None + + let rec get_constant_expr e = + match e.eexpr with + | TConst (v) -> Some v + | TBinop(op, v1, v2) -> aggregate_constant op (get_constant_expr v1) (get_constant_expr v2) + | TParenthesis(e) | TMeta(_,e) -> get_constant_expr e + | _ -> None + + let traverse gen should_warn handle_switch_break handle_not_final_returns java_mode = + let basic = gen.gcon.basic in + + let do_warn = + if should_warn then gen.gcon.warning "Unreachable code" else (fun pos -> ()) + in + + let return_loop expr kind = + match kind with + | Normal | BreaksLoop -> expr, Normal + | _ -> expr, kind + in + + let sbreak = alloc_var "__sbreak__" t_dynamic in + let mk_sbreak = mk_local sbreak in + + let rec has_fallback expr = match expr.eexpr with + | TBlock(bl) -> (match List.rev bl with + | { eexpr = TLocal { v_name = "__fallback__" } } :: _ -> true + | ({ eexpr = TBlock(_) } as bl) :: _ -> has_fallback bl + | _ -> false) + | TLocal { v_name = "__fallback__" } -> true + | _ -> false + in + + let handle_case = if handle_switch_break then + (fun (expr,kind) -> + match kind with + | Normal when has_fallback expr -> expr + | Normal -> Type.concat expr (mk_sbreak expr.epos) + | BreaksLoop | BreaksFunction -> expr + ) + else + fst + in + + let has_break = ref false in + + let rec process_expr expr = + match expr.eexpr with + | TReturn _ | TThrow _ -> expr, BreaksFunction + | TContinue -> expr, BreaksLoop + | TBreak -> has_break := true; expr, BreaksLoop + | TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> expr, BreaksLoop + + | TBlock bl -> + let new_block = ref [] in + let is_unreachable = ref false in + let ret_kind = ref Normal in + + List.iter (fun e -> + if !is_unreachable then + do_warn e.epos + else begin + let changed_e, kind = process_expr e in + new_block := changed_e :: !new_block; + match kind with + | BreaksLoop | BreaksFunction -> + ret_kind := kind; + is_unreachable := true + | _ -> () + end + ) bl; + + { expr with eexpr = TBlock(List.rev !new_block) }, !ret_kind + | TFunction tf -> + let changed, kind = process_expr tf.tf_expr in + let changed = if handle_not_final_returns && not (is_void tf.tf_type) && kind <> BreaksFunction then + Type.concat changed { eexpr = TReturn( Some (null tf.tf_type expr.epos) ); etype = basic.tvoid; epos = expr.epos } + else + changed + in + + { expr with eexpr = TFunction({ tf with tf_expr = changed }) }, Normal + | TFor(var, cond, block) -> + let last_has_break = !has_break in + has_break := false; + + let changed_block, _ = process_expr block in + has_break := last_has_break; + let expr = { expr with eexpr = TFor(var, cond, changed_block) } in + return_loop expr Normal + | TIf(cond, eif, None) -> + if java_mode then + match get_constant_expr cond with + | Some (TBool true) -> + process_expr eif + | _ -> + { expr with eexpr = TIf(cond, fst (process_expr eif), None) }, Normal + else + { expr with eexpr = TIf(cond, fst (process_expr eif), None) }, Normal + | TIf(cond, eif, Some eelse) -> + let eif, eif_k = process_expr eif in + let eelse, eelse_k = process_expr eelse in + let k = aggregate_kind eif_k eelse_k in + { expr with eexpr = TIf(cond, eif, Some eelse) }, k + | TWhile(cond, block, flag) -> + let last_has_break = !has_break in + has_break := false; + + let block, k = process_expr block in + if java_mode then + match get_constant_expr cond, flag, !has_break with + | Some (TBool true), _, false -> + has_break := last_has_break; + { expr with eexpr = TWhile(cond, block, flag) }, BreaksFunction + | Some (TBool false), NormalWhile, _ -> + has_break := last_has_break; + do_warn expr.epos; + null expr.etype expr.epos, Normal + | _ -> + has_break := last_has_break; + return_loop { expr with eexpr = TWhile(cond,block,flag) } Normal + else begin + has_break := last_has_break; + return_loop { expr with eexpr = TWhile(cond,block,flag) } Normal + end + | TSwitch(cond, el_e_l, None) -> + { expr with eexpr = TSwitch(cond, List.map (fun (el, e) -> (el, handle_case (process_expr e))) el_e_l, None) }, Normal + | TSwitch(cond, el_e_l, Some def) -> + let def, k = process_expr def in + let def = handle_case (def, k) in + let k = ref k in + let ret = { expr with eexpr = TSwitch(cond, List.map (fun (el, e) -> + let e, ek = process_expr e in + k := aggregate_kind !k ek; + (el, handle_case (e, ek)) + ) el_e_l, Some def) } in + ret, !k +(* | TMatch(cond, ep, il_vopt_e_l, None) -> + { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> (il, vopt, handle_case (process_expr e))) il_vopt_e_l, None) }, Normal *) +(* | TMatch(cond, ep, il_vopt_e_l, Some def) -> + let def, k = process_expr def in + let def = handle_case (def, k) in + let k = ref k in + let ret = { expr with eexpr = TMatch(cond, ep, List.map (fun (il, vopt, e) -> + let e, ek = process_expr e in + k := aggregate_kind !k ek; + (il, vopt, handle_case (e, ek)) + ) il_vopt_e_l, Some def) } in + ret, !k *) + | TTry (e, catches) -> + let e, k = process_expr e in + let k = ref k in + let ret = { expr with eexpr = TTry(e, List.map (fun (v, e) -> + let e, ek = process_expr e in + k := aggregate_kind !k ek; + (v, e) + ) catches) } in + ret, !k + | _ -> expr, Normal + in + + let run e = fst (process_expr e) in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9594,96 +10485,161 @@ end;; (* - This Module Filter will go through all defined functions in all modules and change them - so they set all default arguments to be of a Nullable type, and adds the unroll from nullable to - the not-nullable type in the beginning of the function. + This Module Filter will go through all defined functions in all modules and change them + so they set all default arguments to be of a Nullable type, and adds the unroll from nullable to + the not-nullable type in the beginning of the function. - dependencies: - It must run before OverloadingCtors, since OverloadingCtors will change optional structures behavior + dependencies: + It must run before OverloadingCtors, since OverloadingCtors will change optional structures behavior *) module DefaultArguments = struct - let name = "default_arguments" - - let priority = solve_deps name [ DBefore OverloadingConstructor.priority ] - - let add_opt gen block pos (var,opt) = - match opt with - | None | Some TNull -> (var,opt) - | Some (TString str) -> - block := Codegen.set_default gen.gcon var (TString str) pos :: !block; - (var, opt) - | Some const -> - let basic = gen.gcon.basic in - let nullable_var = mk_temp gen var.v_name (basic.tnull var.v_type) in - let orig_name = var.v_name in - var.v_name <- nullable_var.v_name; - nullable_var.v_name <- orig_name; - let const_t = match const with - | TString _ -> basic.tstring | TInt _ -> basic.tint | TFloat _ -> basic.tfloat - | TNull -> var.v_type | TBool _ -> basic.tbool | _ -> assert false - in - (* var v = (temp_var == null) ? const : cast temp_var; *) - block := - { - eexpr = TVars([var, Some( - { - eexpr = TIf( - { eexpr = TBinop(Ast.OpEq, mk_local nullable_var pos, null nullable_var.v_type pos); etype = basic.tbool; epos = pos }, - mk_cast var.v_type { eexpr = TConst(const); etype = const_t; epos = pos }, - Some(mk_cast var.v_type (mk_local nullable_var pos)) - ); - etype = var.v_type; - epos = pos; - })]); - etype = basic.tvoid; - epos = pos; - } :: !block; - (nullable_var, opt) - - let change_func gen cf = - let basic = gen.gcon.basic in - match cf.cf_kind, follow cf.cf_type with - | Var _, _ | Method MethDynamic, _ -> () - | _, TFun(args, ret) -> - let found = ref false in - let args = ref (List.map (fun (n,opt,t) -> - (n,opt, if opt then (found := true; basic.tnull t) else t) - ) args) in - (match !found, cf.cf_expr with - | true, Some ({ eexpr = TFunction tf } as texpr) -> - let block = ref [] in - let tf_args = List.map (add_opt gen block tf.tf_expr.epos) tf.tf_args in - - args := fun_args tf_args; - cf.cf_expr <- Some( {texpr with eexpr = TFunction( { tf with - tf_args = tf_args; - tf_expr = Codegen.concat { tf.tf_expr with eexpr = TBlock(!block); etype = basic.tvoid } tf.tf_expr - } ); etype = TFun(!args, ret) } ); - cf.cf_type <- TFun(!args, ret) - - | _ -> () - ); - (if !found then cf.cf_type <- TFun(!args, ret)) - | _, _ -> assert false - - let traverse gen = - let run md = match md with - | TClassDecl cl -> - List.iter (change_func gen) cl.cl_ordered_fields; - List.iter (change_func gen) cl.cl_ordered_statics; - (match cl.cl_constructor with | None -> () | Some cf -> change_func gen cf); - md - | _ -> md - in - run - - let configure gen (mapping_func:module_type->module_type) = - let map md = Some(mapping_func md) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + let name = "default_arguments" + + let priority = solve_deps name [ DBefore OverloadingConstructor.priority ] + + let gen_check basic t nullable_var const pos = + let is_null t = match t with TType({t_path = ([],"Null")}, _) -> true | _ -> false in + let needs_cast t1 t2 = match is_null t1, is_null t2 with + | true, false | false, true -> true + | _ -> false + in + + let const_t = match const with + | TString _ -> basic.tstring | TInt _ -> basic.tint | TFloat _ -> basic.tfloat + | TNull -> t | TBool _ -> basic.tbool | _ -> assert false + in + let const = { eexpr = TConst(const); etype = const_t; epos = pos } in + let const = if needs_cast t const_t then mk_cast t const else const in + + let arg = mk_local nullable_var pos in + let arg = if needs_cast t nullable_var.v_type then mk_cast t arg else arg in + + { + eexpr = TIf( + { eexpr = TBinop(Ast.OpEq, mk_local nullable_var pos, null nullable_var.v_type pos); etype = basic.tbool; epos = pos }, + const, + Some(arg) + ); + etype = t; + epos = pos; + } + + let add_opt gen block pos (var,opt) = + match opt with + | None | Some TNull -> (var,opt) + | Some (TString str) -> + block := Codegen.set_default gen.gcon var (TString str) pos :: !block; + (var, opt) + | Some const -> + let basic = gen.gcon.basic in + let nullable_var = mk_temp gen var.v_name (basic.tnull var.v_type) in + let orig_name = var.v_name in + var.v_name <- nullable_var.v_name; + nullable_var.v_name <- orig_name; + (* var v = (temp_var == null) ? const : cast temp_var; *) + block := + { + eexpr = TVar(var, Some(gen_check basic var.v_type nullable_var const pos)); + etype = basic.tvoid; + epos = pos; + } :: !block; + (nullable_var, opt) + + let rec change_func gen cf = + List.iter (change_func gen) cf.cf_overloads; + let is_ctor = cf.cf_name = "new" in + let basic = gen.gcon.basic in + match cf.cf_kind, follow cf.cf_type with + | Var _, _ | Method MethDynamic, _ -> () + | _, TFun(args, ret) -> + let found = ref false in + let args = ref (List.map (fun (n,opt,t) -> + (n,opt, if opt then (found := true; basic.tnull t) else t) + ) args) in + (match !found, cf.cf_expr with + | true, Some ({ eexpr = TFunction tf } as texpr) -> + let block = ref [] in + let tf_args = List.map (add_opt gen block tf.tf_expr.epos) tf.tf_args in + let arg_assoc = List.map2 (fun (v,o) (v2,_) -> v,(v2,o) ) tf.tf_args tf_args in + let rec extract_super e = match e.eexpr with + | TBlock(({ eexpr = TCall({ eexpr = TConst TSuper }, _) } as e2) :: tl) -> + e2, tl + | TBlock(hd :: tl) -> + let e2, tl2 = extract_super hd in + e2, tl2 @ tl + | _ -> raise Not_found + in + let block = try + if not is_ctor then raise Not_found; + (* issue #2570 *) + (* check if the class really needs the super as the first statement - + just to make sure we don't inadvertently break any existing code *) + let rec check cl = + if not (is_hxgen (TClassDecl cl)) then + () + else match cl.cl_super with + | None -> + raise Not_found + | Some (cl,_) -> + check cl + in + (match gen.gcurrent_class with + | Some cl -> check cl + | _ -> ()); + let super, tl = extract_super tf.tf_expr in + (match super.eexpr with + | TCall({ eexpr = TConst TSuper } as e1, args) -> + (* any super argument will be replaced by an inlined version of the check *) + let found = ref false in + let rec replace_args e = match e.eexpr with + | TLocal(v) -> (try + let v2,o = List.assq v arg_assoc in + let o = match o with + | None -> raise Not_found + | Some o -> o + in + found := true; + gen_check gen.gcon.basic v.v_type v2 o e.epos + with | Not_found -> e) + | _ -> Type.map_expr replace_args e + 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) + with | Not_found -> + Type.concat { tf.tf_expr with eexpr = TBlock(!block); etype = basic.tvoid } tf.tf_expr + in + + args := fun_args tf_args; + cf.cf_expr <- Some( {texpr with eexpr = TFunction( { tf with + tf_args = tf_args; + tf_expr = block + } ); etype = TFun(!args, ret) } ); + cf.cf_type <- TFun(!args, ret) + + | _ -> () + ); + (if !found then cf.cf_type <- TFun(!args, ret)) + | _, _ -> assert false + + let traverse gen = + let run md = match md with + | TClassDecl cl -> + List.iter (change_func gen) cl.cl_ordered_fields; + List.iter (change_func gen) cl.cl_ordered_statics; + (match cl.cl_constructor with | None -> () | Some cf -> change_func gen cf); + md + | _ -> md + in + run + + let configure gen (mapping_func:module_type->module_type) = + let map md = Some(mapping_func md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9693,15 +10649,15 @@ end;; (* - This module filter will take care of sanitizing interfaces for targets that do not support - variables declaration in interfaces. By now this will mean that if anything is typed as the interface, - and a variable access is made, a FNotFound will be returned for the field_access, so - the field will be only accessible by reflection. - Speed-wise, ideally it would be best to create getProp/setProp functions in this case and change - the AST to call them when accessing by interface. (TODO) - But right now it will be accessed by reflection. + This module filter will take care of sanitizing interfaces for targets that do not support + variables declaration in interfaces. By now this will mean that if anything is typed as the interface, + and a variable access is made, a FNotFound will be returned for the field_access, so + the field will be only accessible by reflection. + Speed-wise, ideally it would be best to create getProp/setProp functions in this case and change + the AST to call them when accessing by interface. (TODO) + But right now it will be accessed by reflection. - dependencies: + dependencies: *) @@ -9709,54 +10665,112 @@ end;; module InterfaceVarsDeleteModf = struct - let name = "interface_vars" - - let priority = solve_deps name [] - - let run gen = - let run md = match md with - | TClassDecl ( { cl_interface = true } as cl ) -> - let to_add = ref [] in - let fields = List.filter (fun cf -> - match cf.cf_kind with - | Var vkind -> - (match vkind.v_read with - | AccCall -> - let newcf = mk_class_field ("get_" ^ cf.cf_name) (TFun([],cf.cf_type)) true cf.cf_pos (Method MethNormal) [] in - to_add := newcf :: !to_add; - | _ -> () - ); - (match vkind.v_write with - | AccCall -> - let newcf = mk_class_field ("set_" ^ cf.cf_name) (TFun(["val",false,cf.cf_type],cf.cf_type)) true cf.cf_pos (Method MethNormal) [] in - to_add := newcf :: !to_add; - | _ -> () - ); - cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; - false - | _ -> true - ) cl.cl_ordered_fields in - - cl.cl_ordered_fields <- fields; - - List.iter (fun cf -> - if not (PMap.mem cf.cf_name cl.cl_fields) then begin - cl.cl_ordered_fields <- cf :: cl.cl_ordered_fields; - cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields - end - ) !to_add; - - md - | _ -> md - in - run - - let configure gen = - let run = run gen in - let map md = Some(run md) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + let name = "interface_vars" + + let priority = solve_deps name [] + + let run gen = + let run md = match md with + | TClassDecl ( { cl_interface = true } as cl ) -> + let to_add = ref [] in + let fields = List.filter (fun cf -> + match cf.cf_kind with + | Var _ when gen.gcon.platform = Cs && Meta.has Meta.Event cf.cf_meta -> + true + | Var vkind when not (Type.is_extern_field cf && Meta.has Meta.Property cf.cf_meta) -> + (match vkind.v_read with + | AccCall -> + let newcf = mk_class_field ("get_" ^ cf.cf_name) (TFun([],cf.cf_type)) true cf.cf_pos (Method MethNormal) [] in + to_add := newcf :: !to_add; + | _ -> () + ); + (match vkind.v_write with + | AccCall -> + let newcf = mk_class_field ("set_" ^ cf.cf_name) (TFun(["val",false,cf.cf_type],cf.cf_type)) true cf.cf_pos (Method MethNormal) [] in + to_add := newcf :: !to_add; + | _ -> () + ); + cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; + false + | Method MethDynamic -> + (* TODO OPTIMIZATION - add a `_dispatch` method to the interface which will call the dynamic function itself *) + cl.cl_fields <- PMap.remove cf.cf_name cl.cl_fields; + false + | _ -> true + ) cl.cl_ordered_fields in + + cl.cl_ordered_fields <- fields; + + List.iter (fun cf -> + match field_access gen (TInst(cl,List.map snd cl.cl_params)) cf.cf_name with + | FNotFound | FDynamicField _ -> + cl.cl_ordered_fields <- cf :: cl.cl_ordered_fields; + cl.cl_fields <- PMap.add cf.cf_name cf cl.cl_fields + | _ -> () + ) !to_add; + + md + | _ -> md + in + run + + let configure gen = + let run = run gen in + let map md = Some(run md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + + +end;; + +(* ******************************************* *) +(* InterfaceProps *) +(* ******************************************* *) + +(* + + This module filter will go through all declared properties, and see if they are conforming to a native interface. + If they are, it will add Meta.Property to it + + dependencies: +*) +module InterfaceProps = +struct + let name = "interface_props" + + let priority = solve_deps name [] + + let run gen = + let run md = match md with + | TClassDecl ( { cl_interface = false; cl_extern = false } as cl ) -> + let vars = List.fold_left (fun acc (iface,_) -> + if Meta.has Meta.CsNative iface.cl_meta then + List.filter (fun cf -> match cf.cf_kind with + | Var { v_read = AccCall } | Var { v_write = AccCall } -> + true + | _ -> false + ) iface.cl_ordered_fields @ acc + else + acc + ) [] cl.cl_implements in + let vars = List.map (fun cf -> cf.cf_name) vars in + if vars <> [] then + List.iter (fun cf -> match cf.cf_kind with + | Var { v_read = AccCall } | Var { v_write = AccCall } when List.mem cf.cf_name vars -> + cf.cf_meta <- (Meta.Property, [], Ast.null_pos) :: cf.cf_meta + | _ -> () + ) cl.cl_ordered_fields; + + md + | _ -> md + in + run + + let configure gen = + let run = run gen in + let map md = Some(run md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map end;; (* ******************************************* *) @@ -9765,47 +10779,59 @@ end;; (* - On targets that support int division, this module will force a float division to be performed, - so compatibility with current haxe targets is ensured. - If catch_int_div is set to true, though, it will look for casts to int or use of Std.int() to optimize - this kind of operation. + On targets that support int division, this module will force a float division to be performed, + so compatibility with current haxe targets is ensured. + If catch_int_div is set to true, though, it will look for casts to int or use of Std.int() to optimize + this kind of operation. - dependencies: - since it depends on nothing, but many modules might generate division expressions, - it will be one of the last modules to run + dependencies: + since it depends on nothing, but many modules might generate division expressions, + it will be one of the last modules to run *) module IntDivisionSynf = struct - let name = "int_division_synf" - - let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority ] - - let is_int = like_int - - let default_implementation gen catch_int_div = - let basic = gen.gcon.basic in - let rec run e = - match e.eexpr with - | TBinop((Ast.OpDiv as op), e1, e2) when is_int e1.etype && is_int e2.etype -> - { e with eexpr = TBinop(op, mk_cast basic.tfloat (run e1), run e2) } - | TCall( - { eexpr = TField(_, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) }, - [ ({ eexpr = TBinop((Ast.OpDiv as op), e1, e2) } as ebinop ) ] - ) when catch_int_div && is_int e1.etype && is_int e2.etype -> - { ebinop with eexpr = TBinop(op, run e1, run e2); etype = basic.tint } - | TCast( ({ eexpr = TBinop((Ast.OpDiv as op), e1, e2) } as ebinop ), _ ) - | TCast( ({ eexpr = TBinop(( (Ast.OpAssignOp Ast.OpDiv) as op), e1, e2) } as ebinop ), _ ) when catch_int_div && is_int e1.etype && is_int e2.etype && is_int e.etype -> - { ebinop with eexpr = TBinop(op, run e1, run e2); etype = basic.tint } - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "int_division_synf" + + let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority ] + + let is_int = like_int + + let is_exactly_int t = match follow t with + | TAbstract ({ a_path=[],"Int" }, []) -> true + | _ -> false + + let default_implementation gen catch_int_div = + let basic = gen.gcon.basic in + let rec run e = + match e.eexpr with + | TBinop((Ast.OpDiv as op), e1, e2) when is_int e1.etype && is_int e2.etype -> + { e with eexpr = TBinop(op, mk_cast basic.tfloat (run e1), run e2) } + | TCall( + { eexpr = TField(_, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) }, + [ ({ eexpr = TBinop((Ast.OpDiv as op), e1, e2) } as ebinop ) ] + ) when catch_int_div && is_int e1.etype && is_int e2.etype -> + let e = { ebinop with eexpr = TBinop(op, run e1, run e2); etype = basic.tint } in + if not (is_exactly_int e1.etype && is_exactly_int e2.etype) then + mk_cast basic.tint e + else + e + | TCast( ({ eexpr = TBinop((Ast.OpDiv as op), e1, e2) } as ebinop ), _ ) + | TCast( ({ eexpr = TBinop(( (Ast.OpAssignOp Ast.OpDiv) as op), e1, e2) } as ebinop ), _ ) when catch_int_div && is_int e1.etype && is_int e2.etype && is_int e.etype -> + let ret = { ebinop with eexpr = TBinop(op, run e1, run e2); etype = e.etype } in + if not (is_exactly_int e1.etype && is_exactly_int e2.etype) then + mk_cast e.etype ret + else + e + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9815,57 +10841,57 @@ end;; (* - This module will take care of simplifying unnecessary casts, specially those made by the compiler - when inlining. Right now, it will only take care of casts used as a statement, which are always useless; - TODO: Take care of more cases, e.g. when the to and from types are the same + This module will take care of simplifying unnecessary casts, specially those made by the compiler + when inlining. Right now, it will only take care of casts used as a statement, which are always useless; + TODO: Take care of more cases, e.g. when the to and from types are the same - dependencies: - This must run after CastDetection, but before ExpressionUnwrap + dependencies: + This must run after CastDetection, but before ExpressionUnwrap *) module UnnecessaryCastsRemoval = struct - let name = "casts_removal" - - let priority = solve_deps name [DAfter CastDetect.priority; DBefore ExpressionUnwrap.priority] - - let rec take_off_cast run e = - match e.eexpr with - | TCast (c, _) -> - take_off_cast run c - | _ -> run e - - let default_implementation gen = - let rec traverse e = - match e.eexpr with - | TBlock bl -> - let bl = List.map (fun e -> - take_off_cast traverse e - ) bl in - { e with eexpr = TBlock bl } - | TTry (block, catches) -> - { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) } - | TMatch (cond,ep,il_vol_e_l,default) -> - { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } - | TSwitch (cond,el_e_l, default) -> - { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) } - | TWhile (cond,block,flag) -> - {e with eexpr = TWhile(cond,traverse (mk_block block), flag) } - | TIf (cond, eif, eelse) -> - { e with eexpr = TIf(cond, traverse (mk_block eif), Option.map (fun e -> traverse (mk_block e)) eelse) } - | TFor (v,it,block) -> - { e with eexpr = TFor(v,it, traverse (mk_block block)) } - | TFunction (tfunc) -> - { e with eexpr = TFunction({ tfunc with tf_expr = traverse (mk_block tfunc.tf_expr) }) } - | _ -> e (* if expression doesn't have a block, we will exit *) - in - traverse - - let configure gen = - let map e = Some(default_implementation gen e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "casts_removal" + + let priority = solve_deps name [DAfter CastDetect.priority; DBefore ExpressionUnwrap.priority] + + let rec take_off_cast run e = + match e.eexpr with + | TCast (c, _) -> + take_off_cast run c + | _ -> run e + + let default_implementation gen = + let rec traverse e = + match e.eexpr with + | TBlock bl -> + let bl = List.map (fun e -> + take_off_cast traverse e + ) bl in + { e with eexpr = TBlock bl } + | TTry (block, catches) -> + { e with eexpr = TTry(traverse (mk_block block), List.map (fun (v,block) -> (v, traverse (mk_block block))) catches) } +(* | TMatch (cond,ep,il_vol_e_l,default) -> + { e with eexpr = TMatch(cond,ep,List.map (fun (il,vol,e) -> (il,vol,traverse (mk_block e))) il_vol_e_l, Option.map (fun e -> traverse (mk_block e)) default) } *) + | TSwitch (cond,el_e_l, default) -> + { e with eexpr = TSwitch(cond, List.map (fun (el,e) -> (el, traverse (mk_block e))) el_e_l, Option.map (fun e -> traverse (mk_block e)) default) } + | TWhile (cond,block,flag) -> + {e with eexpr = TWhile(cond,traverse (mk_block block), flag) } + | TIf (cond, eif, eelse) -> + { e with eexpr = TIf(cond, traverse (mk_block eif), Option.map (fun e -> traverse (mk_block e)) eelse) } + | TFor (v,it,block) -> + { e with eexpr = TFor(v,it, traverse (mk_block block)) } + | TFunction (tfunc) -> + { e with eexpr = TFunction({ tfunc with tf_expr = traverse (mk_block tfunc.tf_expr) }) } + | _ -> e (* if expression doesn't have a block, we will exit *) + in + traverse + + let configure gen = + let map e = Some(default_implementation gen e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9875,45 +10901,45 @@ end;; (* - When DCE is on, sometimes a field is marked as override when it - really doesn't override anything. This module filter will take care of this. + When DCE is on, sometimes a field is marked as override when it + really doesn't override anything. This module filter will take care of this. - dependencies: - No dependencies + dependencies: + No dependencies *) module OverrideFix = struct - let name = "override_fix" - - let priority = solve_deps name [] - - let default_implementation gen = - let rec run e = - match e.eexpr with - | _ -> Type.map_expr run e - in - run - - let configure gen = - let map md = - match md with - | TClassDecl cl -> - cl.cl_overrides <- List.filter (fun s -> - let rec loop cl = - match cl.cl_super with - | Some (cl,_) when PMap.mem s.cf_name cl.cl_fields -> true - | Some (cl,_) -> loop cl - | None -> false - in - loop cl - ) cl.cl_overrides; - Some md - | _ -> Some md - in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + let name = "override_fix" + + let priority = solve_deps name [] + + let default_implementation gen = + let rec run e = + match e.eexpr with + | _ -> Type.map_expr run e + in + run + + let configure gen = + let map md = + match md with + | TClassDecl cl -> + cl.cl_overrides <- List.filter (fun s -> + let rec loop cl = + match cl.cl_super with + | Some (cl,_) when PMap.mem s.cf_name cl.cl_fields -> true + | Some (cl,_) -> loop cl + | None -> false + in + loop cl + ) cl.cl_overrides; + Some md + | _ -> Some md + in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9923,39 +10949,39 @@ end;; (* - This module filter will map the compiler created classes from abstract - implementations to valid haxe code, as needed by gencommon + This module filter will map the compiler created classes from abstract + implementations to valid haxe code, as needed by gencommon - dependencies: - No dependencies + dependencies: + No dependencies *) module AbstractImplementationFix = struct - let name = "abstract_implementation_fix" - - let priority = solve_deps name [] - - let default_implementation gen = - let rec run md = - match md with - | TClassDecl ({ cl_kind = KAbstractImpl a } as c) -> - List.iter (function - | cf when Meta.has Meta.Impl cf.cf_meta -> - (* add type parameters to all implementation functions *) - cf.cf_params <- cf.cf_params @ a.a_types - | _ -> () - ) c.cl_ordered_statics; - Some md - | _ -> Some md - in - run - - let configure gen = - let map = default_implementation gen in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + let name = "abstract_implementation_fix" + + let priority = solve_deps name [] + + let default_implementation gen = + let rec run md = + match md with + | TClassDecl ({ cl_kind = KAbstractImpl a } as c) -> + List.iter (function + | cf when Meta.has Meta.Impl cf.cf_meta -> + (* add type parameters to all implementation functions *) + cf.cf_params <- cf.cf_params @ a.a_params + | _ -> () + ) c.cl_ordered_statics; + Some md + | _ -> Some md + in + run + + let configure gen = + let map = default_implementation gen in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -9965,284 +10991,355 @@ end;; (* - Covariant return types, contravariant function arguments and applied type parameters may change - in a way that expected implementations / overrides aren't recognized as such. - This filter will fix that. + Covariant return types, contravariant function arguments and applied type parameters may change + in a way that expected implementations / overrides aren't recognized as such. + This filter will fix that. - dependencies: - FixOverrides expects that the target platform is able to deal with overloaded functions - It must run after DefaultArguments, otherwise code added by the default arguments may be invalid + dependencies: + FixOverrides expects that the target platform is able to deal with overloaded functions + It must run after DefaultArguments, otherwise code added by the default arguments may be invalid *) module FixOverrides = struct - let name = "fix_overrides" - - let priority = solve_deps name [DAfter DefaultArguments.priority] - - (* - if the platform allows explicit interface implementation (C#), - specify a explicit_fn_name function (tclass->string->string) - Otherwise, it expects the platform to be able to handle covariant return types - *) - let run ~explicit_fn_name gen = - let implement_explicitly = is_some explicit_fn_name in - let run md = match md with - | TClassDecl ( { cl_interface = true; cl_extern = false } as c ) -> - (* overrides can be removed from interfaces *) - c.cl_ordered_fields <- List.filter (fun f -> - try - if Meta.has Meta.Overload f.cf_meta then raise Not_found; - let f2 = Codegen.find_field c f in - if f2 == f then raise Not_found; - c.cl_fields <- PMap.remove f.cf_name c.cl_fields; - false; - with Not_found -> - true - ) c.cl_ordered_fields; - md - | TClassDecl({ cl_extern = false } as c) -> - let this = { eexpr = TConst TThis; etype = TInst(c,List.map snd c.cl_types); epos = c.cl_pos } in - (* look through all interfaces, and try to find a type that applies exactly *) - let rec loop_iface (iface:tclass) itl = - List.iter (fun (s,stl) -> loop_iface s (List.map (apply_params iface.cl_types itl) stl)) iface.cl_implements; - let real_itl = gen.greal_type_param (TClassDecl iface) itl in - let rec loop_f f = - List.iter loop_f f.cf_overloads; - let ftype = apply_params iface.cl_types itl f.cf_type in - let real_ftype = get_real_fun gen (apply_params iface.cl_types real_itl f.cf_type) in - replace_mono real_ftype; - let overloads = Typeload.get_overloads c f.cf_name in - try - let t2, f2 = - match overloads with - | (_, cf) :: _ when Meta.has Meta.Overload cf.cf_meta -> (* overloaded function *) - (* try to find exact function *) - List.find (fun (t,f2) -> - Typeload.same_overload_args ftype t f f2 - ) overloads - | _ :: _ -> - (match field_access gen (TInst(c, List.map snd c.cl_types)) f.cf_name with - | FClassField(_,_,_,f2,false,t,_) -> t,f2 (* if it's not an overload, all functions should have the same signature *) - | _ -> raise Not_found) - | [] -> raise Not_found - in - replace_mono t2; - (* if we find a function with the exact type of real_ftype, it means this interface has already been taken care of *) - if not (type_iseq (get_real_fun gen (apply_params f2.cf_params (List.map snd f.cf_params) t2)) real_ftype) then begin - (match f.cf_kind with | Method (MethNormal | MethInline) -> () | _ -> raise Not_found); - let t2 = get_real_fun gen t2 in - if List.length f.cf_params <> List.length f2.cf_params then raise Not_found; - replace_mono t2; - match follow (apply_params f2.cf_params (List.map snd f.cf_params) t2), follow real_ftype with - | TFun(a1,r1), TFun(a2,r2) when not implement_explicitly && not (type_iseq r1 r2) && Typeload.same_overload_args real_ftype t2 f f2 -> - (* different return types are the trickiest cases to deal with *) - (* check for covariant return type *) - let is_covariant = match follow r1, follow r2 with - | _, TDynamic _ -> true - | r1, r2 -> try - unify r1 r2; - true - with | Unify_error _ -> false - in - (* we only have to worry about non-covariant issues *) - if not is_covariant then begin - (* 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 - in - f2.cf_type <- TFun(args,newr); - (match f2.cf_expr with - | Some ({ eexpr = TFunction tf } as e) -> - f2.cf_expr <- Some { e with eexpr = TFunction { tf with tf_type = newr } } - | _ -> ()) - end - | TFun(a1,r1), TFun(a2,r2) -> - (* just implement a function that will call the main one *) - let name, is_explicit = match explicit_fn_name with - | Some fn when not (type_iseq r1 r2) && Typeload.same_overload_args real_ftype t2 f f2 -> - fn iface itl f.cf_name, true - | _ -> f.cf_name, false - in - let p = f2.cf_pos in - let newf = mk_class_field name real_ftype true f.cf_pos (Method MethNormal) f.cf_params in - let vars = List.map (fun (n,_,t) -> alloc_var n t) a2 in - - let args = List.map2 (fun v (_,_,t) -> mk_cast t (mk_local v f2.cf_pos)) vars a1 in - let field = { eexpr = TField(this, FInstance(c,f2)); etype = TFun(a1,r1); epos = p } in - let call = { eexpr = TCall(field, args); etype = r1; epos = p } in - (* let call = gen.gparam_func_call call field (List.map snd f.cf_params) args in *) - let is_void = is_void r2 in - - newf.cf_expr <- Some { - eexpr = TFunction({ - tf_args = List.map (fun v -> v,None) vars; - tf_type = r2; - tf_expr = (if is_void then call else { - eexpr = TReturn (Some (mk_cast r2 call)); - etype = r2; - epos = p - }) - }); - etype = real_ftype; - epos = p; - }; - (* delayed: add to class *) - let delay () = - try - let fm = PMap.find f.cf_name c.cl_fields in - fm.cf_overloads <- newf :: fm.cf_overloads - with | Not_found -> - c.cl_fields <- PMap.add f.cf_name newf c.cl_fields; - c.cl_ordered_fields <- newf :: c.cl_ordered_fields - in - (* gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended *) - delay(); - | _ -> assert false - end - with | Not_found -> () - in - List.iter loop_f iface.cl_ordered_fields - in - List.iter (fun (iface,itl) -> loop_iface iface itl) c.cl_implements; - (* now go through all overrides, *) - let rec check_f f = - (* find the first declared field *) - let is_overload = Meta.has Meta.Overload f.cf_meta in - let decl = if is_overload then - find_first_declared_field gen c ~exact_field:f f.cf_name - else - find_first_declared_field gen c f.cf_name - in - match decl with - | Some(f2,actual_t,_,t,declared_cl,_,_) - when not (Typeload.same_overload_args actual_t (get_real_fun gen f.cf_type) f2 f) -> - if Meta.has Meta.Overload f.cf_meta then begin - (* if it is overload, create another field with the requested type *) - let f3 = mk_class_field f.cf_name t f.cf_public f.cf_pos f.cf_kind f.cf_params in - let p = f.cf_pos in - let old_args, old_ret = get_fun f.cf_type in - let args, ret = get_fun t in - let tf_args = List.map (fun (n,o,t) -> alloc_var n t, None) args in - f3.cf_expr <- Some { - eexpr = TFunction({ - tf_args = tf_args; - tf_type = ret; - tf_expr = mk_block (mk_return (mk_cast ret { - eexpr = TCall( - { - eexpr = TField( - { eexpr = TConst TThis; etype = TInst(c, List.map snd c.cl_types); epos = p }, - FInstance(c,f)); - etype = f.cf_type; - epos = p - }, - List.map2 (fun (v,_) (_,_,t) -> mk_cast t (mk_local v p)) tf_args old_args); - etype = old_ret; - epos = p - })) - }); - etype = t; - epos = p; - }; - gen.gafter_filters_ended <- ((fun () -> - f.cf_overloads <- f3 :: f.cf_overloads; - ) :: gen.gafter_filters_ended); - f3 - end else begin match f.cf_expr with - | Some({ eexpr = TFunction(tf) } as e) -> - (* if it's not overload, just cast the vars *) - let actual_args, _ = get_fun (get_real_fun gen actual_t) in - let new_args, vardecl = List.fold_left2 (fun (args,vdecl) (v,_) (_,_,t) -> - if not (type_iseq (gen.greal_type v.v_type) (gen.greal_type t)) then begin - let new_var = mk_temp gen v.v_name t in - (new_var,None) :: args, (v, Some(mk_cast v.v_type (mk_local new_var f.cf_pos))) :: vdecl - end else - (v,None) :: args, vdecl - ) ([],[]) tf.tf_args actual_args in - if vardecl <> [] then - f.cf_expr <- Some({ e with - eexpr = TFunction({ tf with - tf_args = List.rev new_args; - tf_expr = Codegen.concat { eexpr = TVars(vardecl); etype = gen.gcon.basic.tvoid; epos = e.epos } tf.tf_expr - }); - }); - f - | _ -> f - end - | _ -> f - in - if not c.cl_extern then - c.cl_overrides <- List.map (fun f -> check_f f) c.cl_overrides; - md - | _ -> md - in - run - - let configure ?explicit_fn_name gen = - let delay () = - Hashtbl.clear gen.greal_field_types - in - gen.gafter_mod_filters_ended <- delay :: gen.gafter_mod_filters_ended; - let run = run ~explicit_fn_name:explicit_fn_name gen in - let map md = Some(run md) in - gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + let name = "fix_overrides" + + let priority = solve_deps name [DAfter DefaultArguments.priority] + + (* + if the platform allows explicit interface implementation (C#), + specify a explicit_fn_name function (tclass->string->string) + Otherwise, it expects the platform to be able to handle covariant return types + *) + let run ~explicit_fn_name ~get_vmtype gen = + let implement_explicitly = is_some explicit_fn_name in + let run md = match md with + | TClassDecl ( { cl_interface = true; cl_extern = false } as c ) -> + (* overrides can be removed from interfaces *) + c.cl_ordered_fields <- List.filter (fun f -> + try + if Meta.has Meta.Overload f.cf_meta then raise Not_found; + let f2 = Codegen.find_field gen.gcon c f in + if f2 == f then raise Not_found; + c.cl_fields <- PMap.remove f.cf_name c.cl_fields; + false; + with Not_found -> + true + ) c.cl_ordered_fields; + md + | TClassDecl({ cl_extern = false } as c) -> + let this = { eexpr = TConst TThis; etype = TInst(c,List.map snd c.cl_params); epos = c.cl_pos } in + (* look through all interfaces, and try to find a type that applies exactly *) + let rec loop_iface (iface:tclass) itl = + List.iter (fun (s,stl) -> loop_iface s (List.map (apply_params iface.cl_params itl) stl)) iface.cl_implements; + let real_itl = gen.greal_type_param (TClassDecl iface) itl in + let rec loop_f f = + List.iter loop_f f.cf_overloads; + let ftype = apply_params iface.cl_params itl f.cf_type in + let real_ftype = get_real_fun gen (apply_params iface.cl_params real_itl f.cf_type) in + replace_mono real_ftype; + let overloads = Typeload.get_overloads c f.cf_name in + try + let t2, f2 = + match overloads with + | (_, cf) :: _ when Meta.has Meta.Overload cf.cf_meta -> (* overloaded function *) + (* try to find exact function *) + List.find (fun (t,f2) -> + Typeload.same_overload_args ~get_vmtype ftype t f f2 + ) overloads + | _ :: _ -> + (match field_access gen (TInst(c, List.map snd c.cl_params)) f.cf_name with + | FClassField(_,_,_,f2,false,t,_) -> t,f2 (* if it's not an overload, all functions should have the same signature *) + | _ -> raise Not_found) + | [] -> raise Not_found + in + replace_mono t2; + (* if we find a function with the exact type of real_ftype, it means this interface has already been taken care of *) + if not (type_iseq (get_real_fun gen (apply_params f2.cf_params (List.map snd f.cf_params) t2)) real_ftype) then begin + (match f.cf_kind with | Method (MethNormal | MethInline) -> () | _ -> raise Not_found); + let t2 = get_real_fun gen t2 in + if List.length f.cf_params <> List.length f2.cf_params then raise Not_found; + replace_mono t2; + match follow (apply_params f2.cf_params (List.map snd f.cf_params) t2), follow real_ftype with + | TFun(a1,r1), TFun(a2,r2) when not implement_explicitly && not (type_iseq r1 r2) && Typeload.same_overload_args ~get_vmtype real_ftype t2 f f2 -> + (* different return types are the trickiest cases to deal with *) + (* check for covariant return type *) + let is_covariant = match follow r1, follow r2 with + | _, TDynamic _ -> true + | r1, r2 -> try + unify r1 r2; + true + with | Unify_error _ -> false + in + (* we only have to worry about non-covariant issues *) + if not is_covariant then begin + (* 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 + in + f2.cf_type <- TFun(args,newr); + (match f2.cf_expr with + | Some ({ eexpr = TFunction tf } as e) -> + f2.cf_expr <- Some { e with eexpr = TFunction { tf with tf_type = newr } } + | _ -> ()) + end + | TFun(a1,r1), TFun(a2,r2) -> + (* just implement a function that will call the main one *) + let name, is_explicit = match explicit_fn_name with + | Some fn when not (type_iseq r1 r2) && Typeload.same_overload_args ~get_vmtype real_ftype t2 f f2 -> + fn iface itl f.cf_name, true + | _ -> f.cf_name, false + in + let p = f2.cf_pos in + let newf = mk_class_field name real_ftype true f.cf_pos (Method MethNormal) f.cf_params in + let vars = List.map (fun (n,_,t) -> alloc_var n t) a2 in + + let args = List.map2 (fun v (_,_,t) -> mk_cast t (mk_local v f2.cf_pos)) vars a1 in + let field = { eexpr = TField(this, FInstance(c,List.map snd c.cl_params,f2)); etype = TFun(a1,r1); epos = p } in + let call = { eexpr = TCall(field, args); etype = r1; epos = p } in + (* let call = gen.gparam_func_call call field (List.map snd f.cf_params) args in *) + let is_void = is_void r2 in + + newf.cf_expr <- Some { + eexpr = TFunction({ + tf_args = List.map (fun v -> v,None) vars; + tf_type = r2; + tf_expr = (if is_void then call else { + eexpr = TReturn (Some (mk_cast r2 call)); + etype = r2; + epos = p + }) + }); + etype = real_ftype; + epos = p; + }; + (* delayed: add to class *) + let delay () = + try + let fm = PMap.find f.cf_name c.cl_fields in + fm.cf_overloads <- newf :: fm.cf_overloads + with | Not_found -> + c.cl_fields <- PMap.add f.cf_name newf c.cl_fields; + c.cl_ordered_fields <- newf :: c.cl_ordered_fields + in + (* gen.gafter_filters_ended <- delay :: gen.gafter_filters_ended *) + delay(); + | _ -> assert false + end + with | Not_found -> () + in + List.iter (fun f -> match f.cf_kind with | Var _ -> () | _ -> loop_f f) iface.cl_ordered_fields + in + List.iter (fun (iface,itl) -> loop_iface iface itl) c.cl_implements; + (* now go through all overrides, *) + let rec check_f f = + (* find the first declared field *) + let is_overload = Meta.has Meta.Overload f.cf_meta in + let decl = if is_overload then + find_first_declared_field gen c ~get_vmtype ~exact_field:f f.cf_name + else + find_first_declared_field gen c ~get_vmtype f.cf_name + in + match decl with + | Some(f2,actual_t,_,t,declared_cl,_,_) + when not (Typeload.same_overload_args ~get_vmtype actual_t (get_real_fun gen f.cf_type) f2 f) -> + if Meta.has Meta.Overload f.cf_meta then begin + (* if it is overload, create another field with the requested type *) + let f3 = mk_class_field f.cf_name t f.cf_public f.cf_pos f.cf_kind f.cf_params in + let p = f.cf_pos in + let old_args, old_ret = get_fun f.cf_type in + let args, ret = get_fun t in + let tf_args = List.map (fun (n,o,t) -> alloc_var n t, None) args in + let f3_mk_return = if is_void ret then (fun e -> e) else (fun e -> mk_return (mk_cast ret e)) in + f3.cf_expr <- Some { + eexpr = TFunction({ + tf_args = tf_args; + tf_type = ret; + tf_expr = mk_block (f3_mk_return { + eexpr = TCall( + { + eexpr = TField( + { eexpr = TConst TThis; etype = TInst(c, List.map snd c.cl_params); epos = p }, + FInstance(c,List.map snd c.cl_params,f)); + etype = f.cf_type; + epos = p + }, + List.map2 (fun (v,_) (_,_,t) -> mk_cast t (mk_local v p)) tf_args old_args); + etype = old_ret; + epos = p + }) + }); + etype = t; + epos = p; + }; + gen.gafter_filters_ended <- ((fun () -> + f.cf_overloads <- f3 :: f.cf_overloads; + ) :: gen.gafter_filters_ended); + f3 + end else begin match f.cf_expr with + | Some({ eexpr = TFunction(tf) } as e) -> + (* if it's not overload, just cast the vars *) + let actual_args, _ = get_fun (get_real_fun gen actual_t) in + let new_args, vardecl = List.fold_left2 (fun (args,vdecl) (v,_) (_,_,t) -> + if not (type_iseq (gen.greal_type v.v_type) (gen.greal_type t)) then begin + let new_var = mk_temp gen v.v_name t in + (new_var,None) :: args, (v, Some(mk_cast v.v_type (mk_local new_var f.cf_pos))) :: vdecl + end else + (v,None) :: args, vdecl + ) ([],[]) tf.tf_args actual_args in + + if vardecl <> [] then + f.cf_expr <- Some({ e with + eexpr = TFunction({ tf with + tf_args = List.rev new_args; + tf_expr = Type.concat { eexpr = TBlock(List.map (fun (v,ve) -> { eexpr = TVar(v,ve); etype = gen.gcon.basic.tvoid; epos = e.epos }) vardecl); etype = gen.gcon.basic.tvoid; epos = e.epos } tf.tf_expr + }); + }); + f + | _ -> f + end + | _ -> f + in + if not c.cl_extern then + c.cl_overrides <- List.map (fun f -> check_f f) c.cl_overrides; + md + | _ -> md + in + run + + let configure ?explicit_fn_name ~get_vmtype gen = + let delay () = + Hashtbl.clear gen.greal_field_types + in + gen.gafter_mod_filters_ended <- delay :: gen.gafter_mod_filters_ended; + let run = run ~explicit_fn_name ~get_vmtype gen in + let map md = Some(run md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map +end;; + +(* ******************************************* *) +(* Normalize *) +(* ******************************************* *) + +(* + + - Filters out enum constructor type parameters from the AST; See Issue #1796 + - Filters out monomorphs + - Filters out all non-whitelisted AST metadata + + dependencies: + No dependencies; but it still should be one of the first filters to run, + as it will help normalize the AST + +*) + +module Normalize = +struct + + let name = "normalize_type" + + let priority = max_dep + + let rec filter_param t = match t with + | TInst({ cl_kind = KTypeParameter _ } as c,_) when Meta.has Meta.EnumConstructorParam c.cl_meta -> + t_dynamic + | TMono r -> (match !r with + | None -> t_dynamic + | Some t -> filter_param t) + | TInst(_,[]) | TEnum(_,[]) | TType(_,[]) | TAbstract(_,[]) -> t + | TType(t,tl) -> TType(t,List.map filter_param tl) + | TInst(c,tl) -> TInst(c,List.map filter_param tl) + | TEnum(e,tl) -> TEnum(e,List.map filter_param tl) + | TAbstract({ a_path = (["haxe";"extern"],"Rest") } as a,tl) -> TAbstract(a, List.map filter_param tl) + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + filter_param (Abstract.get_underlying_type a tl) + | TAbstract(a,tl) -> TAbstract(a, List.map filter_param tl) + | TAnon a -> + TAnon { + a_fields = PMap.map (fun f -> { f with cf_type = filter_param f.cf_type }) a.a_fields; + a_status = a.a_status; + } + | TFun(args,ret) -> TFun(List.map (fun (n,o,t) -> (n,o,filter_param t)) args, filter_param ret) + | TDynamic _ -> t + | TLazy f -> filter_param (!f()) + + let default_implementation gen ~metas = + let rec run e = + match e.eexpr with + | TMeta(entry, e) when not (Hashtbl.mem metas entry) -> + run e + | _ -> + map_expr_type (fun e -> run e) filter_param (fun v -> v.v_type <- filter_param v.v_type; v) e + in + run + + let default_implementation_module gen ~metas = + let rec run md = match md with + | TClassDecl cl -> + let rec map cf = + cf.cf_type <- filter_param cf.cf_type; + List.iter map cf.cf_overloads + in + List.iter map cl.cl_ordered_fields; + List.iter map cl.cl_ordered_statics; + Option.may map cl.cl_constructor; + md + | _ -> md + in + run + + let configure gen ~metas = + let map e = Some(default_implementation gen e ~metas:metas) in + gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map; + let map md = Some(default_implementation_module gen ~metas md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map + end;; (* ******************************************* *) -(* NormalizeType *) +(* InterfaceMetas *) (* ******************************************* *) (* - - Filters out enum constructor type parameters from the AST; See Issue #1796 - - Filters out monomorphs + Deal with metadata on interfaces by taking it off from interface, and adding a new class with `_HxMeta` suffix - dependencies: - No dependencies; but it still should be one of the first filters to run, - as it will help normalize the AST + dependencies: + Must run before InitFunction *) -module NormalizeType = +module InterfaceMetas = struct - let name = "normalize_type" - - let priority = max_dep - - let rec filter_param t = match t with - | TInst({ cl_kind = KTypeParameter _ } as c,_) when Meta.has Meta.EnumConstructorParam c.cl_meta -> - t_dynamic - | TMono r -> (match !r with - | None -> t_dynamic - | Some t -> filter_param t) - | TInst(_,[]) | TEnum(_,[]) | TType(_,[]) | TAbstract(_,[]) -> t - | TType(t,tl) -> TType(t,List.map filter_param tl) - | TInst(c,tl) -> TInst(c,List.map filter_param tl) - | TEnum(e,tl) -> TEnum(e,List.map filter_param tl) - | TAbstract(a,tl) -> TAbstract(a, List.map filter_param tl) - | TAnon a -> - TAnon { - a_fields = PMap.map (fun f -> { f with cf_type = filter_param f.cf_type }) a.a_fields; - a_status = a.a_status; - } - | TFun(args,ret) -> TFun(List.map (fun (n,o,t) -> (n,o,filter_param t)) args, filter_param ret) - | TDynamic _ -> t - | TLazy f -> filter_param (!f()) - - let default_implementation gen = - let rec run e = - map_expr_type (fun e -> run e) filter_param (fun v -> v.v_type <- filter_param v.v_type; v) e - in - run - - let configure gen = - let map e = Some(default_implementation gen e) in - gen.gexpr_filters#add ~name:name ~priority:(PCustom priority) map + let name = "interface_metas" + + let priority = solve_deps name [ DBefore InitFunction.priority ] + + let traverse gen = + let run md = match md with + | TClassDecl ({ cl_interface = true; cl_ordered_statics = (_ :: _) } as cl) -> + cl.cl_ordered_statics <- []; + let path = fst cl.cl_path,snd cl.cl_path ^ "_HxMeta" in + (match Codegen.build_metadata gen.gcon (TClassDecl cl) with + | Some expr -> + let ncls = mk_class cl.cl_module path cl.cl_pos in + let cf = mk_class_field "__meta__" expr.etype false expr.epos (Var { v_read = AccNormal; v_write = AccNormal }) [] in + cf.cf_expr <- Some expr; + ncls.cl_statics <- PMap.add "__meta__" cf ncls.cl_statics; + ncls.cl_ordered_statics <- cf :: ncls.cl_ordered_statics; + gen.gadd_to_module (TClassDecl(ncls)) priority; + | _ -> ()) + | _ -> () + in + run + + let configure gen = + let map md = traverse gen md; Some(md) in + gen.gmodule_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -10253,9 +11350,9 @@ end;; (* - description + description - dependencies: + dependencies: *) @@ -10263,20 +11360,20 @@ end;; module Example = struct - let name = "example" + let name = "example" - let priority = solve_deps name [] + let priority = solve_deps name [] - let default_implementation gen = - let rec run e = - match e.eexpr with - | _ -> Type.map_expr run e - in - run + let default_implementation gen = + let rec run e = + match e.eexpr with + | _ -> Type.map_expr run e + in + run - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; *) diff --git a/gencpp.ml b/gencpp.ml index 366c0e370cdfae54b77728b520735d5fed045976..27f6a0f0bde067a4ac18704de9a9ab3ce984d46f 100644 --- a/gencpp.ml +++ b/gencpp.ml @@ -27,929 +27,1294 @@ open Common let unsupported p = error "This expression cannot be generated to Cpp" p (* - Code for generating source files. - It manages creating diretories, indents, blocks and only modifying files + Generators do not care about non-core-type abstracts, so let us follow them + away by default. +*) +let follow = Abstract.follow_with_abstracts + +(* + Code for generating source files. + It manages creating diretories, indents, blocks and only modifying files when the content changes. *) (* - A class_path is made from a package (array of strings) and a class name. - Join these together, inclding a separator. eg, "/" for includes : pack1/pack2/Name or "::" - for namespace "pack1::pack2::Name" + A class_path is made from a package (array of strings) and a class name. + Join these together, inclding a separator. eg, "/" for includes : pack1/pack2/Name or "::" + for namespace "pack1::pack2::Name" *) let join_class_path path separator = - let result = match fst path, snd path with - | [], s -> s - | el, s -> String.concat separator el ^ separator ^ s in - if (String.contains result '+') then begin - let idx = String.index result '+' in - (String.sub result 0 idx) ^ (String.sub result (idx+1) ((String.length result) - idx -1 ) ) - end else - result;; - - -class source_writer write_func close_func= - object(this) - val indent_str = "\t" - val mutable indent = "" - val mutable indents = [] - val mutable just_finished_block = false - method close = close_func(); () - method write x = write_func x; just_finished_block <- false - method indent_one = this#write indent_str - - method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents - method pop_indent = match indents with - | h::tail -> indents <- tail; indent <- String.concat "" indents - | [] -> indent <- "/*?*/"; - method write_i x = this#write (indent ^ x) - method get_indent = indent - method begin_block = this#write ("{\n"); this#push_indent - method end_block = this#pop_indent; this#write_i "}\n"; just_finished_block <- true - method end_block_line = this#pop_indent; this#write_i "}"; just_finished_block <- true - method terminate_line = this#write (if just_finished_block then "" else ";\n") - - - method add_include class_path = - this#write ("#ifndef INCLUDED_" ^ (join_class_path class_path "_") ^ "\n"); - this#write ("#include <" ^ (join_class_path class_path "/") ^ ".h>\n"); - this#write ("#endif\n") + let result = match fst path, snd path with + | [], s -> s + | el, s -> String.concat separator el ^ separator ^ s in + if (String.contains result '+') then begin + let idx = String.index result '+' in + (String.sub result 0 idx) ^ (String.sub result (idx+1) ((String.length result) - idx -1 ) ) + end else + result;; + + +(* The internal classes are implemented by the core hxcpp system, so the cpp + classes should not be generated *) +let is_internal_class = function + | ([],"Int") | ([],"Void") | ([],"String") | ([], "Null") | ([], "Float") + | ([],"Array") | ([], "Class") | ([], "Enum") | ([], "Bool") + | ([], "Dynamic") | ([], "ArrayAccess") | (["cpp"], "FastIterator") + | (["cpp"],"Pointer") | (["cpp"],"ConstPointer") + | (["cpp"],"RawPointer") | (["cpp"],"RawConstPointer") + | (["cpp"],"Function") -> true + | ([],"Math") | (["haxe";"io"], "Unsigned_char__") -> true + | (["cpp"],"Int8") | (["cpp"],"UInt8") | (["cpp"],"Char") + | (["cpp"],"Int16") | (["cpp"],"UInt16") + | (["cpp"],"Int32") | (["cpp"],"UInt32") + | (["cpp"],"Int64") | (["cpp"],"UInt64") + | (["cpp"],"Float32") | (["cpp"],"Float64") -> true + | _ -> false;; + +let get_include_prefix common_ctx with_slash = + try + (Common.defined_value common_ctx Define.IncludePrefix) ^ (if with_slash then "/" else "") + with + Not_found -> "" +;; + + +let should_prefix_include = function + | x when is_internal_class x -> false + | ([],"hxMath") -> true + | _ -> false;; + +class source_writer common_ctx write_func close_func = + object(this) + val indent_str = "\t" + val mutable indent = "" + val mutable indents = [] + val mutable just_finished_block = false + method close = close_func(); () + method write x = write_func x; just_finished_block <- false + method indent_one = this#write indent_str + + method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents + method pop_indent = match indents with + | h::tail -> indents <- tail; indent <- String.concat "" indents + | [] -> indent <- "/*?*/"; + method write_i x = this#write (indent ^ x) + method get_indent = indent + method begin_block = this#write ("{\n"); this#push_indent + method end_block = this#pop_indent; this#write_i "}\n"; just_finished_block <- true + method end_block_line = this#pop_indent; this#write_i "}"; just_finished_block <- true + method terminate_line = this#write (if just_finished_block then "" else ";\n") + + + method add_include class_path = + ( match class_path with + | (["@verbatim"],file) -> this#write ("#include \"" ^ file ^ "\"\n"); + | _ -> + let prefix = if should_prefix_include class_path then "" else get_include_prefix common_ctx true in + this#write ("#ifndef INCLUDED_" ^ (join_class_path class_path "_") ^ "\n"); + this#write ("#include <" ^ prefix ^ (join_class_path class_path "/") ^ ".h>\n"); + this#write ("#endif\n") + ) end;; -let file_source_writer filename = - let out_file = open_out filename in - new source_writer (output_string out_file) (fun ()-> close_out out_file);; +let file_source_writer common_ctx filename = + let out_file = open_out filename in + new source_writer common_ctx (output_string out_file) (fun ()-> close_out out_file);; let read_whole_file chan = - Std.input_all chan;; + Std.input_all chan;; (* The cached_source_writer will not write to the file if it has not changed, - thus allowing the makefile dependencies to work correctly *) -let cached_source_writer filename = - try - let in_file = open_in filename in - let old_contents = read_whole_file in_file in - close_in in_file; - let buffer = Buffer.create 0 in - let add_buf str = Buffer.add_string buffer str in - let close = fun () -> - let contents = Buffer.contents buffer in - if (not (contents=old_contents) ) then begin - let out_file = open_out filename in - output_string out_file contents; - close_out out_file; - end; - in - new source_writer (add_buf) (close); - with _ -> - file_source_writer filename;; - -let rec make_class_directories base dir_list = - ( match dir_list with - | [] -> () - | dir :: remaining -> - let path = match base with - | "" -> dir - | "/" -> "/" ^ dir - | _ -> base ^ "/" ^ dir in - if ( not ( (path="") || - ( ((String.length path)=2) && ((String.sub path 1 1)=":") ) ) ) then - if not (Sys.file_exists path) then - Unix.mkdir path 0o755; - make_class_directories (if (path="") then "/" else path) remaining - );; - - -let new_source_file base_dir sub_dir extension class_path = - make_class_directories base_dir ( sub_dir :: (fst class_path)); - cached_source_writer - ( base_dir ^ "/" ^ sub_dir ^ "/" ^ ( String.concat "/" (fst class_path) ) ^ "/" ^ - (snd class_path) ^ extension);; - - -let new_cpp_file base_dir = new_source_file base_dir "src" ".cpp";; - -let new_header_file base_dir = new_source_file base_dir "include" ".h";; - -let make_base_directory file = - make_class_directories "" ( ( Str.split_delim (Str.regexp "[\\/]+") file ) ); + thus allowing the makefile dependencies to work correctly *) +let cached_source_writer common_ctx filename = + try + let in_file = open_in filename in + let old_contents = read_whole_file in_file in + close_in in_file; + let buffer = Buffer.create 0 in + let add_buf str = Buffer.add_string buffer str in + let close = fun () -> + let contents = Buffer.contents buffer in + if (not (contents=old_contents) ) then begin + let out_file = open_out filename in + output_string out_file contents; + close_out out_file; + end; + in + new source_writer common_ctx (add_buf) (close); + with _ -> + file_source_writer common_ctx filename;; + +let make_class_directories = Common.mkdir_recursive;; + +let make_base_directory dir = + make_class_directories "" ( ( Str.split_delim (Str.regexp "[\\/]+") dir ) );; + +let new_source_file common_ctx base_dir sub_dir extension class_path = + let include_prefix = get_include_prefix common_ctx true in + let full_dir = + if (sub_dir="include") && (include_prefix<>"") then begin + let dir = match fst class_path with + | [] -> base_dir ^ "/include/" ^ (get_include_prefix common_ctx false) + | path -> base_dir ^ "/include/" ^ include_prefix ^ ( String.concat "/" path ) + in + make_base_directory dir; + dir + end else begin + make_class_directories base_dir ( sub_dir :: (fst class_path)); + base_dir ^ "/" ^ sub_dir ^ "/" ^ ( String.concat "/" (fst class_path) ) + end + in + cached_source_writer common_ctx (full_dir ^ "/" ^ ((snd class_path) ^ extension));; + + + +let source_file_extension common_ctx = + try + "." ^ (Common.defined_value common_ctx Define.FileExtension) + with + Not_found -> ".cpp" +;; + + +let new_cpp_file common_ctx base_dir = new_source_file common_ctx base_dir "src" (source_file_extension common_ctx);; + +let new_header_file common_ctx base_dir = + new_source_file common_ctx base_dir "include" ".h";; + (* CPP code generation context *) type context = { - mutable ctx_common : Common.context; - mutable ctx_output : string -> unit; - mutable ctx_dbgout : string -> unit; - mutable ctx_writer : source_writer; - mutable ctx_calling : bool; - mutable ctx_assigning : bool; - mutable ctx_return_from_block : bool; - mutable ctx_tcall_expand_args : bool; - (* This is for returning from the child nodes of TMatch, TSwitch && TTry *) - mutable ctx_return_from_internal_node : bool; - mutable ctx_debug : bool; - mutable ctx_debug_type : bool; - mutable ctx_real_this_ptr : bool; - mutable ctx_dynamic_this_ptr : bool; - mutable ctx_dump_src_pos : unit -> unit; - mutable ctx_dump_stack_line : bool; - mutable ctx_static_id_curr : int; - mutable ctx_static_id_used : int; - mutable ctx_static_id_depth : int; - mutable ctx_switch_id : int; - mutable ctx_class_name : string; - mutable ctx_class_super_name : string; - mutable ctx_local_function_args : (string,string) Hashtbl.t; - mutable ctx_local_return_block_args : (string,string) Hashtbl.t; - mutable ctx_class_member_types : (string,string) Hashtbl.t; - mutable ctx_file_info : (string,string) PMap.t ref; - mutable ctx_for_extern : bool; + mutable ctx_common : Common.context; + mutable ctx_output : string -> unit; + mutable ctx_dbgout : string -> unit; + mutable ctx_writer : source_writer; + mutable ctx_calling : bool; + mutable ctx_assigning : bool; + mutable ctx_return_from_block : bool; + mutable ctx_tcall_expand_args : bool; + (* This is for returning from the child nodes of TMatch, TSwitch && TTry *) + mutable ctx_return_from_internal_node : bool; + mutable ctx_debug_level : int; + mutable ctx_real_this_ptr : bool; + mutable ctx_real_void : bool; + mutable ctx_dynamic_this_ptr : bool; + mutable ctx_dump_src_pos : unit -> unit; + mutable ctx_static_id_curr : int; + mutable ctx_static_id_used : int; + mutable ctx_static_id_depth : int; + mutable ctx_switch_id : int; + mutable ctx_class_name : string; + mutable ctx_class_super_name : string; + mutable ctx_local_function_args : (string,string) Hashtbl.t; + mutable ctx_local_return_block_args : (string,string) Hashtbl.t; + mutable ctx_class_member_types : (string,string) Hashtbl.t; + mutable ctx_file_info : (string,string) PMap.t ref; + mutable ctx_for_extern : bool; } let new_context common_ctx writer debug file_info = - { - ctx_common = common_ctx; - ctx_writer = writer; - ctx_output = (writer#write); - ctx_dbgout = if debug then (writer#write) else (fun _ -> ()); - ctx_calling = false; - ctx_assigning = false; - ctx_debug = debug; - ctx_debug_type = debug; - ctx_dump_src_pos = (fun() -> ()); - ctx_dump_stack_line = true; - ctx_return_from_block = false; - ctx_tcall_expand_args = false; - ctx_return_from_internal_node = false; - ctx_real_this_ptr = true; - ctx_dynamic_this_ptr = false; - ctx_static_id_curr = 0; - ctx_static_id_used = 0; - ctx_static_id_depth = 0; - ctx_switch_id = 0; - ctx_class_name = ""; - ctx_class_super_name = ""; - ctx_local_function_args = Hashtbl.create 0; - ctx_local_return_block_args = Hashtbl.create 0; - ctx_class_member_types = Hashtbl.create 0; - ctx_file_info = file_info; - ctx_for_extern = false; - } +{ + ctx_common = common_ctx; + ctx_writer = writer; + ctx_output = (writer#write); + ctx_dbgout = if debug>1 then (writer#write) else (fun _ -> ()); + ctx_calling = false; + ctx_assigning = false; + ctx_debug_level = debug; + ctx_dump_src_pos = (fun() -> ()); + ctx_return_from_block = false; + ctx_tcall_expand_args = false; + ctx_return_from_internal_node = false; + ctx_real_this_ptr = true; + ctx_real_void = false; + ctx_dynamic_this_ptr = false; + ctx_static_id_curr = 0; + ctx_static_id_used = 0; + ctx_static_id_depth = 0; + ctx_switch_id = 0; + ctx_class_name = ""; + ctx_class_super_name = ""; + ctx_local_function_args = Hashtbl.create 0; + ctx_local_return_block_args = Hashtbl.create 0; + ctx_class_member_types = Hashtbl.create 0; + ctx_file_info = file_info; + ctx_for_extern = false; +} let new_extern_context common_ctx writer debug file_info = - let ctx = new_context common_ctx writer debug file_info in - ctx.ctx_for_extern <- true; - ctx + let ctx = new_context common_ctx writer debug file_info in + ctx.ctx_for_extern <- true; + ctx ;; -(* The internal classes are implemented by the core hxcpp system, so the cpp - classes should not be generated *) -let is_internal_class = function - | ([],"Int") | ([],"Void") | ([],"String") | ([], "Null") | ([], "Float") - | ([],"Array") | ([], "Class") | ([], "Enum") | ([], "Bool") - | ([], "Dynamic") | ([], "ArrayAccess") | (["cpp"], "FastIterator")-> true - | (["cpp"], "CppInt32__") | ([],"Math") | (["haxe";"io"], "Unsigned_char__") -> true - | _ -> false - - (* The internal header files are also defined in the hx/Object.h file, so you do - #include them separately. However, the Int32 and Math classes do have their - own header files (these are under the hxcpp tree) so these should be included *) + #include them separately. However, Math classes has its + own header file (under the hxcpp tree) so these should be included *) let include_class_header = function - | ([],"@Main") -> false - | (["cpp"], "CppInt32__") | ([],"Math") -> true - | path -> not ( is_internal_class path ) + | ([],"@Main") -> false + | ([],"Math") -> true + | path -> not ( is_internal_class path ) let is_cpp_class = function - | ("cpp"::_ , _) -> true - | ( [] , "Xml" ) -> true - | ( [] , "EReg" ) -> true - | ( ["haxe"] , "Log" ) -> true + | ("cpp"::_ , _) -> true + | ( [] , "EReg" ) -> true + | ( ["haxe"] , "Log" ) -> true | _ -> false;; let is_scalar typename = match typename with - | "int" | "unsigned int" | "signed int" - | "char" | "unsigned char" - | "short" | "unsigned short" - | "float" | "double" - | "bool" -> true - | _ -> false + | "int" | "unsigned int" | "signed int" + | "char" | "unsigned char" + | "short" | "unsigned short" + | "float" | "double" + | "bool" -> true + | _ -> false ;; let is_block exp = match exp.eexpr with | TBlock _ -> true | _ -> false ;; let to_block expression = - if is_block expression then expression else (mk_block expression);; + if is_block expression then expression else (mk_block expression);; (* todo - is this how it's done? *) let hash_keys hash = - let key_list = ref [] in - Hashtbl.iter (fun key value -> key_list := key :: !key_list ) hash; - !key_list;; + let key_list = ref [] in + Hashtbl.iter (fun key value -> key_list := key :: !key_list ) hash; + !key_list;; let pmap_keys pmap = - let key_list = ref [] in - PMap.iter (fun key value -> key_list := key :: !key_list ) pmap; - !key_list;; + let key_list = ref [] in + PMap.iter (fun key _ -> key_list := key :: !key_list ) pmap; + !key_list;; + +let pmap_values pmap = + let value_list = ref [] in + PMap.iter (fun _ value -> value_list := value :: !value_list ) pmap; + !value_list;; (* The Hashtbl structure seems a little odd - but here is a helper function *) let hash_iterate hash visitor = - let result = ref [] in - Hashtbl.iter (fun key value -> result := (visitor key value) :: !result ) hash; - !result + let result = ref [] in + Hashtbl.iter (fun key value -> result := (visitor key value) :: !result ) hash; + !result (* Convert function names that can't be written in c++ ... *) let keyword_remap name = - match name with - | "int" - | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum" - | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected" - | "register" | "short" | "signed" | "sizeof" | "template" | "typedef" - | "union" | "unsigned" | "void" | "volatile" | "or" | "and" | "xor" | "or_eq" | "not" - | "and_eq" | "xor_eq" | "typeof" | "stdin" | "stdout" | "stderr" - | "BIG_ENDIAN" | "LITTLE_ENDIAN" | "assert" | "NULL" | "wchar_t" | "EOF" - | "bool" | "const_cast" | "dynamic_cast" | "explicit" | "export" | "mutable" | "namespace" - | "reinterpret_cast" | "static_cast" | "typeid" | "typename" | "virtual" - | "_Complex" - | "struct" -> "_" ^ name - | "asm" -> "_asm_" - | x -> x + match name with + | "int" + | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum" + | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected" + | "register" | "short" | "signed" | "sizeof" | "template" | "typedef" + | "union" | "unsigned" | "void" | "volatile" | "or" | "and" | "xor" | "or_eq" | "not" + | "and_eq" | "xor_eq" | "typeof" | "stdin" | "stdout" | "stderr" | "system" + | "BIG_ENDIAN" | "LITTLE_ENDIAN" | "assert" | "NULL" | "wchar_t" | "EOF" + | "bool" | "const_cast" | "dynamic_cast" | "explicit" | "export" | "mutable" | "namespace" + | "reinterpret_cast" | "static_cast" | "typeid" | "typename" | "virtual" + | "_Complex" | "INFINITY" | "NAN" + | "INT_MIN" | "INT_MAX" | "INT8_MIN" | "INT8_MAX" | "UINT8_MAX" | "INT16_MIN" + | "INT16_MAX" | "UINT16_MAX" | "INT32_MIN" | "INT32_MAX" | "UINT32_MAX" + | "struct" -> "_" ^ name + | "asm" -> "_asm_" + | x -> x ;; let remap_class_path class_path = - (List.map keyword_remap (fst class_path)) , (snd class_path) + (List.map keyword_remap (fst class_path)) , (snd class_path) ;; let join_class_path_remap path separator = - join_class_path (remap_class_path path) separator + match join_class_path (remap_class_path path) separator with + | "Class" -> "hx::Class" + | x -> x ;; let get_meta_string meta key = - let rec loop = function - | [] -> "" - | (k,[Ast.EConst (Ast.String name),_],_) :: _ when k=key-> name - | _ :: l -> loop l - in - loop meta + let rec loop = function + | [] -> "" + | (k,[Ast.EConst (Ast.String name),_],_) :: _ when k=key-> name + | _ :: l -> loop l + in + loop meta +;; + + + +let get_meta_string_path meta key = + let rec loop = function + | [] -> "" + | (k,[Ast.EConst (Ast.String name),_], pos) :: _ when k=key-> + (try + if (String.sub name 0 2) = "./" then begin + let base = if (Filename.is_relative pos.pfile) then + Filename.concat (Sys.getcwd()) pos.pfile + else + pos.pfile + in + Gencommon.normalize (Filename.concat (Filename.dirname base) (String.sub name 2 ((String.length name) -2) )) + end else + name + with Invalid_argument _ -> name) + | _ :: l -> loop l + in + loop meta +;; + + +let get_meta_string_full_filename meta key = + let rec loop = function + | [] -> "" + | (k,_, pos) :: _ when k=key-> + if (Filename.is_relative pos.pfile) then + Gencommon.normalize (Filename.concat (Sys.getcwd()) pos.pfile) + else + pos.pfile + | _ :: l -> loop l + in + loop meta +;; + +let get_meta_string_full_dirname meta key = + let name = get_meta_string_full_filename meta key in + try + Gencommon.normalize (Filename.dirname name) + with Invalid_argument _ -> "" +;; + + +let get_field_access_meta field_access key = +match field_access with + | FInstance(_,_,class_field) + | FStatic(_,class_field) -> get_meta_string class_field.cf_meta key + | _ -> "" +;; + +let format_code code = + String.concat "\n" (ExtString.String.nsplit code "\r\n") + +let get_code meta key = + let code = get_meta_string meta key in + let magic_var = "${GENCPP_SOURCE_DIRECTORY}" in + let code = if ExtString.String.exists code magic_var then begin + let source_directory = get_meta_string_full_dirname meta key in + let _,code = ExtString.String.replace code magic_var source_directory in + code + end else + code + in + if (code<>"") then format_code code ^ "\n" else code ;; let has_meta_key meta key = List.exists (fun m -> match m with | (k,_,_) when k=key-> true | _ -> false ) meta ;; +let type_has_meta_key haxe_type key = + match follow haxe_type with + | TInst (klass,_) -> has_meta_key klass.cl_meta key + | TType (type_def,_) -> has_meta_key type_def.t_meta key + | TEnum (enum_def,_) -> has_meta_key enum_def.e_meta key + | _ -> false +;; -let get_code meta key = - let code = get_meta_string meta key in - if (code<>"") then code ^ "\n" else code +(* +let dump_meta meta = + List.iter (fun m -> match m with | (k,_,_) -> print_endline ((fst (MetaInfo.to_string k)) ^ "=" ^ (get_meta_string meta k) ) | _ -> () ) meta;; +*) + +let get_class_code class_def key = match class_def.cl_kind with + | KAbstractImpl abstract_def -> + let value = (get_code abstract_def.a_meta key) in + value + | _ -> get_code class_def.cl_meta key ;; + (* Add include to source code *) let add_include writer class_path = - writer#add_include class_path;; + writer#add_include class_path;; (* This gets the class include order correct. In the header files, we forward declare - the class types so the header file does not have any undefined variables. - In the cpp files, we include all the required header files, providing the actual - types for everything. This way there is no problem with circular class references. + the class types so the header file does not have any undefined variables. + In the cpp files, we include all the required header files, providing the actual + types for everything. This way there is no problem with circular class references. *) let gen_forward_decl writer class_path = - if ( class_path = (["cpp"],"CppInt32__")) then - writer#add_include class_path - else begin - let output = writer#write in - let name = fst (remap_class_path class_path) in - output ("HX_DECLARE_CLASS" ^ (string_of_int (List.length name ) ) ^ "("); - List.iter (fun package_part -> output (package_part ^ ",") ) name; - output ( (snd class_path) ^ ")\n") - end;; + begin + let output = writer#write in + match class_path with + | (["@verbatim"],file) -> writer#write ("#include <" ^ file ^ ">\n"); + | _ -> + let name = fst (remap_class_path class_path) in + output ("HX_DECLARE_CLASS" ^ (string_of_int (List.length name ) ) ^ "("); + List.iter (fun package_part -> output (package_part ^ ",") ) name; + output ( (snd class_path) ^ ")\n") +end;; let real_interfaces = List.filter (function (t,pl) -> - match t, pl with - | { cl_path = ["cpp";"rtti"],_ },[] -> false - | _ -> true + match t, pl with + | { cl_path = ["cpp";"rtti"],_ },[] -> false + | _ -> true );; let rec is_function_expr expr = match expr.eexpr with - | TParenthesis expr -> is_function_expr expr - | TCast (e,None) -> is_function_expr e + | TParenthesis expr | TMeta(_,expr) -> is_function_expr expr | TFunction _ -> true | _ -> false;; let is_var_field field = match field.cf_kind with | Var _ -> true - | Method MethDynamic -> true - | _ -> false + | Method MethDynamic -> true + | _ -> false ;; let rec has_rtti_interface c interface = - List.exists (function (t,pl) -> - (snd t.cl_path) = interface && (match fst t.cl_path with | ["cpp";"rtti"] -> true | _ -> false ) - ) c.cl_implements || - (match c.cl_super with None -> false | Some (c,_) -> has_rtti_interface c interface);; + List.exists (function (t,pl) -> + (snd t.cl_path) = interface && (match fst t.cl_path with | ["cpp";"rtti"] -> true | _ -> false ) + ) c.cl_implements || + (match c.cl_super with None -> false | Some (c,_) -> has_rtti_interface c interface);; let has_field_integer_lookup class_def = - has_rtti_interface class_def "FieldIntegerLookup";; + has_rtti_interface class_def "FieldIntegerLookup";; let has_field_integer_numeric_lookup class_def = - has_rtti_interface class_def "FieldNumericIntegerLookup";; + has_rtti_interface class_def "FieldNumericIntegerLookup";; (* Output required code to place contents in required namespace *) let gen_open_namespace output class_path = - List.iter (fun namespace -> output ("namespace " ^ namespace ^ "{\n")) (List.map keyword_remap (fst class_path));; + List.iter (fun namespace -> output ("namespace " ^ namespace ^ "{\n")) (List.map keyword_remap (fst class_path));; let gen_close_namespace output class_path = - List.iter - (fun namespace -> output ( "}" ^ " // end namespace " ^ namespace ^"\n")) - (fst class_path);; + List.iter + (fun namespace -> output ( "}" ^ " // end namespace " ^ namespace ^"\n")) + (fst class_path);; (* The basic types can have default values and are passesby value *) let is_numeric = function - | "Int" | "Bool" | "Float" | "::haxe::io::Unsigned_char__" | "unsigned char" -> true - | "int" | "bool" | "double" | "float" -> true - | _ -> false + | "Int" | "Bool" | "Float" | "::haxe::io::Unsigned_char__" | "unsigned char" -> true + | "::cpp::UInt8" | "::cpp::Int8" | "::cpp::Char" + | "::cpp::UInt16" | "::cpp::Int16" + | "::cpp::UInt32" | "::cpp::Int32" + | "::cpp::UInt64" | "::cpp::Int64" + | "::cpp::Float32" | "::cpp::Float64" + | "int" | "bool" | "double" | "float" -> true + | _ -> false -let cant_be_null type_string = - is_numeric type_string +let rec remove_parens expression = + match expression.eexpr with + | TParenthesis e -> remove_parens e + | TMeta(_,e) -> remove_parens e + | _ -> expression ;; -let is_object type_string = - not (is_numeric type_string || type_string="::String"); + +(* +let rec remove_parens_cast expression = + match expression.eexpr with + | TParenthesis e -> remove_parens_cast e + | TMeta(_,e) -> remove_parens_cast e + | TCast ( e,None) -> remove_parens_cast e + | _ -> expression +;; +*) +let is_interface_type t = + match follow t with + | TInst (klass,params) -> klass.cl_interface + | _ -> false +;; + + +let is_cpp_function_instance haxe_type = + match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_path with + | ["cpp"] , "Function" -> true + | _ -> false ) + | _ -> false + ;; + + +let is_cpp_function_class haxe_type = + match follow haxe_type with + | TType (klass,params) -> + (match klass.t_path with + | ["cpp"] , "Function" -> true + | _ -> false ) + | _ -> false + ;; + +let is_fromStaticFunction_call func = + match (remove_parens func).eexpr with + | TField (_,FStatic ({cl_path=["cpp"],"Function"},{cf_name="fromStaticFunction"} ) ) -> true + | _ -> false +;; + +let is_addressOf_call func = + match (remove_parens func).eexpr with + | TField (_,FStatic ({cl_path=["cpp"],"Pointer"},{cf_name="addressOf"} ) ) -> true + | _ -> false ;; +let is_lvalue var = + match (remove_parens var).eexpr with + | TLocal _ -> true + | TField (_,FStatic(_,field) ) | TField (_,FInstance(_,_,field) ) -> is_var_field field + | _ -> false +;; + + + +let is_pointer haxe_type includeRaw = + match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_path with + | ["cpp"] , "Pointer" + | ["cpp"] , "ConstPointer" + | ["cpp"] , "Function" -> true + | ["cpp"] , "RawPointer" when includeRaw -> true + | ["cpp"] , "RawConstPointer" when includeRaw -> true + | _ -> false ) + | TType (type_def,params) -> + (match type_def.t_path with + | ["cpp"] , "Pointer" + | ["cpp"] , "ConstPointer" + | ["cpp"] , "Function" -> true + | ["cpp"] , "RawPointer" when includeRaw -> true + | ["cpp"] , "RawConstPointer" when includeRaw -> true + | _ -> false ) + | _ -> false + ;; + +let is_dynamic_type_param class_kind = + match class_kind with + | KTypeParameter _ -> true + | _ -> false +;; (* Get a string to represent a type. - The "suffix" will be nothing or "_obj", depending if we want the name of the - pointer class or the pointee (_obj class *) -let rec class_string klass suffix params = - (match klass.cl_path with - (* Array class *) - | ([],"Array") when is_dynamic_array_param (List.hd params) -> "Dynamic" - | ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "< " ^ (String.concat "," - (List.map array_element_type params) ) ^ " >" - (* FastIterator class *) - | (["cpp"],"FastIterator") -> "::cpp::FastIterator" ^ suffix ^ "< " ^ (String.concat "," - (List.map type_string params) ) ^ " >" - | _ when (match klass.cl_kind with KTypeParameter _ -> true | _ -> false) -> "Dynamic" - | ([],"#Int") -> "/* # */int" - | (["haxe";"io"],"Unsigned_char__") -> "unsigned char" - | ([],"Class") -> "::Class" - | ([],"EnumValue") -> "Dynamic" - | ([],"Null") -> (match params with - | [t] -> - (match follow t with - | TAbstract ({ a_path = [],"Int" },_) - | TAbstract ({ a_path = [],"Float" },_) - | TAbstract ({ a_path = [],"Bool" },_) - | TInst ({ cl_path = [],"Int" },_) - | TInst ({ cl_path = [],"Float" },_) - | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" - | _ -> "/*NULL*/" ^ (type_string t) ) - | _ -> assert false); - (* Normal class *) - | path when klass.cl_extern && (not (is_internal_class path) )-> + The "suffix" will be nothing or "_obj", depending if we want the name of the + pointer class or the pointee (_obj class *) +let rec class_string klass suffix params 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 klass.cl_path with + (* Array class *) + | ([],"Array") when is_dynamic_array_param (List.hd params) -> + "cpp::ArrayBase" ^ suffix (* "Dynamic" *) + | ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "< " ^ (String.concat "," + (List.map array_element_type params) ) ^ " >" + (* FastIterator class *) + | (["cpp"],"FastIterator") -> "::cpp::FastIterator" ^ suffix ^ "< " ^ (String.concat "," + (List.map type_string params) ) ^ " >" + | (["cpp"],"Pointer") + | (["cpp"],"ConstPointer") -> + "::cpp::Pointer< " ^ (String.concat "," (List.map type_string params) ) ^ " >" + | (["cpp"],"RawPointer") -> + " " ^ (String.concat "," (List.map type_string params) ) ^ " * " + | (["cpp"],"RawConstPointer") -> + " const " ^ (String.concat "," (List.map type_string params) ) ^ " * " + | (["cpp"],"Function") -> + "::cpp::Function< " ^ (cpp_function_signature_params params) ^ " >" + | _ when is_dynamic_type_param klass.cl_kind -> "Dynamic" + | ([],"#Int") -> "/* # */int" + | (["haxe";"io"],"Unsigned_char__") -> "unsigned char" + | ([],"Class") -> "hx::Class" + | ([],"EnumValue") -> "Dynamic" + | ([],"Null") -> (match params with + | [t] -> + (match follow t with + | TAbstract ({ a_path = [],"Int" },_) + | TAbstract ({ a_path = [],"Float" },_) + | TAbstract ({ a_path = [],"Bool" },_) + | TInst ({ cl_path = [],"Int" },_) + | TInst ({ cl_path = [],"Float" },_) + | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" + | t when type_has_meta_key t Meta.NotNull -> "Dynamic" + | _ -> "/*NULL*/" ^ (type_string t) ) + | _ -> assert false); + (* Normal class *) + | path when klass.cl_extern && (not (is_internal_class path) )-> (join_class_path_remap klass.cl_path "::") ^ suffix - | _ -> "::" ^ (join_class_path_remap klass.cl_path "::") ^ suffix - ) -and type_string_suff suffix haxe_type = - (match haxe_type with - | TMono r -> (match !r with None -> "Dynamic" ^ suffix | Some t -> type_string_suff suffix t) - | TAbstract ({ a_path = ([],"Void") },[]) -> "Void" - | TAbstract ({ a_path = ([],"Bool") },[]) -> "bool" - | TAbstract ({ a_path = ([],"Float") },[]) -> "Float" - | TAbstract ({ a_path = ([],"Int") },[]) -> "int" - | TAbstract( { a_path = ([], "EnumValue") }, _ ) -> "Dynamic" - | TEnum ({ e_path = ([],"Void") },[]) -> "Void" - | TEnum ({ e_path = ([],"Bool") },[]) -> "bool" - | TInst ({ cl_path = ([],"Float") },[]) -> "Float" - | TInst ({ cl_path = ([],"Int") },[]) -> "int" - | TEnum (enum,params) -> "::" ^ (join_class_path_remap enum.e_path "::") ^ suffix - | TInst (klass,params) -> (class_string klass suffix params) - | TType (type_def,params) -> - (match type_def.t_path with - | [] , "Null" -> - (match params with - | [t] -> - (match follow t with - | TAbstract ({ a_path = [],"Int" },_) - | TAbstract ({ a_path = [],"Float" },_) - | TAbstract ({ a_path = [],"Bool" },_) - | TInst ({ cl_path = [],"Int" },_) - | TInst ({ cl_path = [],"Float" },_) - | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" ^ suffix - | _ -> type_string_suff suffix t) - | _ -> assert false); - | [] , "Array" -> - (match params with - | [t] when (type_string (follow t)) = "Dynamic" -> "Dynamic" - | [t] -> "Array< " ^ (type_string (follow t) ) ^ " >" - | _ -> assert false) - | ["cpp"] , "FastIterator" -> - (match params with - | [t] -> "::cpp::FastIterator< " ^ (type_string (follow t) ) ^ " >" - | _ -> assert false) - | _ -> type_string_suff suffix (apply_params type_def.t_types params type_def.t_type) - ) - | TFun (args,haxe_type) -> "Dynamic" ^ suffix - | TAnon a -> "Dynamic" + | _ -> "::" ^ (join_class_path_remap klass.cl_path "::") ^ suffix + ) +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) + | TAbstract ({ a_path = ([],"Void") },[]) -> "Void" + | TAbstract ({ a_path = ([],"Bool") },[]) -> "bool" + | TAbstract ({ a_path = ([],"Float") },[]) -> "Float" + | TAbstract ({ a_path = ([],"Int") },[]) -> "int" + | TAbstract( { a_path = ([], "EnumValue") }, _ ) -> "Dynamic" + | TEnum (enum,params) -> "::" ^ (join_class_path_remap enum.e_path "::") ^ suffix + | TInst (klass,params) -> (class_string klass suffix params remap) + | TType (type_def,params) -> + (match type_def.t_path with + | [] , "Null" -> + (match params with + | [t] -> + (match follow t with + | TAbstract ({ a_path = [],"Int" },_) + | TAbstract ({ a_path = [],"Float" },_) + | TAbstract ({ a_path = [],"Bool" },_) + | TInst ({ cl_path = [],"Int" },_) + | TInst ({ cl_path = [],"Float" },_) + | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" ^ suffix + | t when type_has_meta_key t Meta.NotNull -> "Dynamic" ^ suffix + | _ -> type_string_suff suffix t remap) + | _ -> assert false); + | [] , "Array" -> + (match params with + | [t] when (type_string (follow t) ) = "Dynamic" -> "Dynamic" + | [t] -> "Array< " ^ (type_string (follow t) ) ^ " >" + | _ -> assert false) + | ["cpp"] , "FastIterator" -> + (match params with + | [t] -> "::cpp::FastIterator< " ^ (type_string (follow t) ) ^ " >" + | _ -> assert false) + | ["cpp"] , "Pointer" + | ["cpp"] , "ConstPointer" -> + (match params with + | [t] -> "::cpp::Pointer< " ^ (type_string (follow t) ) ^ " >" + | _ -> assert false) + | ["cpp"] , "RawPointer" -> + (match params with + | [t] -> " " ^ (type_string (follow t) ) ^ " *" + | _ -> assert false) + | ["cpp"] , "RawConstPointer" -> + (match params with + | [t] -> "const " ^ (type_string (follow t) ) ^ " *" + | _ -> assert false) + | ["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 + ) + | TFun (args,haxe_type) -> "Dynamic" ^ suffix + | TAnon a -> "Dynamic" (* - (match !(a.a_status) with - | Statics c -> type_string_suff suffix (TInst (c,List.map snd c.cl_types)) - | EnumStatics e -> type_string_suff suffix (TEnum (e,List.map snd e.e_types)) - | _ -> "Dynamic" ^ suffix ) + (match !(a.a_status) with + | Statics c -> type_string_suff suffix (TInst (c,List.map snd c.cl_params)) + | EnumStatics e -> type_string_suff suffix (TEnum (e,List.map snd e.e_params)) + | _ -> "Dynamic" ^ suffix ) *) - | TDynamic haxe_type -> "Dynamic" ^ suffix - | TLazy func -> type_string_suff suffix ((!func)()) - | TAbstract (abs,pl) when abs.a_impl <> None -> - type_string_suff suffix (Codegen.Abstract.get_underlying_type abs pl) - | TAbstract (abs,pl) -> - "::" ^ (join_class_path_remap abs.a_path "::") ^ suffix - ) + | TDynamic haxe_type -> "Dynamic" ^ suffix + | TLazy func -> type_string_suff suffix ((!func)()) remap + | TAbstract (abs,pl) when abs.a_impl <> None -> + type_string_suff suffix (Abstract.get_underlying_type abs pl) remap + | TAbstract (abs,pl) -> + "::" ^ (join_class_path_remap abs.a_path "::") ^ suffix + ) + +and type_string_remap remap haxe_type = + type_string_suff "" haxe_type remap + and type_string haxe_type = - type_string_suff "" haxe_type + type_string_suff "" haxe_type true + and array_element_type haxe_type = match type_string haxe_type with - | x when cant_be_null x -> x + | x when cant_be_null haxe_type -> x + | x when is_interface_type (follow haxe_type) -> x | "::String" -> "::String" | _ -> "::Dynamic" and is_dynamic_array_param haxe_type = if (type_string (follow haxe_type)) = "Dynamic" then true - else (match follow haxe_type with - | TInst (klass,params) -> - (match klass.cl_path with - | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") -> false - | _ -> (match klass.cl_kind with KTypeParameter _ -> true | _ -> false) - ) + else (match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_path with + | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") + | (["cpp"],"RawPointer") |(["cpp"],"ConstRawPointer") + | (["cpp"],"Pointer") |(["cpp"],"ConstPointer")|(["cpp"],"Function") -> false + | _ -> (match klass.cl_kind with KTypeParameter _ -> true | _ -> false) + ) | _ -> false - ) + ) +and cpp_function_signature tfun abi = + match follow tfun with + | TFun(args,ret) -> (type_string ret) ^ " " ^ abi ^ "( " ^ (gen_tfun_interface_arg_list args) ^ ")" + | _ -> "void *" + +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 ) + | _ -> + print_endline ("Params:" ^ (String.concat "," (List.map type_string params) )); + assert false; + +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 ^ " > " + else + type_str ) + + + ^ " " ^ (keyword_remap name) +and gen_tfun_interface_arg_list args = + String.concat "," (List.map (fun (name,opt,typ) -> gen_interface_arg_type_name name opt typ) args) +and cant_be_null haxe_type = + is_numeric (type_string haxe_type) || (type_has_meta_key haxe_type Meta.NotNull ) ;; +let is_object type_string = + not (is_numeric type_string || type_string="::String"); +;; let is_array haxe_type = - match follow haxe_type with - | TInst (klass,params) -> - (match klass.cl_path with - | [] , "Array" -> not (is_dynamic_array_param (List.hd params)) - | _ -> false ) - | TType (type_def,params) -> - (match type_def.t_path with - | [] , "Array" -> not (is_dynamic_array_param (List.hd params)) - | _ -> false ) - | _ -> false - ;; + match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_path with + | [] , "Array" -> not (is_dynamic_array_param (List.hd params)) + | _ -> false ) + | TType (type_def,params) -> + (match type_def.t_path with + | [] , "Array" -> not (is_dynamic_array_param (List.hd params)) + | _ -> false ) + | _ -> false + ;; + +let is_array_or_dyn_array haxe_type = + match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_path with | [] , "Array" -> true | _ -> false ) + | TType (type_def,params) -> + (match type_def.t_path with | [] , "Array" -> true | _ -> false ) + | _ -> false + ;; + + let is_array_implementer haxe_type = - match follow haxe_type with - | TInst (klass,params) -> - (match klass.cl_array_access with - | Some _ -> true - | _ -> false ) - | _ -> false - ;; + match follow haxe_type with + | TInst (klass,params) -> + (match klass.cl_array_access with + | Some _ -> true + | _ -> false ) + | _ -> false + ;; let is_numeric_field field = match field.cf_kind with | Var _ -> is_numeric (type_string field.cf_type) - | _ -> false; + | _ -> false; ;; -(* Get the type and output it to the stream *) -let gen_type ctx haxe_type = - ctx.ctx_output (type_string haxe_type) +let is_static_access obj = + match (remove_parens obj).eexpr with + | TTypeExpr _ -> true + | _ -> false ;; -(* Get the type and output it to the stream *) -let gen_type_suff ctx haxe_type suff = - ctx.ctx_output (type_string_suff suff haxe_type);; +let is_native_with_space func = + match (remove_parens func).eexpr with + | TField(obj,field) when is_static_access obj -> + String.contains (get_field_access_meta field Meta.Native) ' ' + | _ -> false +;; -let member_type ctx field_object member = - let name = (if (is_array field_object.etype) then "::Array" - else (type_string field_object.etype)) ^ "." ^ member in - try ( Hashtbl.find ctx.ctx_class_member_types name ) - with Not_found -> "?";; -let is_interface_type t = - match follow t with - | TInst (klass,params) -> klass.cl_interface - | _ -> false +let rec is_cpp_function_member func = + match (remove_parens func).eexpr with + | TField(obj,field) when is_cpp_function_instance obj.etype -> true + | TCall(obj,_) -> is_cpp_function_member obj + | _ -> false +;; + + + + +(* Get the type and output it to the stream *) +let gen_type ctx haxe_type = + ctx.ctx_output (type_string haxe_type) ;; +let member_type ctx field_object member = + let name = (if (is_array field_object.etype) then "::Array" + else (type_string field_object.etype)) ^ "." ^ member in + try ( Hashtbl.find ctx.ctx_class_member_types name ) + with Not_found -> "?";; + let is_interface obj = is_interface_type obj.etype;; let should_implement_field x = not (is_extern_field x);; let is_function_member expression = - match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;; + match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;; let is_internal_member member = match member with - | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString" - | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal" - | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField" - -> true + | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString" + | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal" + | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField" + | "__GetRealObject" + -> true | _ -> false;; +let is_extern_class class_def = + class_def.cl_extern || (has_meta_key class_def.cl_meta Meta.Extern) || + (match class_def.cl_kind with + | KAbstractImpl abstract_def -> (has_meta_key abstract_def.a_meta Meta.Extern) + | _ -> false ); +;; + + +let is_native_gen_class class_def = + (has_meta_key class_def.cl_meta Meta.NativeGen) || + (match class_def.cl_kind with + | KAbstractImpl abstract_def -> (has_meta_key abstract_def.a_meta Meta.NativeGen) + | _ -> false ); +;; + + +let is_extern_class_instance obj = + match follow obj.etype with + | TInst (klass,params) -> klass.cl_extern + | _ -> false +;; + + +let is_struct_access t = + match follow t with + | TInst (class_def,_) -> (has_meta_key class_def.cl_meta Meta.StructAccess) + | _ -> false +;; + + + let rec is_dynamic_accessor name acc field class_def = ( ( acc ^ "_" ^ field.cf_name) = name ) && - ( not (List.exists (fun f -> f.cf_name=name) class_def.cl_ordered_fields) ) + ( not (List.exists (fun f -> f.cf_name=name) class_def.cl_ordered_fields) ) && (match class_def.cl_super with None -> true | Some (parent,_) -> is_dynamic_accessor name acc field parent ) ;; let gen_arg_type_name name default_val arg_type prefix = - let remap_name = keyword_remap name in - let type_str = (type_string arg_type) in - match default_val with - | Some TNull -> (type_str,remap_name) - | Some constant when (cant_be_null type_str) -> ("hx::Null< " ^ type_str ^ " > ",prefix ^ remap_name) - | Some constant -> (type_str,prefix ^ remap_name) - | _ -> (type_str,remap_name);; - -let gen_interface_arg_type_name name opt typ = - let type_str = (type_string typ) in - (if (opt && (cant_be_null type_str) ) then - "hx::Null< " ^ type_str ^ " > " - else - type_str ) - ^ " " ^ (keyword_remap name) -;; - -let gen_tfun_interface_arg_list args = - String.concat "," (List.map (fun (name,opt,typ) -> gen_interface_arg_type_name name opt typ) args) -;; + let remap_name = keyword_remap name in + let type_str = (type_string arg_type) in + match default_val with + | Some TNull -> (type_str,remap_name) + | Some constant when (cant_be_null arg_type) -> ("hx::Null< " ^ type_str ^ " > ",prefix ^ remap_name) + | Some constant -> (type_str,prefix ^ remap_name) + | _ -> (type_str,remap_name);; (* Generate prototype text, including allowing default values to be null *) let gen_arg name default_val arg_type prefix = - let pair = gen_arg_type_name name default_val arg_type prefix in - (fst pair) ^ " " ^ (snd pair);; + let pair = gen_arg_type_name name default_val arg_type prefix in + (fst pair) ^ " " ^ (snd pair);; let rec gen_arg_list arg_list prefix = - String.concat "," (List.map (fun (v,o) -> (gen_arg v.v_name o v.v_type prefix) ) arg_list) + String.concat "," (List.map (fun (v,o) -> (gen_arg v.v_name o v.v_type prefix) ) arg_list) let rec gen_tfun_arg_list arg_list = - match arg_list with - | [] -> "" - | [(name,o,arg_type)] -> gen_arg name None arg_type "" - | (name,o,arg_type) :: remaining -> - (gen_arg name None arg_type "") ^ "," ^ (gen_tfun_arg_list remaining) + match arg_list with + | [] -> "" + | [(name,o,arg_type)] -> gen_arg name None arg_type "" + | (name,o,arg_type) :: remaining -> + (gen_arg name None arg_type "") ^ "," ^ (gen_tfun_arg_list remaining) (* Check to see if we are the first object in the parent tree to implement a dynamic interface *) let implement_dynamic_here class_def = - let implements_dynamic c = match c.cl_dynamic with None -> false | _ -> true in - let rec super_implements_dynamic c = match c.cl_super with - | None -> false - | Some (csup, _) -> if (implements_dynamic csup) then true else - super_implements_dynamic csup; - in - ( (implements_dynamic class_def) && (not (super_implements_dynamic class_def) ) );; + let implements_dynamic c = match c.cl_dynamic with None -> false | _ -> true in + let rec super_implements_dynamic c = match c.cl_super with + | None -> false + | Some (csup, _) -> if (implements_dynamic csup) then true else + super_implements_dynamic csup; + in + ( (implements_dynamic class_def) && (not (super_implements_dynamic class_def) ) );; + + +let gen_hash32 seed str = + let h = ref (Int32.of_int seed) in + let cycle = Int32.of_int 223 in + for i = 0 to String.length str - 1 do + h := Int32.add (Int32.mul !h cycle) (Int32.of_int (int_of_char (String.unsafe_get str i))); + done; + !h +;; + +let gen_hash seed str = + Printf.sprintf "0x%08lx" (gen_hash32 seed str) +;; + +let gen_string_hash str = + let h = gen_hash32 0 str in + Printf.sprintf "\"\\x%02lx\",\"\\x%02lx\",\"\\x%02lx\",\"\\x%02lx\"" + (Int32.shift_right_logical (Int32.shift_left h 24) 24) + (Int32.shift_right_logical (Int32.shift_left h 16) 24) + (Int32.shift_right_logical (Int32.shift_left h 8) 24) + (Int32.shift_right_logical h 24) +;; + (* Make string printable for c++ code *) (* Here we know there are no utf8 characters, so use the L"" notation to avoid conversion *) let escape_stringw s l = - let b = Buffer.create 0 in - Buffer.add_char b 'L'; - Buffer.add_char b '"'; - let skip = ref 0 in - for i = 0 to String.length s - 1 do - if (!skip>0) then begin - skip := !skip -1; - l := !l-1; - end else - match Char.code (String.unsafe_get s i) with - | c when (c>127) -> - let encoded = ((c land 0x3F) lsl 6) lor ( Char.code ((String.unsafe_get s (i+1))) land 0x7F) in - skip := 1; - Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" encoded) - | c when (c < 32) -> Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" c) - | c -> Buffer.add_char b (Char.chr c) - done; - Buffer.add_char b '"'; - Buffer.contents b;; + let b = Buffer.create 0 in + Buffer.add_char b 'L'; + Buffer.add_char b '"'; + let skip = ref 0 in + for i = 0 to String.length s - 1 do + if (!skip>0) then begin + skip := !skip -1; + l := !l-1; + end else + match Char.code (String.unsafe_get s i) with + | c when (c>127) -> + let encoded = ((c land 0x3F) lsl 6) lor ( Char.code ((String.unsafe_get s (i+1))) land 0x7F) in + skip := 1; + Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" encoded) + | c when (c < 32) -> Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" c) + | c -> Buffer.add_char b (Char.chr c) + done; + Buffer.add_char b '"'; + Buffer.contents b;; let special_to_hex s = - let l = String.length s in - let b = Buffer.create 0 in - for i = 0 to l - 1 do - match Char.code (String.unsafe_get s i) with - | c when (c>127) || (c<32) -> - Buffer.add_string b (Printf.sprintf "\\x%02x\"\"" c) - | c -> Buffer.add_char b (Char.chr c) - done; - Buffer.contents b;; + let l = String.length s in + let b = Buffer.create 0 in + for i = 0 to l - 1 do + match Char.code (String.unsafe_get s i) with + | c when (c>127) || (c<32) -> + Buffer.add_string b (Printf.sprintf "\\x%02x\"\"" c) + | c -> Buffer.add_char b (Char.chr c) + done; + Buffer.contents b;; let escape_extern s = - let l = String.length s in - let b = Buffer.create 0 in - for i = 0 to l - 1 do - match Char.code (String.unsafe_get s i) with - | c when (c>127) || (c<32) || (c=34) || (c=92) -> - Buffer.add_string b (Printf.sprintf "\\x%02x" c) - | c -> Buffer.add_char b (Char.chr c) - done; - Buffer.contents b;; + let l = String.length s in + let b = Buffer.create 0 in + for i = 0 to l - 1 do + match Char.code (String.unsafe_get s i) with + | c when (c>127) || (c<32) || (c=34) || (c=92) -> + Buffer.add_string b (Printf.sprintf "\\x%02x" c) + | c -> Buffer.add_char b (Char.chr c) + done; + Buffer.contents b;; let has_utf8_chars s = - let result = ref false in - for i = 0 to String.length s - 1 do - result := !result || ( Char.code (String.unsafe_get s i) > 127 ) - done; - !result;; + let result = ref false in + for i = 0 to String.length s - 1 do + result := !result || ( Char.code (String.unsafe_get s i) > 127 ) + done; + !result;; let escape_command s = - let b = Buffer.create 0 in + let b = Buffer.create 0 in String.iter (fun ch -> if (ch=='"' || ch=='\\' ) then Buffer.add_string b "\\"; Buffer.add_char b ch ) s; Buffer.contents b;; - let str s = - let escaped = Ast.s_escape s in - ("HX_CSTRING(\"" ^ (special_to_hex escaped) ^ "\")") + let rec split s plus = + let escaped = Ast.s_escape ~hex:false s in + let hexed = (special_to_hex escaped) in + if (String.length hexed <= 16000 ) then + plus ^ " HX_CSTRING(\"" ^ hexed ^ "\")" + else begin + let len = String.length s in + let half = len lsr 1 in + (split (String.sub s 0 half) plus ) ^ (split (String.sub s half (len-half)) "+" ) + end + in + let escaped = Ast.s_escape ~hex:false s in + let hexed = (special_to_hex escaped) in + if (String.length hexed <= 16000 ) then + "HX_HCSTRING(\"" ^ hexed ^ "\"," ^ (gen_string_hash s) ^ ")" + else + "(" ^ (split s "" ) ^ ")" +;; + +let const_char_star s = + let escaped = Ast.s_escape ~hex:false s in + "\"" ^ special_to_hex escaped ^ "\""; ;; (* When we are in a "real" object, we refer to ourselves as "this", but - if we are in a local class that is used to generate return values, - we use the fake "__this" pointer. - If we are in an "Anon" object, then the "this" refers to the anon object (eg List iterator) *) + if we are in a local class that is used to generate return values, + we use the fake "__this" pointer. + If we are in an "Anon" object, then the "this" refers to the anon object (eg List iterator) *) let clear_real_this_ptr ctx dynamic_this = - let old_flag = ctx.ctx_real_this_ptr in - let old_dynamic = ctx.ctx_dynamic_this_ptr in - ctx.ctx_real_this_ptr <- false; - ctx.ctx_dynamic_this_ptr <- dynamic_this; - fun () -> ( ctx.ctx_real_this_ptr <- old_flag; ctx.ctx_dynamic_this_ptr <- old_dynamic; );; + let old_flag = ctx.ctx_real_this_ptr in + let old_dynamic = ctx.ctx_dynamic_this_ptr in + let old_void = ctx.ctx_real_void in + ctx.ctx_real_this_ptr <- false; + ctx.ctx_dynamic_this_ptr <- dynamic_this; + fun () -> ( + ctx.ctx_real_this_ptr <- old_flag; + ctx.ctx_dynamic_this_ptr <- old_dynamic; + ctx.ctx_real_void <- old_void; + ) +;; (* Generate temp variable names *) let next_anon_function_name ctx = - ctx.ctx_static_id_curr <- ctx.ctx_static_id_curr + 1; - "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_curr);; + ctx.ctx_static_id_curr <- ctx.ctx_static_id_curr + 1; + "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_curr);; let use_anon_function_name ctx = - ctx.ctx_static_id_used <- ctx.ctx_static_id_used + 1; - "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_used);; + ctx.ctx_static_id_used <- ctx.ctx_static_id_used + 1; + "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_used);; let push_anon_names ctx = - let old_used = ctx.ctx_static_id_used in - let old_curr = ctx.ctx_static_id_curr in - let old_depth = ctx.ctx_static_id_depth in - ctx.ctx_static_id_used <- 0; - ctx.ctx_static_id_curr <- 0; - ctx.ctx_static_id_depth <- ctx.ctx_static_id_depth + 1; - ( function () -> ( - ctx.ctx_static_id_used <- old_used; - ctx.ctx_static_id_curr <- old_curr; - ctx.ctx_static_id_depth <- old_depth; ) ) + let old_used = ctx.ctx_static_id_used in + let old_curr = ctx.ctx_static_id_curr in + let old_depth = ctx.ctx_static_id_depth in + ctx.ctx_static_id_used <- 0; + ctx.ctx_static_id_curr <- 0; + ctx.ctx_static_id_depth <- ctx.ctx_static_id_depth + 1; + ( function () -> ( + ctx.ctx_static_id_used <- old_used; + ctx.ctx_static_id_curr <- old_curr; + ctx.ctx_static_id_depth <- old_depth; ) ) ;; let get_switch_var ctx = - ctx.ctx_switch_id <- ctx.ctx_switch_id + 1; - "_switch_" ^ (string_of_int ctx.ctx_switch_id) + ctx.ctx_switch_id <- ctx.ctx_switch_id + 1; + "_switch_" ^ (string_of_int ctx.ctx_switch_id) (* If you put on the "-debug" flag, you get extra comments in the source code *) let debug_expression expression type_too = - "/* " ^ Type.s_expr_kind expression ^ (if (type_too) then " = " ^ (type_string expression.etype) else "") ^ " */";; + "/* " ^ Type.s_expr_kind expression ^ (if (type_too) then " = " ^ (type_string expression.etype) else "") ^ " */";; (* This is like the Type.iter, but also keeps the "retval" flag up to date *) let rec iter_retval f retval e = - match e.eexpr with - | TConst _ - | TLocal _ - | TBreak - | TContinue - | TTypeExpr _ -> - () - | TArray (e1,e2) - | TBinop (_,e1,e2) -> - f true e1; - f true e2; - | TWhile (e1,e2,_) -> - f true e1; - f false e2; - | TFor (_,e1,e2) -> - f true e1; - f false e2; - | TThrow e - | TField (e,_) - | TUnop (_,_,e) -> - f true e - | TParenthesis e -> - f retval e - | TBlock expr_list when retval -> - let rec return_last = function - | [] -> () - | expr :: [] -> f true expr - | expr :: exprs -> f false expr; return_last exprs in - return_last expr_list - | TArrayDecl el - | TNew (_,_,el) -> - List.iter (f true ) el - | TBlock el -> - List.iter (f false ) el - | TObjectDecl fl -> - List.iter (fun (_,e) -> f true e) fl - | TCall (e,el) -> - f true e; - List.iter (f true) el - | TVars vl -> - List.iter (fun (_,e) -> match e with None -> () | Some e -> f true e) vl - | TFunction fu -> - f false fu.tf_expr - | TIf (e,e1,e2) -> - f true e; - f retval e1; - (match e2 with None -> () | Some e -> f retval e) - | TSwitch (e,cases,def) -> - f true e; - List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases; - (match def with None -> () | Some e -> f retval e) - | TMatch (e,_,cases,def) -> - f true e; - List.iter (fun (_,_,e) -> f false e) cases; - (match def with None -> () | Some e -> f false e) - | TTry (e,catches) -> - f retval e; - List.iter (fun (_,e) -> f false e) catches - | TReturn eo -> - (match eo with None -> () | Some e -> f true e) - | TCast (e,None) -> - f retval e - | TCast (e,_) -> - f true e + match e.eexpr with + | TConst _ + | TLocal _ + | TBreak + | TContinue + | TTypeExpr _ -> + () + | TArray (e1,e2) + | TBinop (_,e1,e2) -> + f true e1; + f true e2; + | TWhile (e1,e2,_) -> + f true e1; + f false e2; + | TFor (_,e1,e2) -> + f true e1; + f false e2; + | TThrow e + | TField (e,_) + | TEnumParameter (e,_,_) + | TUnop (_,_,e) -> + f true e + | TParenthesis e | TMeta(_,e) -> + f retval e + | TBlock expr_list when retval -> + let rec return_last = function + | [] -> () + | expr :: [] -> f true expr + | expr :: exprs -> f false expr; return_last exprs in + return_last expr_list + | TArrayDecl el + | TNew (_,_,el) -> + List.iter (f true ) el + | TBlock el -> + List.iter (f false ) el + | TObjectDecl fl -> + List.iter (fun (_,e) -> f true e) fl + | TCall (e,el) -> + f true e; + List.iter (f true) el + | TVar (_,eo) -> + (match eo with None -> () | Some e -> f true e) + | TFunction fu -> + f false fu.tf_expr + | TIf (e,e1,e2) -> + f true e; + f retval e1; + (match e2 with None -> () | Some e -> f retval e) + | TSwitch (e,cases,def) -> + f true e; + List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases; + (match def with None -> () | Some e -> f retval e) +(* | TMatch (e,_,cases,def) -> + f true e; + List.iter (fun (_,_,e) -> f false e) cases; + (match def with None -> () | Some e -> f false e) *) + | TTry (e,catches) -> + f retval e; + List.iter (fun (_,e) -> f false e) catches + | TReturn eo -> + (match eo with None -> () | Some e -> f true e) + | TCast (e,None) -> + f retval e + | TCast (e,_) -> + f true e ;; (* Convert an array to a comma separated list of values *) let array_arg_list inList = - let i = ref (0-1) in - String.concat "," (List.map (fun _ -> incr i; "inArgs[" ^ (string_of_int !i) ^ "]" ) inList) + let i = ref (0-1) in + String.concat "," (List.map (fun _ -> incr i; "inArgs[" ^ (string_of_int !i) ^ "]" ) inList) let list_num l = string_of_int (List.length l);; let only_int_cases cases = - match cases with - | [] -> false - | _ -> - not (List.exists (fun (cases,expression) -> - List.exists (fun case -> match case.eexpr with TConst (TInt _) -> false | _ -> true ) cases - ) cases );; + match cases with + | [] -> false + | _ -> + not (List.exists (fun (cases,expression) -> + List.exists (fun case -> match case.eexpr with TConst (TInt _) -> false | _ -> true ) cases + ) cases );; (* See if there is a haxe break statement that will be swollowed by c++ break *) exception BreakFound;; let contains_break expression = - try ( - let rec check_all expression = - Type.iter (fun expr -> match expr.eexpr with - | TBreak -> raise BreakFound - | TFor _ - | TFunction _ - | TWhile (_,_,_) -> () - | _ -> check_all expr; - ) expression in - check_all expression; - false; - ) with BreakFound -> true;; + try ( + let rec check_all expression = + Type.iter (fun expr -> match expr.eexpr with + | TBreak -> raise BreakFound + | TFor _ + | TFunction _ + | TWhile (_,_,_) -> () + | _ -> check_all expr; + ) expression in + check_all expression; + false; + ) with BreakFound -> true;; (* Decide is we should look the field up by name *) let dynamic_internal = function | "__Is" -> true | _ -> false -(* Get a list of variables to extract from a enum tmatch *) -let tmatch_params_to_args params = - (match params with - | None | Some [] -> [] - | Some l -> - let n = ref (-1) in - List.fold_left - (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,v.v_type,!n) :: acc) [] l) - let rec is_null expr = match expr.eexpr with | TConst TNull -> true - | TParenthesis expr -> is_null expr + | TParenthesis expr | TMeta (_,expr) -> is_null expr | TCast (e,None) -> is_null e | _ -> false ;; let find_undeclared_variables_ctx ctx undeclared declarations this_suffix allow_this expression = - let output = ctx.ctx_output in - let rec find_undeclared_variables undeclared declarations this_suffix allow_this expression = - match expression.eexpr with - | TVars var_list -> - List.iter (fun (tvar, optional_init) -> - Hashtbl.add declarations (keyword_remap tvar.v_name) (); - if (ctx.ctx_debug) then - output ("/* found var " ^ tvar.v_name ^ "*/ "); - match optional_init with - | Some expression -> find_undeclared_variables undeclared declarations this_suffix allow_this expression - | _ -> () - ) var_list - | TFunction func -> List.iter ( fun (tvar, opt_val) -> - if (ctx.ctx_debug) then - output ("/* found arg " ^ tvar.v_name ^ " = " ^ (type_string tvar.v_type) ^ " */ "); - Hashtbl.add declarations (keyword_remap tvar.v_name) () ) func.tf_args; - find_undeclared_variables undeclared declarations this_suffix false func.tf_expr - | TTry (try_block,catches) -> - find_undeclared_variables undeclared declarations this_suffix allow_this try_block; - List.iter (fun (tvar,catch_expt) -> - let old_decs = Hashtbl.copy declarations in - Hashtbl.add declarations (keyword_remap tvar.v_name) (); - find_undeclared_variables undeclared declarations this_suffix allow_this catch_expt; - Hashtbl.clear declarations; - Hashtbl.iter ( Hashtbl.add declarations ) old_decs - ) catches; - | TLocal tvar -> + let output = ctx.ctx_output in + let rec find_undeclared_variables undeclared declarations this_suffix allow_this expression = + match expression.eexpr with + | TVar (tvar,optional_init) -> + Hashtbl.add declarations (keyword_remap tvar.v_name) (); + if (ctx.ctx_debug_level>1) then + output ("/* found var " ^ tvar.v_name ^ "*/ "); + (match optional_init with + | Some expression -> find_undeclared_variables undeclared declarations this_suffix allow_this expression + | _ -> ()) + | TFunction func -> List.iter ( fun (tvar, opt_val) -> + if (ctx.ctx_debug_level>1) then + output ("/* found arg " ^ tvar.v_name ^ " = " ^ (type_string tvar.v_type) ^ " */ "); + Hashtbl.add declarations (keyword_remap tvar.v_name) () ) func.tf_args; + find_undeclared_variables undeclared declarations this_suffix false func.tf_expr + | TTry (try_block,catches) -> + find_undeclared_variables undeclared declarations this_suffix allow_this try_block; + List.iter (fun (tvar,catch_expt) -> + let old_decs = Hashtbl.copy declarations in + Hashtbl.add declarations (keyword_remap tvar.v_name) (); + find_undeclared_variables undeclared declarations this_suffix allow_this catch_expt; + Hashtbl.clear declarations; + Hashtbl.iter ( Hashtbl.add declarations ) old_decs + ) catches; + | TLocal tvar -> let name = keyword_remap tvar.v_name in - if not (Hashtbl.mem declarations name) then - Hashtbl.replace undeclared name (type_string expression.etype) - | TMatch (condition, enum, cases, default) -> - find_undeclared_variables undeclared declarations this_suffix allow_this condition; - List.iter (fun (case_ids,params,expression) -> - let old_decs = Hashtbl.copy declarations in - (match params with - | None -> () - | Some l -> List.iter (fun (opt_var) -> - match opt_var with | Some v -> Hashtbl.add declarations (keyword_remap v.v_name) () | _ -> () ) - l ); - find_undeclared_variables undeclared declarations this_suffix allow_this expression; - Hashtbl.clear declarations; - Hashtbl.iter ( Hashtbl.add declarations ) old_decs - ) cases; - (match default with | None -> () - | Some expr -> - find_undeclared_variables undeclared declarations this_suffix allow_this expr; - ); - | TFor (tvar, init, loop) -> - let old_decs = Hashtbl.copy declarations in - Hashtbl.add declarations (keyword_remap tvar.v_name) (); - find_undeclared_variables undeclared declarations this_suffix allow_this init; - find_undeclared_variables undeclared declarations this_suffix allow_this loop; - Hashtbl.clear declarations; - Hashtbl.iter ( Hashtbl.add declarations ) old_decs - | TConst TSuper - | TConst TThis -> - if ((not (Hashtbl.mem declarations "this")) && allow_this) then - Hashtbl.replace undeclared "this" (type_string_suff this_suffix expression.etype) - | TBlock expr_list -> - let old_decs = Hashtbl.copy declarations in - List.iter (find_undeclared_variables undeclared declarations this_suffix allow_this ) expr_list; - (* what is the best way for this ? *) - Hashtbl.clear declarations; - Hashtbl.iter ( Hashtbl.add declarations ) old_decs - | _ -> Type.iter (find_undeclared_variables undeclared declarations this_suffix allow_this) expression - in - find_undeclared_variables undeclared declarations this_suffix allow_this expression + if not (Hashtbl.mem declarations name) then + Hashtbl.replace undeclared name (type_string expression.etype) +(* | TMatch (condition, enum, cases, default) -> + find_undeclared_variables undeclared declarations this_suffix allow_this condition; + List.iter (fun (case_ids,params,expression) -> + let old_decs = Hashtbl.copy declarations in + (match params with + | None -> () + | Some l -> List.iter (fun (opt_var) -> + match opt_var with | Some v -> Hashtbl.add declarations (keyword_remap v.v_name) () | _ -> () ) + l ); + find_undeclared_variables undeclared declarations this_suffix allow_this expression; + Hashtbl.clear declarations; + Hashtbl.iter ( Hashtbl.add declarations ) old_decs + ) cases; + (match default with | None -> () + | Some expr -> + find_undeclared_variables undeclared declarations this_suffix allow_this expr; + ); *) + | TFor (tvar, init, loop) -> + let old_decs = Hashtbl.copy declarations in + Hashtbl.add declarations (keyword_remap tvar.v_name) (); + find_undeclared_variables undeclared declarations this_suffix allow_this init; + find_undeclared_variables undeclared declarations this_suffix allow_this loop; + Hashtbl.clear declarations; + Hashtbl.iter ( Hashtbl.add declarations ) old_decs + | TConst TSuper + | TConst TThis -> + if ((not (Hashtbl.mem declarations "this")) && allow_this) then + Hashtbl.replace undeclared "this" (type_string_suff this_suffix expression.etype true) + | TBlock expr_list -> + let old_decs = Hashtbl.copy declarations in + List.iter (find_undeclared_variables undeclared declarations this_suffix allow_this ) expr_list; + (* what is the best way for this ? *) + Hashtbl.clear declarations; + Hashtbl.iter ( Hashtbl.add declarations ) old_decs + | _ -> Type.iter (find_undeclared_variables undeclared declarations this_suffix allow_this) expression + in + find_undeclared_variables undeclared declarations this_suffix allow_this expression ;; let rec is_dynamic_in_cpp ctx expr = - let expr_type = type_string ( match follow expr.etype with TFun (args,ret) -> ret | _ -> expr.etype) in + let expr_type = type_string ( match follow expr.etype with TFun (args,ret) -> ret | _ -> expr.etype) in ctx.ctx_dbgout ( "/* idic: " ^ expr_type ^ " */" ); - if ( expr_type="Dynamic" ) then - true - else begin - let result = ( - match expr.eexpr with - | TField( obj, field ) -> - let name = field_name field in - ctx.ctx_dbgout ("/* ?tfield "^name^" */"); - if (is_dynamic_member_lookup_in_cpp ctx obj name) then + if ( expr_type="Dynamic" || expr_type="cpp::ArrayBase") then + true + else begin + let result = ( + match expr.eexpr with + | TEnumParameter( obj, _, index ) -> + true (* TODO? *) + | TField( obj, field ) -> + let name = field_name field in + ctx.ctx_dbgout ("/* ?tfield "^name^" */"); + if (is_dynamic_member_lookup_in_cpp ctx obj field) then ( ctx.ctx_dbgout "/* tf=dynobj */"; true ) - else if (is_dynamic_member_return_in_cpp ctx obj name) then + else if (is_dynamic_member_return_in_cpp ctx obj field) then ( ctx.ctx_dbgout "/* tf=dynret */"; true @@ -959,96 +1324,109 @@ let rec is_dynamic_in_cpp ctx expr = ctx.ctx_dbgout "/* tf=notdyn */"; false ) - | TConst TThis when ((not ctx.ctx_real_this_ptr) && ctx.ctx_dynamic_this_ptr) -> - ctx.ctx_dbgout ("/* dthis */"); true - | TArray (obj,index) -> let dyn = is_dynamic_in_cpp ctx obj in - ctx.ctx_dbgout ("/* aidr:" ^ (if dyn then "Dyn" else "Not") ^ " */"); - dyn; - | TTypeExpr _ -> false - | TCall(func,args) -> - (match follow func.etype with + | TConst TThis when ((not ctx.ctx_real_this_ptr) && ctx.ctx_dynamic_this_ptr) -> + ctx.ctx_dbgout ("/* dthis */"); true + | TArray (obj,index) -> let dyn = is_dynamic_in_cpp ctx obj in + ctx.ctx_dbgout ("/* aidr:" ^ (if dyn then "Dyn" else "Not") ^ " */"); + dyn; + | TTypeExpr _ -> false + | TCall(func,args) -> + (match follow func.etype with | TFun (args,ret) -> ctx.ctx_dbgout ("/* ret = "^ (type_string ret) ^" */"); - is_dynamic_in_cpp ctx func + is_dynamic_in_cpp ctx func | _ -> ctx.ctx_dbgout "/* not TFun */"; true - ); - | TParenthesis(expr) -> is_dynamic_in_cpp ctx expr - | TCast (e,None) -> is_dynamic_in_cpp ctx e - | TLocal { v_name = "__global__" } -> false - | TConst TNull -> true - | _ -> ctx.ctx_dbgout "/* other */"; false (* others ? *) ) - in - ctx.ctx_dbgout (if result then "/* Y */" else "/* N */" ); - result - end - -and is_dynamic_member_lookup_in_cpp ctx field_object member = + ); + | TParenthesis(expr) | TMeta(_,expr) -> is_dynamic_in_cpp ctx expr + | TCast (e,None) -> (type_string expr.etype) = "Dynamic" + | TLocal { v_name = "__global__" } -> false + | TConst TNull -> true + | _ -> ctx.ctx_dbgout "/* other */"; false (* others ? *) ) + in + ctx.ctx_dbgout (if result then "/* Y */" else "/* N */" ); + result + end + +and is_dynamic_member_lookup_in_cpp ctx field_object field = + let member = field_name field in ctx.ctx_dbgout ("/*mem."^member^".*/"); - if (is_internal_member member) then false else - if (match field_object.eexpr with | TTypeExpr _ -> ctx.ctx_dbgout "/*!TTypeExpr*/"; true | _ -> false) then false else - if (is_dynamic_in_cpp ctx field_object) then true else - if (is_array field_object.etype) then false else ( - let tstr = type_string field_object.etype in + if (is_internal_member member) then false else + if (is_pointer field_object.etype true) then false else + if (match field_object.eexpr with | TTypeExpr _ -> ctx.ctx_dbgout "/*!TTypeExpr*/"; true | _ -> false) then false else + if (is_dynamic_in_cpp ctx field_object) then true else + if (is_array field_object.etype) then false else ( + let tstr = type_string field_object.etype in ctx.ctx_dbgout ("/* ts:"^tstr^"*/"); - match tstr with - (* Internal classes have no dynamic members *) - | "::String" | "Null" | "::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> ctx.ctx_dbgout ("/* ok:" ^ (type_string field_object.etype) ^ " */"); false - | "Dynamic" -> true - | name -> - let full_name = name ^ "." ^ member in - ctx.ctx_dbgout ("/* t:" ^ full_name ^ " */"); - try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in - ctx.ctx_dbgout ("/* =" ^ mem_type ^ "*/"); - false ) - with Not_found -> true + match tstr with + (* Internal classes have no dynamic members *) + | "::String" | "Null" | "::hx::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> ctx.ctx_dbgout ("/* ok:" ^ (type_string field_object.etype) ^ " */"); false + | "Dynamic" -> true + | name -> + let full_name = name ^ "." ^ member in + ctx.ctx_dbgout ("/* t:" ^ full_name ^ " */"); + try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in + ctx.ctx_dbgout ("/* =" ^ mem_type ^ "*/"); + false ) + with Not_found -> not (is_extern_class_instance field_object) ) -and is_dynamic_member_return_in_cpp ctx field_object member = - if (is_array field_object.etype) then false else - if (is_internal_member member) then false else +and is_dynamic_member_return_in_cpp ctx field_object field = + let member = field_name field in + if (is_array field_object.etype) then false else + if (is_pointer field_object.etype true) then false else + if (is_internal_member member) then false else match field_object.eexpr with | TTypeExpr t -> let full_name = "::" ^ (join_class_path (t_path t) "::" ) ^ "." ^ member in - ctx.ctx_dbgout ("/*static:"^ full_name^"*/"); - ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic" ) - with Not_found -> true ) + ctx.ctx_dbgout ("/*static:"^ full_name^"*/"); + ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic"||mem_type="cpp::ArrayBase" ) + with Not_found -> true ) | _ -> - let tstr = type_string field_object.etype in - (match tstr with - (* Internal classes have no dynamic members *) - | "::String" | "Null" | "::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> false - | "Dynamic" -> ctx.ctx_dbgout "/*D*/"; true - | name -> - let full_name = name ^ "." ^ member in - ctx.ctx_dbgout ("/*R:"^full_name^"*/"); - try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic" ) - with Not_found -> true ) + let tstr = type_string field_object.etype in + (match tstr with + (* Internal classes have no dynamic members *) + | "::String" | "Null" | "::hx::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> false + | "Dynamic" | "cpp::ArrayBase" -> ctx.ctx_dbgout "/*D*/"; true + | name -> + let full_name = name ^ "." ^ member in + ctx.ctx_dbgout ("/*R:"^full_name^"*/"); + try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic"||mem_type="cpp::ArrayBase" ) + with Not_found -> true ) ;; let cast_if_required ctx expr to_type = - let expr_type = (type_string expr.etype) in + let expr_type = (type_string expr.etype) in ctx.ctx_dbgout ( "/* cir: " ^ expr_type ^ " */" ); if (is_dynamic_in_cpp ctx expr) then ctx.ctx_output (".Cast< " ^ to_type ^ " >()" ) ;; +let is_matching_interface_type t0 t1 = + (match (follow t0),(follow t1) with + | TInst (k0,_), TInst(k1,_) -> k0==k1 + | _ -> false + ) +;; + + + let default_value_string = function - | TInt i -> Printf.sprintf "%ld" i - | TFloat float_as_string -> float_as_string - | TString s -> str s - | TBool b -> (if b then "true" else "false") - | TNull -> "null()" - | _ -> "/* Hmmm */" + | TInt i -> Printf.sprintf "%ld" i + | TFloat float_as_string -> "((Float)" ^ float_as_string ^ ")" + | TString s -> str s + | TBool b -> (if b then "true" else "false") + | TNull -> "null()" + | _ -> "/* Hmmm */" ;; let generate_default_values ctx args prefix = - List.iter ( fun (v,o) -> let type_str = type_string v.v_type in + List.iter ( fun (v,o) -> let type_str = type_string v.v_type in let name = (keyword_remap v.v_name) in - match o with - | Some TNull -> () - | Some const -> - ctx.ctx_output (type_str ^ " " ^ name ^ " = " ^ prefix ^ name ^ ".Default(" ^ - (default_value_string const) ^ ");\n") - | _ -> () ) args;; + match o with + | Some TNull -> () + | Some const -> + ctx.ctx_output (type_str ^ " " ^ name ^ " = " ^ prefix ^ name ^ ".Default(" ^ + (default_value_string const) ^ ");\n") + | _ -> () ) args;; let return_type_string t = match t with @@ -1056,35 +1434,43 @@ let return_type_string t = | _ -> "" ;; + +let get_return_type field = + match follow field.cf_type with + | TFun (_,return_type) -> return_type + | _ -> raise Not_found +;; + + (* let rec has_side_effects expr = match expr.eexpr with - | TConst _ | TLocal _ | TFunction _ | TTypeExpr _ -> false - | TUnop(Increment,_,_) | TUnop(Decrement,_,_) | TBinop(OpAssign,_,_) | TBinop(OpAssignOp _,_,_) -> true - | TUnop(_,_,e) -> has_side_effects e - | TArray(e1,e2) | TBinop(_,e1,e2) -> has_side_effects e1 || has_side_effects e2 - | TIf(cond,e1,Some e2) -> has_side_effects cond || has_side_effects e1 || has_side_effects e2 - | TField(e,_) | TParenthesis e -> has_side_effects e - | TArrayDecl el -> List.exists has_side_effects el - | TObjectDecl decls -> List.exists (fun (_,e) -> has_side_effects e) decls - | TCast(e,_) -> has_side_effects e - | _ -> true + | TConst _ | TLocal _ | TFunction _ | TTypeExpr _ -> false + | TUnop(Increment,_,_) | TUnop(Decrement,_,_) | TBinop(OpAssign,_,_) | TBinop(OpAssignOp _,_,_) -> true + | TUnop(_,_,e) -> has_side_effects e + | TArray(e1,e2) | TBinop(_,e1,e2) -> has_side_effects e1 || has_side_effects e2 + | TIf(cond,e1,Some e2) -> has_side_effects cond || has_side_effects e1 || has_side_effects e2 + | TField(e,_) | TParenthesis e -> has_side_effects e + | TArrayDecl el -> List.exists has_side_effects el + | TObjectDecl decls -> List.exists (fun (_,e) -> has_side_effects e) decls + | TCast(e,_) -> has_side_effects e + | _ -> true ;; let rec can_be_affected expr = match expr.eexpr with - | TConst _ | TFunction _ | TTypeExpr _ -> false - | TLocal _ -> true - | TUnop(Increment,_,_) | TUnop(Decrement,_,_) -> true - | TUnop(_,_,e) -> can_be_affected e - | TBinop(OpAssign,_,_) | TBinop(OpAssignOp _,_,_) -> true - | TBinop(_,e1,e2) -> can_be_affected e1 || can_be_affected e2 - | TField(e,_) -> can_be_affected e - | TParenthesis e -> can_be_affected e - | TCast(e,_) -> can_be_affected e - | TArrayDecl el -> List.exists can_be_affected el - | TObjectDecl decls -> List.exists (fun (_,e) -> can_be_affected e) decls - | _ -> true + | TConst _ | TFunction _ | TTypeExpr _ -> false + | TLocal _ -> true + | TUnop(Increment,_,_) | TUnop(Decrement,_,_) -> true + | TUnop(_,_,e) -> can_be_affected e + | TBinop(OpAssign,_,_) | TBinop(OpAssignOp _,_,_) -> true + | TBinop(_,e1,e2) -> can_be_affected e1 || can_be_affected e2 + | TField(e,_) -> can_be_affected e + | TParenthesis e -> can_be_affected e + | TCast(e,_) -> can_be_affected e + | TArrayDecl el -> List.exists can_be_affected el + | TObjectDecl decls -> List.exists (fun (_,e) -> can_be_affected e) decls + | _ -> true ;; @@ -1093,7 +1479,7 @@ let call_has_side_effects func args = let affected = (if can_be_affected func then 1 else 0) + (List.length (List.filter can_be_affected args)) in effects + affected > 22; ;; - The above code may be overly pessimistic - will have to check performance + The above code may be overly pessimistic - will have to check performance *) @@ -1104,453 +1490,509 @@ let call_has_side_effects func args = false;; let has_default_values args = - List.exists ( fun (_,o) -> match o with + List.exists ( fun (_,o) -> match o with | Some TNull -> false | Some _ -> true | _ -> false ) args ;; exception PathFound of string;; + +let strip_file ctx file = (match Common.defined ctx Common.Define.AbsolutePath with + | true -> file + | false -> let flen = String.length file in + (* Not quite right - should probably test is file exists *) + try + List.iter (fun path -> + let plen = String.length path in + if (flen>plen && path=(String.sub file 0 plen )) + then raise (PathFound (String.sub file plen (flen-plen)) ) ) + (ctx.class_path @ ctx.std_path); + file; + with PathFound tail -> + tail) +;; + let hx_stack_push ctx output clazz func_name pos = - let file = pos.pfile in - let flen = String.length file in - (* Not quite right - should probably test is file exists *) - let stripped_file = try - List.iter (fun path -> - let plen = String.length path in - if (flen>plen && path=(String.sub file 0 plen )) - then raise (PathFound (String.sub file plen (flen-plen)) ) ) - (ctx.ctx_common.class_path @ ctx.ctx_common.std_path); - file; - with PathFound tail -> tail in - let qfile = "\"" ^ (Ast.s_escape stripped_file) ^ "\"" in - ctx.ctx_file_info := PMap.add qfile qfile !(ctx.ctx_file_info); - if (ctx.ctx_dump_stack_line) then - output ("HX_STACK_PUSH(\"" ^ clazz ^ "::" ^ func_name ^ "\"," ^ qfile ^ "," - ^ (string_of_int (Lexer.get_error_line pos) ) ^ ");\n") + if ctx.ctx_debug_level > 0 then begin + let stripped_file = strip_file ctx.ctx_common pos.pfile in + let qfile = "\"" ^ (Ast.s_escape stripped_file) ^ "\"" in + ctx.ctx_file_info := PMap.add stripped_file pos.pfile !(ctx.ctx_file_info); + if (ctx.ctx_debug_level>0) then begin + let hash_class_func = gen_hash 0 (clazz^"."^func_name) in + let hash_file = gen_hash 0 stripped_file in + output ("HX_STACK_FRAME(\"" ^ clazz ^ "\",\"" ^ func_name ^ "\"," ^ hash_class_func ^ ",\"" ^ + clazz ^ "." ^ func_name ^ "\"," ^ qfile ^ "," ^ + (string_of_int (Lexer.get_error_line pos) ) ^ "," ^ hash_file ^ ")\n") + end + end ;; (* - This is the big one. - Once you get inside a function, all code is generated (recursively) as a "expression". - "retval" is tracked to determine whether the value on an expression is actually used. - eg, if the result of a block (ie, the last expression in the list) is used, then - we have to do some funky stuff to generate a local function. - Some things that change less often are stored in the context and are extracted - at the top for simplicity. + This is the big one. + Once you get inside a function, all code is generated (recursively) as a "expression". + "retval" is tracked to determine whether the value on an expression is actually used. + eg, if the result of a block (ie, the last expression in the list) is used, then + we have to do some funky stuff to generate a local function. + Some things that change less often are stored in the context and are extracted + at the top for simplicity. *) let rec define_local_function_ctx ctx func_name func_def = - let writer = ctx.ctx_writer in - let output_i = writer#write_i in - let output = ctx.ctx_output in - let remap_this = function | "this" -> "__this" | other -> other in - let rec define_local_function func_name func_def = - let declarations = Hashtbl.create 0 in - let undeclared = Hashtbl.create 0 in - (* '__global__', '__cpp__' are always defined *) - Hashtbl.add declarations "__global__" (); - Hashtbl.add declarations "__cpp__" (); - Hashtbl.add declarations "__trace" (); - (* Add args as defined variables *) - List.iter ( fun (arg_var, opt_val) -> - if (ctx.ctx_debug) then - output ("/* found arg " ^ arg_var.v_name ^ " = " ^ (type_string arg_var.v_type) ^" */ "); - Hashtbl.add declarations (keyword_remap arg_var.v_name) () ) func_def.tf_args; - find_undeclared_variables_ctx ctx undeclared declarations "" true func_def.tf_expr; - - let has_this = Hashtbl.mem undeclared "this" in - if (has_this) then Hashtbl.remove undeclared "this"; - let typed_vars = hash_iterate undeclared (fun key value -> value ^ "," ^ (keyword_remap key) ) in - let func_name_sep = func_name ^ (if List.length typed_vars > 0 then "," else "") in - output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ (list_num typed_vars) ^ "(" ^ + let writer = ctx.ctx_writer in + let output_i = writer#write_i in + let output = ctx.ctx_output in + let remap_this = function | "this" -> "__this" | other -> other in + let rec define_local_function func_name func_def = + let declarations = Hashtbl.create 0 in + let undeclared = Hashtbl.create 0 in + (* '__global__', '__cpp__' are always defined *) + Hashtbl.add declarations "__global__" (); + Hashtbl.add declarations "__cpp__" (); + Hashtbl.add declarations "__trace" (); + (* Add args as defined variables *) + List.iter ( fun (arg_var, opt_val) -> + if (ctx.ctx_debug_level>1) then + output ("/* found arg " ^ arg_var.v_name ^ " = " ^ (type_string arg_var.v_type) ^" */ "); + Hashtbl.add declarations (keyword_remap arg_var.v_name) () ) func_def.tf_args; + find_undeclared_variables_ctx ctx undeclared declarations "" true func_def.tf_expr; + + let has_this = Hashtbl.mem undeclared "this" in + if (has_this) then Hashtbl.remove undeclared "this"; + let typed_vars = hash_iterate undeclared (fun key value -> value ^ "," ^ (keyword_remap key) ) in + let func_name_sep = func_name ^ (if List.length typed_vars > 0 then "," else "") in + output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ (list_num typed_vars) ^ "(" ^ (if has_this then "hx::LocalThisFunc," else "hx::LocalFunc,") ^ func_name_sep ^ - (String.concat "," typed_vars) ^ ")\n" ); + (String.concat "," typed_vars) ^ ")\n" ); + output_i ("int __ArgCount() const { return " ^ (string_of_int (List.length func_def.tf_args)) ^"; }\n"); - (* actual function, called "run" *) - let args_and_types = List.map - (fun (v,_) -> (type_string v.v_type) ^ " " ^ (keyword_remap v.v_name) ) func_def.tf_args in - let block = is_block func_def.tf_expr in - let func_type = type_string func_def.tf_type in - output_i (func_type ^ " run(" ^ (gen_arg_list func_def.tf_args "__o_") ^ ")"); + (* actual function, called "run" *) + let args_and_types = List.map + (fun (v,_) -> (type_string v.v_type) ^ " " ^ (keyword_remap v.v_name) ) func_def.tf_args in + let block = is_block func_def.tf_expr in + let func_type = type_string func_def.tf_type in + output_i (func_type ^ " run(" ^ (gen_arg_list func_def.tf_args "__o_") ^ ")"); - let close_defaults = + let close_defaults = if (has_default_values func_def.tf_args) then begin - writer#begin_block; - output_i ""; - generate_default_values ctx func_def.tf_args "__o_"; - output_i ""; + writer#begin_block; + output_i ""; + generate_default_values ctx func_def.tf_args "__o_"; + output_i ""; true; end else false in - let pop_real_this_ptr = clear_real_this_ptr ctx true in + let pop_real_this_ptr = clear_real_this_ptr ctx true in - writer#begin_block; - hx_stack_push ctx output_i "*" func_name func_def.tf_expr.epos; - if (has_this && ctx.ctx_dump_stack_line) then - output_i ("HX_STACK_THIS(__this.mPtr);\n"); - List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") ) + writer#begin_block; + if (ctx.ctx_debug_level>0) then begin + hx_stack_push ctx output_i "*" func_name func_def.tf_expr.epos; + if (has_this && ctx.ctx_debug_level>0) then + output_i ("HX_STACK_THIS(__this.mPtr)\n"); + List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\")\n") ) func_def.tf_args; + end; + + if (block) then begin + output_i ""; + gen_expression ctx false func_def.tf_expr; + output_i "return null();\n"; + end else begin + (* Save old values, and equalize for new input ... *) + let pop_names = push_anon_names ctx in + + find_local_functions_and_return_blocks_ctx ctx false func_def.tf_expr; + + (match func_def.tf_expr.eexpr with + | TReturn (Some return_expression) when (func_type<>"Void") -> + output_i "return "; + gen_expression ctx true return_expression; + | TReturn (Some return_expression) -> + output_i ""; + gen_expression ctx false return_expression; + | _ -> + output_i ""; + gen_expression ctx false (to_block func_def.tf_expr); + ); + output ";\n"; + output_i "return null();\n"; + pop_names(); + end; + writer#end_block; + + if close_defaults then writer#end_block; + pop_real_this_ptr(); + + let return = if (type_string func_def.tf_type ) = "Void" then "(void)" else "return" in + output_i ("HX_END_LOCAL_FUNC" ^ (list_num args_and_types) ^ "(" ^ return ^ ")\n\n"); - if (block) then begin - output_i ""; - gen_expression ctx false func_def.tf_expr; - output_i "return null();\n"; - end else begin - (* Save old values, and equalize for new input ... *) - let pop_names = push_anon_names ctx in - - find_local_functions_and_return_blocks_ctx ctx false func_def.tf_expr; - - (match func_def.tf_expr.eexpr with - | TReturn (Some return_expression) when (func_type<>"Void") -> - output_i "return "; - gen_expression ctx true return_expression; - | TReturn (Some return_expression) -> - output_i ""; - gen_expression ctx false return_expression; - | _ -> - output_i ""; - gen_expression ctx false (to_block func_def.tf_expr); - ); - output ";\n"; - output_i "return null();\n"; - pop_names(); - end; - writer#end_block; - - if close_defaults then writer#end_block; - pop_real_this_ptr(); - - let return = if (type_string func_def.tf_type ) = "Void" then "(void)" else "return" in - output_i ("HX_END_LOCAL_FUNC" ^ (list_num args_and_types) ^ "(" ^ return ^ ")\n\n"); - - Hashtbl.replace ctx.ctx_local_function_args func_name - (if (ctx.ctx_real_this_ptr) then - String.concat "," (hash_keys undeclared) - else - String.concat "," (List.map remap_this (hash_keys undeclared)) ) - in - define_local_function func_name func_def + Hashtbl.replace ctx.ctx_local_function_args func_name + (if (ctx.ctx_real_this_ptr) then + String.concat "," (hash_keys undeclared) + else + String.concat "," (List.map remap_this (hash_keys undeclared)) ) + in + define_local_function func_name func_def and find_local_functions_and_return_blocks_ctx ctx retval expression = - let output = ctx.ctx_output in - let rec find_local_functions_and_return_blocks retval expression = - match expression.eexpr with - | TBlock _ -> - if (retval) then begin - define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true; - end (* else we are done *) - | TMatch (_, _, _, _) - | TTry (_, _) - | TSwitch (_, _, _) when retval -> - define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true; + let output = ctx.ctx_output in + let rec find_local_functions_and_return_blocks retval expression = + match expression.eexpr with + | TBlock _ -> + if (retval) then begin + define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true; + end (* else we are done *) + | TTry (_, _) + | TSwitch (_, _, _) when retval -> + define_local_return_block_ctx ctx expression (next_anon_function_name ctx) true; | TObjectDecl ( ("fileName" , { eexpr = (TConst (TString file)) }) :: ("lineNumber" , { eexpr = (TConst (TInt line)) }) :: ("className" , { eexpr = (TConst (TString class_name)) }) :: ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) -> () - | TObjectDecl decl_list -> - let name = next_anon_function_name ctx in - define_local_return_block_ctx ctx expression name true; - | TCall(func,args) when call_has_side_effects func args -> - define_local_return_block_ctx ctx expression (next_anon_function_name ctx) retval - (*| TCall (e,el) -> (* visit function object first, then args *) - find_local_functions_and_return_blocks e; - List.iter find_local_functions_and_return_blocks el *) - | TFunction func -> - let func_name = next_anon_function_name ctx in - output "\n"; - define_local_function_ctx ctx func_name func - | TField (obj,_) when (is_null obj) -> ( ) - | TArray (obj,_) when (is_null obj) -> ( ) - | TIf ( _ , _ , _ ) when retval -> (* ? operator style *) - iter_retval find_local_functions_and_return_blocks retval expression - | TMatch (_, _, _, _) - | TSwitch (_, _, _) when retval -> ( ) - | TMatch ( cond , _, _, _) - | TWhile ( cond , _, _ ) - | TIf ( cond , _, _ ) - | TSwitch ( cond , _, _) -> iter_retval find_local_functions_and_return_blocks true cond - | _ -> iter_retval find_local_functions_and_return_blocks retval expression - in find_local_functions_and_return_blocks retval expression + | TObjectDecl decl_list -> + let name = next_anon_function_name ctx in + define_local_return_block_ctx ctx expression name true; + | TCall(func,args) when call_has_side_effects func args -> + define_local_return_block_ctx ctx expression (next_anon_function_name ctx) retval + (*| TCall (e,el) -> (* visit function object first, then args *) + find_local_functions_and_return_blocks e; + List.iter find_local_functions_and_return_blocks el *) + | TFunction func -> + let func_name = next_anon_function_name ctx in + output "\n"; + define_local_function_ctx ctx func_name func + | TField (obj,_) | TEnumParameter (obj,_,_) when (is_null obj) -> ( ) + | TArray (obj,_) when (is_null obj) -> ( ) + | TIf ( _ , _ , _ ) when retval -> (* ? operator style *) + iter_retval find_local_functions_and_return_blocks retval expression + | TSwitch (_, _, _) when retval -> ( ) + (* | TMatch ( cond , _, _, _) *) + | TWhile ( cond , _, _ ) + | TIf ( cond , _, _ ) + | TSwitch ( cond , _, _) -> iter_retval find_local_functions_and_return_blocks true cond + | _ -> iter_retval find_local_functions_and_return_blocks retval expression + in find_local_functions_and_return_blocks retval expression and define_local_return_block_ctx ctx expression name retval = - let writer = ctx.ctx_writer in - let output_i = writer#write_i in - let output = ctx.ctx_output in - let check_this = function | "this" when not ctx.ctx_real_this_ptr -> "__this" | x -> x in - let reference = function | "this" -> " *__this" | "_this" -> " _this" | name -> " &" ^name in - let rec define_local_return_block expression = - let declarations = Hashtbl.create 0 in - let undeclared = Hashtbl.create 0 in - (* '__global__' is always defined *) - Hashtbl.add declarations "__global__" (); - Hashtbl.add declarations "__cpp__" (); - Hashtbl.add declarations "__trace" (); - find_undeclared_variables_ctx ctx undeclared declarations "_obj" true expression; - - let vars = (hash_keys undeclared) in - let args = String.concat "," (List.map check_this (hash_keys undeclared)) in - Hashtbl.replace ctx.ctx_local_return_block_args name args; - output_i ("struct " ^ name); - writer#begin_block; - let ret_type = if (not retval) then "Void" else - match expression.eexpr with - | TObjectDecl _ -> "Dynamic" - | _ -> type_string expression.etype in - output_i ("inline static " ^ ret_type ^ " Block( "); - output (String.concat "," ( (List.map (fun var -> - (Hashtbl.find undeclared var) ^ (reference var)) ) vars)); - output (")"); - let return_data = ret_type <> "Void" in - writer#begin_block; + let writer = ctx.ctx_writer in + let output_i = writer#write_i in + let output = ctx.ctx_output in + let check_this = function | "this" when not ctx.ctx_real_this_ptr -> "__this" | x -> x in + let rec define_local_return_block expression = + let declarations = Hashtbl.create 0 in + let undeclared = Hashtbl.create 0 in + (* '__global__' is always defined *) + Hashtbl.add declarations "__global__" (); + Hashtbl.add declarations "__cpp__" (); + Hashtbl.add declarations "__trace" (); + find_undeclared_variables_ctx ctx undeclared declarations "_obj" true expression; + + let vars = (hash_keys undeclared) in + let args = String.concat "," (List.map check_this (hash_keys undeclared)) in + Hashtbl.replace ctx.ctx_local_return_block_args name args; + output_i ("struct " ^ name); + writer#begin_block; + let ret_type = if (not retval) then "Void" else + match expression.eexpr with + | TObjectDecl _ -> "Dynamic" + | _ -> type_string expression.etype in + (* TODO - analyse usage *) + let pass_by_value name = (String.length name >=5 ) && (String.sub name 0 5 = "_this") in + output_i ("inline static " ^ ret_type ^ " Block( "); + output (String.concat "," ( + (List.map + (fun var -> + let var_type = Hashtbl.find undeclared var in + (* Args passed into inline-block should be references, so they can be changed. + Fake 'this' pointers can't be changed, so needn't be references *) + match var with + | "this" -> "hx::ObjectPtr< " ^ var_type ^ " > __this" + | name when (pass_by_value name) -> var_type ^ " " ^ name + | name -> var_type ^ " &" ^name + ) vars) ) ); + output (")"); + let return_data = ret_type <> "Void" in + writer#begin_block; hx_stack_push ctx output_i "*" "closure" expression.epos; - output_i ""; - - let pop_real_this_ptr = clear_real_this_ptr ctx false in - (match expression.eexpr with - | TObjectDecl decl_list -> - writer#begin_block; - output_i "hx::Anon __result = hx::Anon_obj::Create();\n"; - let pop_names = push_anon_names ctx in - List.iter (function (name,value) -> - find_local_functions_and_return_blocks_ctx ctx true value; - output_i ( "__result->Add(" ^ (str name) ^ " , "); - gen_expression ctx true value; - output (if is_function_expr value then ",true" else ",false" ); - output (");\n"); - ) decl_list; - pop_names(); - output_i "return __result;\n"; - writer#end_block; - | TBlock _ -> - ctx.ctx_return_from_block <- return_data; - ctx.ctx_return_from_internal_node <- false; - gen_expression ctx false expression; - | TCall(func,args) -> - writer#begin_block; - let pop_names = push_anon_names ctx in - find_local_functions_and_return_blocks_ctx ctx true func; - List.iter (find_local_functions_and_return_blocks_ctx ctx true) args; - ctx.ctx_tcall_expand_args <- true; - gen_expression ctx return_data expression; - output ";\n"; - pop_names(); - writer#end_block; - | _ -> - ctx.ctx_return_from_block <- false; - ctx.ctx_return_from_internal_node <- return_data; - gen_expression ctx false (to_block expression); - ); - output_i "return null();\n"; - writer#end_block; - pop_real_this_ptr(); - writer#end_block_line; - output ";\n"; - in - define_local_return_block expression + output_i ""; + + let pop_real_this_ptr = clear_real_this_ptr ctx false in + (match expression.eexpr with + | TObjectDecl decl_list -> + writer#begin_block; + output_i "hx::Anon __result = hx::Anon_obj::Create();\n"; + let pop_names = push_anon_names ctx in + List.iter (function (name,value) -> + find_local_functions_and_return_blocks_ctx ctx true value; + output_i ( "__result->Add(" ^ (str name) ^ " , "); + gen_expression ctx true value; + output (if is_function_expr value then ",true" else ",false" ); + output (");\n"); + ) decl_list; + pop_names(); + output_i "return __result;\n"; + writer#end_block; + | TBlock _ -> + ctx.ctx_return_from_block <- return_data; + ctx.ctx_return_from_internal_node <- false; + gen_expression ctx false expression; + | TCall(func,args) -> + writer#begin_block; + let pop_names = push_anon_names ctx in + find_local_functions_and_return_blocks_ctx ctx true func; + List.iter (find_local_functions_and_return_blocks_ctx ctx true) args; + ctx.ctx_tcall_expand_args <- true; + gen_expression ctx return_data expression; + output ";\n"; + pop_names(); + writer#end_block; + | _ -> + ctx.ctx_return_from_block <- false; + ctx.ctx_return_from_internal_node <- return_data; + gen_expression ctx false (to_block expression); + ); + output_i "return null();\n"; + writer#end_block; + pop_real_this_ptr(); + writer#end_block_line; + output ";\n"; + in + define_local_return_block expression and gen_expression ctx retval expression = - let output = ctx.ctx_output in - let writer = ctx.ctx_writer in - let output_i = writer#write_i in - let calling = ctx.ctx_calling in - ctx.ctx_calling <- false; - let assigning = ctx.ctx_assigning in - ctx.ctx_assigning <- false; - let return_from_block = ctx.ctx_return_from_block in - ctx.ctx_return_from_block <- false; - let tcall_expand_args = ctx.ctx_tcall_expand_args in - ctx.ctx_tcall_expand_args <- false; - let return_from_internal_node = ctx.ctx_return_from_internal_node in - ctx.ctx_return_from_internal_node <- false; - let dump_src_pos = ctx.ctx_dump_src_pos in - ctx.ctx_dump_src_pos <- (fun() -> ()); - - (* Annotate source code with debug - can get a bit verbose. Mainly for debugging code gen, - rather than the run time *) - if (ctx.ctx_debug) then begin - (*if calling then output "/* Call */";*) - (*if ctx.ctx_real_this_ptr then output "/* this */" else output "/* FAKE __this */";*) - output (debug_expression expression ctx.ctx_debug_type); - end; - - (* Write comma separated list of variables - useful for function args. *) - let rec gen_expression_list expressions = - (match expressions with - | [] -> () - | [single] -> gen_expression ctx true single - | first :: remaining -> - gen_expression ctx true first; - output ","; - gen_expression_list remaining - ) in - - let rec gen_bin_op_string expr1 op expr2 = - let cast = (match op with - | ">>" | "<<" | "&" | "|" | "^" -> "int(" - | "&&" | "||" -> "bool(" - | "/" -> "Float(" - | _ -> "") in - if (op <> "=") then output "("; - if ( cast <> "") then output cast; - gen_expression ctx true expr1; - if ( cast <> "") then output ")"; - - output (" " ^ op ^ " "); - - if ( cast <> "") then output cast; - gen_expression ctx true expr2; - if ( cast <> "") then output ")"; - if (op <> "=") then output ")"; - in - let rec gen_bin_op op expr1 expr2 = - match op with - | Ast.OpAssign -> ctx.ctx_assigning <- true; - gen_bin_op_string expr1 "=" expr2 - | Ast.OpUShr -> - output "hx::UShr("; - gen_expression ctx true expr1; - output ","; - gen_expression ctx true expr2; - output ")"; - | Ast.OpMod -> - output "hx::Mod("; - gen_expression ctx true expr1; - output ","; - gen_expression ctx true expr2; - output ")"; - - | Ast.OpAssignOp bin_op -> - output (match bin_op with - | Ast.OpAdd -> "hx::AddEq(" - | Ast.OpMult -> "hx::MultEq(" - | Ast.OpDiv -> "hx::DivEq(" - | Ast.OpSub -> "hx::SubEq(" - | Ast.OpAnd -> "hx::AndEq(" - | Ast.OpOr -> "hx::OrEq(" - | Ast.OpXor -> "hx::XorEq(" - | Ast.OpShl -> "hx::ShlEq(" - | Ast.OpShr -> "hx::ShrEq(" - | Ast.OpUShr -> "hx::UShrEq(" - | Ast.OpMod -> "hx::ModEq(" - | _ -> error "Unknown OpAssignOp" expression.epos ); - ctx.ctx_assigning <- true; - gen_expression ctx true expr1; - output ","; - gen_expression ctx true expr2; - output ")" - | Ast.OpNotEq -> gen_bin_op_string expr1 "!=" expr2 - | Ast.OpEq -> gen_bin_op_string expr1 "==" expr2 - | _ -> gen_bin_op_string expr1 (Ast.s_binop op) expr2 - in - - let gen_array_cast cast_name real_type call = - output (cast_name ^ "< " ^ real_type ^ " >" ^ call) + let output = ctx.ctx_output in + let writer = ctx.ctx_writer in + let output_i = writer#write_i in + let calling = ctx.ctx_calling in + ctx.ctx_calling <- false; + let assigning = ctx.ctx_assigning in + ctx.ctx_assigning <- false; + let return_from_block = ctx.ctx_return_from_block in + ctx.ctx_return_from_block <- false; + let tcall_expand_args = ctx.ctx_tcall_expand_args in + ctx.ctx_tcall_expand_args <- false; + let return_from_internal_node = ctx.ctx_return_from_internal_node in + ctx.ctx_return_from_internal_node <- false; + let dump_src_pos = ctx.ctx_dump_src_pos in + ctx.ctx_dump_src_pos <- (fun() -> ()); + + (* Annotate source code with debug - can get a bit verbose. Mainly for debugging code gen, + rather than the run time *) + if (ctx.ctx_debug_level>1) then begin + (*if calling then output "/* Call */";*) + (*if ctx.ctx_real_this_ptr then output "/* this */" else output "/* FAKE __this */";*) + output (debug_expression expression (ctx.ctx_debug_level>1) ); + end; + + (* Write comma separated list of variables - useful for function args. *) + let rec gen_expression_list expressions = + (match expressions with + | [] -> () + | [single] -> gen_expression ctx true single + | first :: remaining -> + gen_expression ctx true first; + output ","; + gen_expression_list remaining + ) in + + let rec gen_bin_op_string expr1 op expr2 = + let cast = (match op with + | ">>" | "<<" | "&" | "|" | "^" -> "int(" + | "&&" | "||" -> "bool(" + | "/" -> "Float(" + | _ -> "") in + if (op <> "=") then output "("; + if ( cast <> "") then output cast; + gen_expression ctx true expr1; + if ( cast <> "") then output ")"; + + output (" " ^ op ^ " "); + + if ( cast <> "") then output cast; + gen_expression ctx true expr2; + if ( cast <> "") then output ")"; + if (op <> "=") then output ")"; + in + let rec is_const_string_term expr = + match expr.eexpr with + | TConst( TString _ ) -> true + | TBinop (OpAdd,e1,e2) -> (is_const_string_term e1) && (is_const_string_term e2 ) + | _ -> false + in + let rec combine_string_terms expr = + match expr.eexpr with + | TConst( TString s ) -> s + | TBinop (OpAdd,e1,e2) -> (combine_string_terms e1) ^ (combine_string_terms e2 ) + | _ -> "" + in + let rec gen_bin_op op expr1 expr2 = + match op with + | Ast.OpAdd when (is_const_string_term expr1) && (is_const_string_term expr2) -> + output (str ((combine_string_terms expr1) ^ (combine_string_terms expr2)) ) + | Ast.OpAssign -> ctx.ctx_assigning <- true; + gen_bin_op_string expr1 "=" expr2 + | Ast.OpUShr -> + output "hx::UShr("; + gen_expression ctx true expr1; + output ","; + gen_expression ctx true expr2; + output ")"; + | Ast.OpMod -> + output "hx::Mod("; + gen_expression ctx true expr1; + output ","; + gen_expression ctx true expr2; + output ")"; + + | Ast.OpAssignOp bin_op -> + output (match bin_op with + | Ast.OpAdd -> "hx::AddEq(" + | Ast.OpMult -> "hx::MultEq(" + | Ast.OpDiv -> "hx::DivEq(" + | Ast.OpSub -> "hx::SubEq(" + | Ast.OpAnd -> "hx::AndEq(" + | Ast.OpOr -> "hx::OrEq(" + | Ast.OpXor -> "hx::XorEq(" + | Ast.OpShl -> "hx::ShlEq(" + | Ast.OpShr -> "hx::ShrEq(" + | Ast.OpUShr -> "hx::UShrEq(" + | Ast.OpMod -> "hx::ModEq(" + | _ -> error "Unknown OpAssignOp" expression.epos ); + ctx.ctx_assigning <- true; + gen_expression ctx true expr1; + output ","; + gen_expression ctx true expr2; + output ")" + | Ast.OpNotEq -> gen_bin_op_string expr1 "!=" expr2 + | Ast.OpEq -> gen_bin_op_string expr1 "==" expr2 + | _ -> gen_bin_op_string expr1 (Ast.s_binop op) expr2 + in + + let gen_array_cast cast_name real_type call = + output (cast_name ^ "< " ^ real_type ^ " >" ^ call) in - let rec check_array_element_cast array_type cast_name call = - match follow array_type with - | TInst (klass,[element]) -> + let rec check_array_element_cast array_type cast_name call = + match follow array_type with + | TInst (klass,[element]) -> ( match type_string element with - | x when cant_be_null x -> () - | "::String" | "Dynamic" -> () - | real_type -> gen_array_cast cast_name real_type call + | _ when is_struct_access element -> () + | x when cant_be_null element -> () + | _ when is_interface_type element -> () + | "::String" | "Dynamic" -> () + | real_type -> gen_array_cast cast_name real_type call ) - | TAbstract (abs,pl) when abs.a_impl <> None -> - check_array_element_cast (Codegen.Abstract.get_underlying_type abs pl) cast_name call + | TAbstract (abs,pl) when abs.a_impl <> None -> + check_array_element_cast (Abstract.get_underlying_type abs pl) cast_name call | _ -> () in - let rec check_array_cast array_type = - match follow array_type with - | TInst (klass,[element]) -> + let rec check_array_cast array_type = + match follow array_type with + | x when is_interface_type x -> () + | TInst (klass,[element]) -> let name = type_string element in - if ( is_object name ) then + if ( is_object name && not (is_interface_type element) ) then gen_array_cast ".StaticCast" "Array" "()" else gen_array_cast ".StaticCast" (type_string array_type) "()" - | TAbstract (abs,pl) when abs.a_impl <> None -> - check_array_cast (Codegen.Abstract.get_underlying_type abs pl) + | TAbstract (abs,pl) when abs.a_impl <> None -> + check_array_cast (Abstract.get_underlying_type abs pl) | _ -> () in - - let rec gen_tfield field_object field = + + let rec gen_tfield field_object field = let member = (field_name field) in - let remap_name = keyword_remap member in - let already_dynamic = ref false in - (match field_object.eexpr with - (* static access ... *) - | TTypeExpr type_def -> - let class_name = "::" ^ (join_class_path_remap (t_path type_def) "::" ) in - if (class_name="::String") then - output ("::String::" ^ remap_name) - else - output (class_name ^ "_obj::" ^ remap_name); - (* Special internal access *) - | TLocal { v_name = "__global__" } -> - output ("::" ^ member ) - | TConst TSuper -> output (if ctx.ctx_real_this_ptr then "this" else "__this"); - output ("->super::" ^ remap_name) - | TConst TThis when ctx.ctx_real_this_ptr -> output ( "this->" ^ remap_name ) - | TConst TNull -> output "null()" - | _ -> - gen_expression ctx true field_object; + let remap_name = keyword_remap member in + let already_dynamic = ref false in + (match field_object.eexpr with + (* static access ... *) + | TTypeExpr type_def -> + (match get_field_access_meta field Meta.Native with + | "" -> + let class_name = "::" ^ (join_class_path_remap (t_path type_def) "::" ) in + if (class_name="::String") then + output ("::String::" ^ remap_name) + else + output (class_name ^ "_obj::" ^ remap_name); + | native -> output native + ) + (* Special internal access *) + | TLocal { v_name = "__global__" } -> + output ("::" ^ member ) + | TConst TSuper -> output (if ctx.ctx_real_this_ptr then "this" else "__this"); + output ("->super::" ^ remap_name) + | TConst TThis when ctx.ctx_real_this_ptr -> output ( "this->" ^ remap_name ) + | TConst TNull -> output "null()" + | _ -> + gen_expression ctx true field_object; ctx.ctx_dbgout "/* TField */"; (* toString is the only internal member that can be set... *) let settingInternal = assigning && member="toString" in - if (is_internal_member member && not settingInternal) then begin - output ( "->" ^ member ); - end else if (settingInternal || is_dynamic_member_lookup_in_cpp ctx field_object member) then begin + let isString = (type_string field_object.etype)="::String" in + if (is_struct_access field_object.etype) then + output ( "." ^ member ) + else if (is_internal_member member && not settingInternal) then begin + output ( (if isString then "." else "->") ^ member ); + end else if (settingInternal || is_dynamic_member_lookup_in_cpp ctx field_object field) then begin if assigning then - output ( "->__FieldRef(" ^ (str member) ^ ")" ) + output ( "->__FieldRef(" ^ (str member) ^ ")" ) else - output ( "->__Field(" ^ (str member) ^ ",true)" ); + output ( "->__Field(" ^ (str member) ^ ", hx::paccDynamic )" ); already_dynamic := true; end else begin - if ((type_string field_object.etype)="::String" ) then - output ( "." ^ remap_name ) + if (isString) then + output ( "." ^ remap_name ) else begin cast_if_required ctx field_object (type_string field_object.etype); + let remap_name = if (type_string field_object.etype)="cpp::ArrayBase" then + match remap_name with + | "length" -> remap_name + | _ -> "__" ^ remap_name + else + remap_name + in output ( "->" ^ remap_name ); if (calling && (is_array field_object.etype) && remap_name="iterator" ) then check_array_element_cast field_object.etype "Fast" ""; already_dynamic := (match field with - | FInstance(_,var) when is_var_field var -> true + | FInstance(_,_,var) when is_var_field var -> true | _ -> false); end; end; ); - if ( (not !already_dynamic) && (not calling) && (not assigning) && (is_function_member expression) ) then + if ( (not !already_dynamic) && (not calling) && (not assigning) && (is_function_member expression) ) then output "_dyn()"; - in + in let gen_local_block_call () = - let func_name = use_anon_function_name ctx in ( - try - output ( func_name ^ "::Block(" ^ - (Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" ) - with Not_found -> - (*error ("Block function " ^ func_name ^ " not found" ) expression.epos;*) - output ("/* Block function " ^ func_name ^ " not found */" ); - ) + let func_name = use_anon_function_name ctx in ( + try + output ( func_name ^ "::Block(" ^ + (Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" ) + with Not_found -> + (*error ("Block function " ^ func_name ^ " not found" ) expression.epos;*) + output ("/* Block function " ^ func_name ^ " not found */" ); + ) in - (match expression.eexpr with - | TConst TNull when not retval -> - output "Dynamic()"; - | TCall (func, arg_list) when (match func.eexpr with - | TLocal { v_name = "__cpp__" } -> true - | _ -> false) -> - ( match arg_list with - | [{ eexpr = TConst (TString code) }] -> output code; - | _ -> error "__cpp__ accepts only one string as an argument" func.epos; - ) - | TCall (func, arg_list) when tcall_expand_args-> + (match expression.eexpr with + | TConst TNull when not retval -> + output "Dynamic()"; + | TCall (func, arg_list) when (match func.eexpr with + | TLocal { v_name = "__cpp__" } -> true + | _ -> false) -> + ( match arg_list with + | [{ eexpr = TConst (TString code) }] -> output (format_code code); + | ({ eexpr = TConst (TString code) } as ecode) :: tl -> + Codegen.interpolate_code ctx.ctx_common (format_code code) tl output (gen_expression ctx true) ecode.epos + | _ -> error "__cpp__'s first argument must be a string" func.epos; + ) + | TCall (func, arg_list) when tcall_expand_args-> let use_temp_func = has_side_effects func in if (use_temp_func) then begin output_i "Dynamic __func = "; @@ -1571,493 +2013,505 @@ and gen_expression ctx retval expression = if use_temp_func then output "__func" else begin - ctx.ctx_calling <- true; + ctx.ctx_calling <- true; gen_expression ctx true func; end; output ("(" ^ !arg_string ^ ");\n"); - | TCall (func, arg_list) -> - let rec is_variable e = match e.eexpr with - | TField _ -> false - | TLocal { v_name = "__global__" } -> false - | TParenthesis p -> is_variable p - | TCast (e,None) -> is_variable e - | _ -> true + | TCall (func, arg_list) when is_fromStaticFunction_call func -> + (match arg_list with + | [ {eexpr = TField( _, FStatic(klass,field)) } ] -> + let signature = cpp_function_signature field.cf_type "" in + let name = keyword_remap field.cf_name in + let void_cast = has_meta_key field.cf_meta Meta.Void in + output ("::cpp::Function< " ^ signature ^">("); + if (void_cast) then output "hx::AnyCast("; + output ("&::" ^(join_class_path klass.cl_path "::")^ "_obj::" ^ name ); + if (void_cast) then output ")"; + output (" )"); + | _ -> error "fromStaticFunction must take a static function" expression.epos; + ) + + | TCall (func, [arg]) when is_addressOf_call func && not (is_lvalue arg) -> + error "addressOf must take a local or member variable" expression.epos; + + | TCall (func, arg_list) -> + let rec is_variable e = match e.eexpr with + | TField _ | TEnumParameter _ -> false + | TLocal { v_name = "__global__" } -> false + | TParenthesis p | TMeta(_,p) -> is_variable p + | _ -> true in - let expr_type = type_string expression.etype in - let rec is_fixed_override e = (not (is_scalar expr_type)) && match e.eexpr with - | TField(obj,FInstance(_,field) ) -> + let expr_type = type_string expression.etype in + let rec is_fixed_override e = (not (is_scalar expr_type)) && match e.eexpr with + | TField(obj,FInstance(_,_,field) ) -> let cpp_type = member_type ctx obj field.cf_name in (not (is_scalar cpp_type)) && ( let fixed = (cpp_type<>"?") && (expr_type<>"Dynamic") && (cpp_type<>"Dynamic") && - (cpp_type<>expr_type) && (expr_type<>"Void") in - if (fixed && ctx.ctx_debug_type ) then begin + (cpp_type<>expr_type) && (expr_type<>"Void") && (cpp_type<>"cpp::ArrayBase") in + if (fixed && (ctx.ctx_debug_level>1) ) then begin output ("/* " ^ (cpp_type) ^ " != " ^ expr_type ^ " -> cast */"); - (* print_endline (cpp_type ^ " != " ^ expr_type ^ " -> cast"); *) end; fixed - ) - | TParenthesis p -> is_fixed_override p - | _ -> false + ) + | TParenthesis p | TMeta(_,p) -> is_fixed_override p + | _ -> false + in + let check_extern_pointer_cast e = match (remove_parens e).eexpr with + | TField (_,FInstance(class_def,_,_) ) + | TField (_,FStatic(class_def,_) ) + when class_def.cl_extern -> + (try + let return_type = expression.etype in + (is_pointer return_type false) && + ( output ( (type_string return_type) ^ "(" ); true; ) + with Not_found -> false ) + | _ -> false in let is_super = (match func.eexpr with | TConst TSuper -> true | _ -> false ) in - if (ctx.ctx_debug_type) then output ("/* TCALL ret=" ^ expr_type ^ "*/"); - let is_block_call = call_has_side_effects func arg_list in + if (ctx.ctx_debug_level>1) then output ("/* TCALL ret=" ^ expr_type ^ "*/"); + let is_block_call = call_has_side_effects func arg_list in let cast_result = (not is_super) && (is_fixed_override func) in if (cast_result) then output ("hx::TCast< " ^ expr_type ^ " >::cast("); - if (is_block_call) then + let cast_result = cast_result || check_extern_pointer_cast func in + if (is_block_call) then gen_local_block_call() else begin - ctx.ctx_calling <- true; - gen_expression ctx true func; + (* If a static function has @:native('new abc') + c++ new has lower precedence than in haxe so ( ) must be used *) + let paren_result = + if is_native_with_space func then + ( output "("; true ) + else + false + in + ctx.ctx_calling <- true; + gen_expression ctx true func; - output "("; - gen_expression_list arg_list; - output ")"; + output "("; + gen_expression_list arg_list; + output ")"; + if paren_result then + output ")"; end; if (cast_result) then output (")"); - if ( (is_variable func) && (expr_type<>"Dynamic") && (not is_super) && (not is_block_call)) then + if ( (is_variable func) && (not (is_cpp_function_member func) ) && + (expr_type<>"Dynamic" && expr_type<>"cpp::ArrayBase" ) && (not is_super) && (not is_block_call)) then ctx.ctx_output (".Cast< " ^ expr_type ^ " >()" ); let rec cast_array_output func = match func.eexpr with | TField(obj,field) when is_array obj.etype -> (match field_name field with - | "pop" | "shift" -> check_array_element_cast obj.etype ".StaticCast" "()" + | "pop" | "shift" | "__unsafe_get" | "__unsafe_set" -> check_array_element_cast obj.etype ".StaticCast" "()" | "map" -> check_array_cast expression.etype | _ -> () ) - | TParenthesis p -> cast_array_output p + | TParenthesis p | TMeta(_,p) -> cast_array_output p | _ -> () in cast_array_output func; - | TBlock expr_list -> - if (retval) then + | TBlock expr_list -> + if (retval) then gen_local_block_call() - else begin - writer#begin_block; - dump_src_pos(); - (* Save old values, and equalize for new input ... *) - let pop_names = push_anon_names ctx in - let remaining = ref (List.length expr_list) in - List.iter (fun expression -> - let want_value = (return_from_block && !remaining = 1) in - find_local_functions_and_return_blocks_ctx ctx want_value expression; - if (ctx.ctx_dump_stack_line) then - output_i ("HX_STACK_LINE(" ^ (string_of_int (Lexer.get_error_line expression.epos)) ^ ")\n" ); - output_i ""; - ctx.ctx_return_from_internal_node <- return_from_internal_node; - if (want_value) then output "return "; - gen_expression ctx want_value expression; - decr remaining; - writer#terminate_line - ) expr_list; - writer#end_block; - pop_names() - end - | TTypeExpr type_expr -> - let klass = "::" ^ (join_class_path_remap (t_path type_expr) "::" ) in - let klass1 = if klass="::Array" then "Array" else klass in - output ("hx::ClassOf< " ^ klass1 ^ " >()") - | TReturn _ when retval -> - unsupported expression.epos - | TReturn optional_expr -> - output ""; - ( match optional_expr with - | Some return_expression when ( (type_string expression.etype)="Void") -> - output "return null("; + else begin + writer#begin_block; + dump_src_pos(); + (* Save old values, and equalize for new input ... *) + let pop_names = push_anon_names ctx in + let remaining = ref (List.length expr_list) in + List.iter (fun expression -> + let want_value = (return_from_block && !remaining = 1) in + find_local_functions_and_return_blocks_ctx ctx want_value expression; + if (ctx.ctx_debug_level>0) then + output_i ("HX_STACK_LINE(" ^ (string_of_int (Lexer.get_error_line expression.epos)) ^ ")\n" ); + output_i ""; + ctx.ctx_return_from_internal_node <- return_from_internal_node; + if (want_value) then output "return "; + gen_expression ctx want_value expression; + decr remaining; + writer#terminate_line + ) expr_list; + writer#end_block; + pop_names() + end + | TTypeExpr type_expr -> + let klass = "::" ^ (join_class_path_remap (t_path type_expr) "::" ) in + let klass1 = if klass="::Array" then "Array" else klass in + output ("hx::ClassOf< " ^ klass1 ^ " >()") + | TReturn _ when retval -> + unsupported expression.epos + | TReturn optional_expr -> + output ""; + ( match optional_expr with + | Some return_expression when ( (type_string expression.etype)="Void") -> + output "return null("; gen_expression ctx true return_expression; - output ")"; - | Some return_expression -> - output "return "; - gen_expression ctx true return_expression - | _ -> output "return null()" - ) - - | TConst const -> - (match const with - | TInt i when ctx.ctx_for_extern -> output (Printf.sprintf "%ld" i) - | TInt i -> output (Printf.sprintf "(int)%ld" i) - | TFloat float_as_string -> output float_as_string - | TString s when ctx.ctx_for_extern -> output ("\"" ^ (escape_extern s) ^ "\"") - | TString s -> output (str s) - | TBool b -> output (if b then "true" else "false") - (*| TNull -> output ("((" ^ (type_string expression.etype) ^ ")null())")*) - | TNull -> output (if ctx.ctx_for_extern then "null" else "null()") - | TThis -> output (if ctx.ctx_real_this_ptr then "hx::ObjectPtr(this)" else "__this") - | TSuper when calling -> + output ")"; + | Some return_expression -> + output "return "; + gen_expression ctx true return_expression + | _ -> output (if ctx.ctx_real_void then "return" else "return null()") + ) + + | TConst const -> + (match const with + | TInt i when ctx.ctx_for_extern -> output (Printf.sprintf "%ld" i) + | TInt i -> output (Printf.sprintf "(int)%ld" i) + | TFloat float_as_string -> output ("((Float)" ^ float_as_string ^")") + | TString s when ctx.ctx_for_extern -> output ("\"" ^ (escape_extern s) ^ "\"") + | TString s -> output (str s) + | TBool b -> output (if b then "true" else "false") + (*| TNull -> output ("((" ^ (type_string expression.etype) ^ ")null())")*) + | TNull -> output (if ctx.ctx_for_extern then "null" else "null()") + | TThis -> output (if ctx.ctx_real_this_ptr then "hx::ObjectPtr(this)" else "__this") + | TSuper when calling -> output (if ctx.ctx_real_this_ptr then - "super::__construct" - else - ("__this->" ^ ctx.ctx_class_super_name ^ "::__construct") ) - | TSuper -> output ("hx::ObjectPtr(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this.mPtr") ^ ")") - ) - - - | TLocal v -> output (keyword_remap v.v_name); - | TArray (array_expr,_) when (is_null array_expr) -> output "Dynamic()" - | TArray (array_expr,index) -> - let dynamic = is_dynamic_in_cpp ctx array_expr in - if ( assigning && (not dynamic) ) then begin + "super::__construct" + else + ("__this->" ^ ctx.ctx_class_super_name ^ "::__construct") ) + | TSuper -> output ("hx::ObjectPtr(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this.mPtr") ^ ")") + ) + + + | TLocal v -> output (keyword_remap v.v_name); + | TArray (array_expr,_) when (is_null array_expr) -> output "Dynamic()" + | TArray (array_expr,index) -> + let dynamic = is_dynamic_in_cpp ctx array_expr || (type_string array_expr.etype) = "cpp::ArrayBase" in + if ( assigning && (not dynamic) ) then begin if (is_array_implementer array_expr.etype) then begin - output "hx::__ArrayImplRef("; - gen_expression ctx true array_expr; - output ","; - gen_expression ctx true index; - output ")"; + output "hx::__ArrayImplRef("; + gen_expression ctx true array_expr; + output ","; + gen_expression ctx true index; + output ")"; end else begin - gen_expression ctx true array_expr; - output "["; - gen_expression ctx true index; - output "]"; + gen_expression ctx true array_expr; + output "["; + gen_expression ctx true index; + output "]"; end - end else if (assigning) then begin - (* output (" /*" ^ (type_string array_expr.etype) ^ " */ "); *) - output "hx::IndexRef(("; - gen_expression ctx true array_expr; - output ").mPtr,"; - gen_expression ctx true index; - output ")"; - end else if ( dynamic ) then begin - gen_expression ctx true array_expr; - output "->__GetItem("; - gen_expression ctx true index; - output ")"; - end else begin - gen_expression ctx true array_expr; - output "->__get("; - gen_expression ctx true index; - output ")"; - check_array_element_cast array_expr.etype ".StaticCast" "()"; - end - (* Get precidence matching haxe ? *) - | TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2 - | TField (expr,name) when (is_null expr) -> output "Dynamic()" - - | TField (field_object,field) -> - gen_tfield field_object field - - | TParenthesis expr when not retval -> - gen_expression ctx retval expr; - | TParenthesis expr -> output "("; gen_expression ctx retval expr; output ")" - | TObjectDecl ( + end else if (assigning) then begin + (* output (" /*" ^ (type_string array_expr.etype) ^ " */ "); *) + output "hx::IndexRef(("; + gen_expression ctx true array_expr; + output ").mPtr,"; + gen_expression ctx true index; + output ")"; + end else if ( dynamic ) then begin + gen_expression ctx true array_expr; + output "->__GetItem("; + gen_expression ctx true index; + output ")"; + end else begin + gen_expression ctx true array_expr; + output "->__get("; + gen_expression ctx true index; + output ")"; + if not (is_pointer array_expr.etype true) then + check_array_element_cast array_expr.etype ".StaticCast" "()"; + end + (* Get precidence matching haxe ? *) + | TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2 + | TField (expr,_) | TEnumParameter (expr,_,_) when (is_null expr) -> + output "hx::Throw(HX_CSTRING(\"Invalid field access on null object\"))" + | TEnumParameter (expr,ef,i) -> + let enum = match follow ef.ef_type with + | TEnum(en,_) | TFun(_,TEnum(en,_)) -> en + | _ -> assert false + in + output ( "(::" ^ (join_class_path_remap enum.e_path "::") ^ "("); + gen_expression ctx true expr; + output ( "))->__Param(" ^ (string_of_int i) ^ ")") + | TField (field_object,field) -> + gen_tfield field_object field + + | TParenthesis expr when not retval -> + gen_expression ctx retval expr; + | TParenthesis expr -> output "("; gen_expression ctx retval expr; output ")" + | TMeta (_,expr) -> gen_expression ctx retval expr; + | TObjectDecl ( ("fileName" , { eexpr = (TConst (TString file)) }) :: ("lineNumber" , { eexpr = (TConst (TInt line)) }) :: ("className" , { eexpr = (TConst (TString class_name)) }) :: ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) -> - output ("hx::SourceInfo(" ^ (str file) ^ "," ^ (Printf.sprintf "%ld" line) ^ "," ^ - (str class_name) ^ "," ^ (str meth) ^ ")" ) - | TObjectDecl decl_list -> gen_local_block_call() - | TArrayDecl decl_list -> - (* gen_type output expression.etype; *) - let tstr = (type_string_suff "_obj" expression.etype) in + output ("hx::SourceInfo(" ^ (str file) ^ "," ^ (Printf.sprintf "%ld" line) ^ "," ^ + (str class_name) ^ "," ^ (str meth) ^ ")" ) + | TObjectDecl decl_list -> gen_local_block_call() + | TArrayDecl decl_list -> + (* gen_type output expression.etype; *) + let tstr = (type_string_suff "_obj" expression.etype true) in if tstr="Dynamic" then - output "Dynamic( Array_obj::__new()" + output "Dynamic( Array_obj::__new()" else - output ( (type_string_suff "_obj" expression.etype) ^ "::__new()"); - List.iter ( fun elem -> output ".Add("; - gen_expression ctx true elem; - output ")" ) decl_list; + output ( (type_string_suff "_obj" expression.etype true) ^ "::__new()"); + List.iter ( fun elem -> output ".Add("; + gen_expression ctx true elem; + output ")" ) decl_list; if tstr="Dynamic" then output ")"; - | TNew (klass,params,expressions) -> + | TNew (klass,params,expressions) -> let is_param_array = match klass.cl_path with - | ([],"Array") when is_dynamic_array_param (List.hd params) -> true | _ -> false + | ([],"Array") when is_dynamic_array_param (List.hd params) -> true | _ -> false in if is_param_array then - output "Dynamic( Array_obj::__new() )" + output "Dynamic( Array_obj::__new() )" else begin - if (klass.cl_path = ([],"String")) then - output "::String(" - else - output ( ( class_string klass "_obj" params) ^ "::__new(" ); - gen_expression_list expressions; - output ")" + if (klass.cl_path = ([],"String")) then + output "::String(" + else + output ( ( class_string klass "_obj" params true) ^ "::__new(" ); + gen_expression_list expressions; + output ")" + end + | TUnop (Ast.NegBits,Ast.Prefix,expr) -> + output "~(int)("; + gen_expression ctx true expr; + output ")" + | TUnop (op,Ast.Prefix,expr) -> + ctx.ctx_assigning <- (match op with Ast.Increment | Ast.Decrement -> true | _ ->false); + output (Ast.s_unop op); + output "("; + gen_expression ctx true expr; + output ")" + | TUnop (op,Ast.Postfix,expr) -> + ctx.ctx_assigning <- true; + output "("; + gen_expression ctx true expr; + output ")"; + output (Ast.s_unop op) + | TFunction func -> + let func_name = use_anon_function_name ctx in + ( + try + output ( " Dynamic(new " ^ func_name ^ "(" ^ + (Hashtbl.find ctx.ctx_local_function_args func_name) ^ "))" ) + with Not_found -> + (*error ("function " ^ func_name ^ " not found.") expression.epos; *) + output ("function " ^ func_name ^ " not found."); + ) + + | TVar (tvar,optional_init) -> + let count = ref 1 in (* TODO: this section can be simplified *) + if (retval && !count==1) then + (match optional_init with + | None -> output "null()" + | Some expression -> gen_expression ctx true expression ) + else begin + let type_name = (type_string tvar.v_type) in + output (if type_name="Void" then "Dynamic" else type_name ); + let name = (keyword_remap tvar.v_name) in + output (" " ^ name ); + (match optional_init with + | None -> () + | Some expression -> output " = "; gen_expression ctx true expression); + count := !count -1; + if (ctx.ctx_debug_level>0) then + output (";\t\tHX_STACK_VAR(" ^name ^",\""^ tvar.v_name ^"\")"); + if (!count > 0) then begin output ";\n"; output_i "" end end - | TUnop (Ast.NegBits,Ast.Prefix,expr) -> - output "~(int)("; - gen_expression ctx true expr; - output ")" - | TUnop (op,Ast.Prefix,expr) -> - ctx.ctx_assigning <- (match op with Ast.Increment | Ast.Decrement -> true | _ ->false); - output (Ast.s_unop op); - output "("; - gen_expression ctx true expr; - output ")" - | TUnop (op,Ast.Postfix,expr) -> - ctx.ctx_assigning <- true; - output "("; - gen_expression ctx true expr; - output ")"; - output (Ast.s_unop op) - | TFunction func -> - let func_name = use_anon_function_name ctx in - ( - try - output ( " Dynamic(new " ^ func_name ^ "(" ^ - (Hashtbl.find ctx.ctx_local_function_args func_name) ^ "))" ) - with Not_found -> - (*error ("function " ^ func_name ^ " not found.") expression.epos; *) - output ("function " ^ func_name ^ " not found."); - ) - - | TVars var_list -> - let count = ref (List.length var_list) in - List.iter (fun (tvar, optional_init) -> - if (retval && !count==1) then - (match optional_init with - | None -> output "null()" - | Some expression -> gen_expression ctx true expression ) - else begin - let type_name = (type_string tvar.v_type) in - output (if type_name="Void" then "Dynamic" else type_name ); - let name = (keyword_remap tvar.v_name) in - output (" " ^ name ); - (match optional_init with - | None -> () - | Some expression -> output " = "; gen_expression ctx true expression); - count := !count -1; - if (ctx.ctx_dump_stack_line) then - output (";\t\tHX_STACK_VAR(" ^name ^",\""^ tvar.v_name ^"\")"); - if (!count > 0) then begin output ";\n"; output_i "" end - end - ) var_list - | TFor (tvar, init, loop) -> - output ("for(::cpp::FastIterator_obj< " ^ (type_string tvar.v_type) ^ - " > *__it = ::cpp::CreateFastIterator< "^(type_string tvar.v_type) ^ " >("); - gen_expression ctx true init; - output ("); __it->hasNext(); )"); - ctx.ctx_writer#begin_block; - output_i ( (type_string tvar.v_type) ^ " " ^ (keyword_remap tvar.v_name) ^ " = __it->next();\n" ); - output_i ""; - gen_expression ctx false loop; - output ";\n"; - ctx.ctx_writer#end_block; - | TIf (condition, if_expr, optional_else_expr) -> - (match optional_else_expr with - | Some else_expr -> - if (retval) then begin +| TFor (tvar, init, loop) -> + output ("for(::cpp::FastIterator_obj< " ^ (type_string tvar.v_type) ^ + " > *__it = ::cpp::CreateFastIterator< "^(type_string tvar.v_type) ^ " >("); + gen_expression ctx true init; + output ("); __it->hasNext(); )"); + ctx.ctx_writer#begin_block; + output_i ( (type_string tvar.v_type) ^ " " ^ (keyword_remap tvar.v_name) ^ " = __it->next();\n" ); + output_i ""; + gen_expression ctx false loop; + output ";\n"; + ctx.ctx_writer#end_block; + | TIf (condition, if_expr, optional_else_expr) -> + (match optional_else_expr with + | Some else_expr -> + if (retval) then begin output "( ("; - gen_expression ctx true condition; - output ") ? "; - let type_str = match (type_string expression.etype) with - | "Void" -> "Dynamic" - | other -> other - in - output (type_str ^ "("); - gen_expression ctx true if_expr; - output ") : "; - - output (type_str ^ "("); - gen_expression ctx true else_expr; - output ") )"; - end else begin - output "if ("; - gen_expression ctx true condition; - output ")"; - gen_expression ctx false (to_block if_expr); - output_i "else"; - gen_expression ctx false (to_block else_expr); - end - | _ -> output "if ("; - gen_expression ctx true condition; - output ")"; - gen_expression ctx false (to_block if_expr); - ) - | TWhile (condition, repeat, Ast.NormalWhile ) -> - output "while("; - gen_expression ctx true condition; - output ")"; + gen_expression ctx true condition; + output ") ? "; + let type_str = match (type_string expression.etype) with + | "Void" -> "Dynamic" + | other -> other + in + output (type_str ^ "("); + gen_expression ctx true if_expr; + output ") : "; + + output (type_str ^ "("); + gen_expression ctx true else_expr; + output ") )"; + end else begin + output "if ("; + gen_expression ctx true condition; + output ")"; + gen_expression ctx false (to_block if_expr); + output_i "else"; + gen_expression ctx false (to_block else_expr); + end + | _ -> output "if ("; + gen_expression ctx true condition; + output ")"; + gen_expression ctx false (to_block if_expr); + ) + | TWhile (condition, repeat, Ast.NormalWhile ) -> + output "while("; + gen_expression ctx true condition; + output ")"; gen_expression ctx false (to_block repeat) - | TWhile (condition, repeat, Ast.DoWhile ) -> - output "do"; - gen_expression ctx false (to_block repeat); - output "while("; - gen_expression ctx true condition; - output ")" - - (* These have already been defined in find_local_return_blocks ... *) - | TTry (_,_) - | TSwitch (_,_,_) - | TMatch (_, _, _, _) when (retval && (not return_from_internal_node) )-> + | TWhile (condition, repeat, Ast.DoWhile ) -> + output "do"; + gen_expression ctx false (to_block repeat); + output "while("; + gen_expression ctx true condition; + output ")" + + (* These have already been defined in find_local_return_blocks ... *) + | TTry (_,_) + | TSwitch (_,_,_) when (retval && (not return_from_internal_node) ) -> gen_local_block_call() - | TSwitch (condition,cases,optional_default) -> - let switch_on_int_constants = (only_int_cases cases) && (not (contains_break expression)) in - if (switch_on_int_constants) then begin - output "switch( (int)"; - gen_expression ctx true condition; - output ")"; - ctx.ctx_writer#begin_block; - List.iter (fun (cases_list,expression) -> - output_i ""; - List.iter (fun value -> output "case "; - gen_expression ctx true value; - output ": " ) cases_list; - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block expression); - output_i ";break;\n"; - ) cases; - (match optional_default with | None -> () - | Some default -> - output_i "default: "; - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block default); - ); - ctx.ctx_writer#end_block; - end else begin - let tmp_name = get_switch_var ctx in - output ( (type_string condition.etype) ^ " " ^ tmp_name ^ " = " ); - gen_expression ctx true condition; - output ";\n"; - let else_str = ref "" in - if (List.length cases > 0) then - List.iter (fun (cases,expression) -> - output_i ( !else_str ^ "if ( "); - else_str := "else "; - let or_str = ref "" in - List.iter (fun value -> - output (!or_str ^ " ( " ^ tmp_name ^ "=="); - gen_expression ctx true value; - output ")"; - or_str := " || "; - ) cases; - output (")"); - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block expression); - ) cases; - (match optional_default with | None -> () - | Some default -> - output_i ( !else_str ^ " "); - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block default); - output ";\n"; - ); - end - | TMatch (condition, enum, cases, default) -> - let tmp_var = get_switch_var ctx in - writer#begin_block; - output_i ( "::" ^ (join_class_path_remap (fst enum).e_path "::") ^ " " ^ tmp_var ^ " = " ); - gen_expression ctx true condition; - output ";\n"; - - let use_if_statements = contains_break expression in - let dump_condition = if (use_if_statements) then begin - let tmp_name = get_switch_var ctx in - output_i ( "int " ^ tmp_name ^ " = (" ^ tmp_var ^ ")->GetIndex();" ); - let elif = ref "if" in - ( fun case_ids -> output (!elif ^ " (" ); elif := "else if"; - output (String.concat "||" - (List.map (fun id -> (string_of_int id) ^ "==" ^ tmp_name ) case_ids ) ); - output ") " ) - end else begin - output_i ("switch((" ^ tmp_var ^ ")->GetIndex())"); - ( fun case_ids -> - List.iter (fun id -> output ("case " ^ (string_of_int id) ^ ": ") ) case_ids; - ) - end in - writer#begin_block; - List.iter (fun (case_ids,params,expression) -> - output_i ""; - dump_condition case_ids; - let has_params = match params with | Some _ -> true | _ -> false in - if (has_params) then begin - writer#begin_block; - List.iter (fun (name,vtype,id) -> output_i - ((type_string vtype) ^ " " ^ (keyword_remap name) ^ - " = " ^ tmp_var ^ "->__Param(" ^ (string_of_int id) ^ ");\n")) - (tmatch_params_to_args params); - end; - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block expression); - if (has_params) then writer#end_block; - if (not use_if_statements) then output_i ";break;\n"; - ) cases; - (match default with - | None -> () - | Some e -> - if (use_if_statements) then - output_i "else " - else - output_i "default: "; - ctx.ctx_return_from_block <- return_from_internal_node; - gen_expression ctx false (to_block e); - ); - writer#end_block; - writer#end_block; - - | TTry (expression, catch_list) -> - output "try"; - (* Move this "inside" the try call ... *) - ctx.ctx_return_from_block <-return_from_internal_node; - gen_expression ctx false (to_block expression); - if (List.length catch_list > 0 ) then begin - output_i "catch(Dynamic __e)"; - ctx.ctx_writer#begin_block; - let seen_dynamic = ref false in - let else_str = ref "" in - List.iter (fun (v,expression) -> - let type_name = type_string v.v_type in - if (type_name="Dynamic") then begin - seen_dynamic := true; - output_i !else_str; - end else - output_i (!else_str ^ "if (__e.IsClass< " ^ type_name ^ " >() )"); - ctx.ctx_writer#begin_block; - output_i "HX_STACK_BEGIN_CATCH\n"; - output_i (type_name ^ " " ^ v.v_name ^ " = __e;"); - (* Move this "inside" the catch call too ... *) - ctx.ctx_return_from_block <-return_from_internal_node; - gen_expression ctx false (to_block expression); - ctx.ctx_writer#end_block; - else_str := "else "; - ) catch_list; - if (not !seen_dynamic) then begin - output_i "else throw(__e);\n"; - end; - ctx.ctx_writer#end_block; - end; - | TBreak -> output "break" - | TContinue -> output "continue" - | TThrow expression -> output "hx::Throw ("; - gen_expression ctx true expression; - output ")" - | TCast (cast,None) -> - let void_cast = retval && ((type_string expression.etype)="Void" ) in - if (void_cast) then output "Void("; - gen_expression ctx retval cast; - if (void_cast) then output ")"; - | TCast (e1,Some t) -> - let class_name = (join_class_path_remap (t_path t) "::" ) in - if (class_name="Array") then - output ("hx::TCastToArray(" ) - else - output ("hx::TCast< " ^ class_name ^ " >::cast(" ); - gen_expression ctx true e1; - output ")"; - );; + | TSwitch (condition,cases,optional_default) -> + let switch_on_int_constants = (only_int_cases cases) && (not (contains_break expression)) in + if (switch_on_int_constants) then begin + output "switch( (int)"; + gen_expression ctx true condition; + output ")"; + ctx.ctx_writer#begin_block; + List.iter (fun (cases_list,expression) -> + output_i ""; + List.iter (fun value -> output "case "; + gen_expression ctx true value; + output ": " ) cases_list; + ctx.ctx_return_from_block <- return_from_internal_node; + gen_expression ctx false (to_block expression); + output_i ";break;\n"; + ) cases; + (match optional_default with | None -> () + | Some default -> + output_i "default: "; + ctx.ctx_return_from_block <- return_from_internal_node; + gen_expression ctx false (to_block default); + ); + ctx.ctx_writer#end_block; + end else begin + let tmp_name = get_switch_var ctx in + output ( (type_string condition.etype) ^ " " ^ tmp_name ^ " = " ); + gen_expression ctx true condition; + output ";\n"; + let else_str = ref "" in + if (List.length cases > 0) then + List.iter (fun (cases,expression) -> + output_i ( !else_str ^ "if ( "); + else_str := "else "; + let or_str = ref "" in + List.iter (fun value -> + output (!or_str ^ " ( " ^ tmp_name ^ "=="); + gen_expression ctx true value; + output ")"; + or_str := " || "; + ) cases; + output (")"); + ctx.ctx_return_from_block <- return_from_internal_node; + gen_expression ctx false (to_block expression); + ) cases; + (match optional_default with | None -> () + | Some default -> + output_i ( !else_str ^ " "); + ctx.ctx_return_from_block <- return_from_internal_node; + gen_expression ctx false (to_block default); + output ";\n"; + ); + end + | TTry (expression, catch_list) -> + output "try\n"; + output_i "{\n"; + let counter = ref 0 in + List.iter (fun (v, e) -> + let type_name = type_string v.v_type in + output_i ("HX_STACK_CATCHABLE(" ^ type_name ^ ", " ^ string_of_int !counter ^ ");\n"); + counter := !counter + 1;) + catch_list; + output_i(""); + (* Move this "inside" the try call ... *) + ctx.ctx_return_from_block <-return_from_internal_node; + gen_expression ctx false (to_block expression); + output_i "}\n"; + if (List.length catch_list > 0 ) then begin + output_i "catch(Dynamic __e)"; + ctx.ctx_writer#begin_block; + let seen_dynamic = ref false in + let else_str = ref "" in + List.iter (fun (v,expression) -> + let type_name = type_string v.v_type in + if (type_name="Dynamic") then begin + seen_dynamic := true; + output_i !else_str; + end else + output_i (!else_str ^ "if (__e.IsClass< " ^ type_name ^ " >() )"); + ctx.ctx_writer#begin_block; + output_i "HX_STACK_BEGIN_CATCH\n"; + output_i (type_name ^ " " ^ v.v_name ^ " = __e;"); + (* Move this "inside" the catch call too ... *) + ctx.ctx_return_from_block <-return_from_internal_node; + gen_expression ctx false (to_block expression); + ctx.ctx_writer#end_block; + else_str := "else "; + ) catch_list; + if (not !seen_dynamic) then begin + output_i "else {\n"; + output_i " HX_STACK_DO_THROW(__e);\n"; + output_i "}\n"; + end; + ctx.ctx_writer#end_block; + end; + | TBreak -> output "break" + | TContinue -> output "continue" + | TThrow expression -> + output "HX_STACK_DO_THROW("; + gen_expression ctx true expression; + output ")"; + | TCast (cast,None) when (not retval) || (type_string expression.etype) = "Void" -> + gen_expression ctx retval cast; + | TCast (cast,None) -> + let ret_type = type_string expression.etype in + let from_type = if is_dynamic_in_cpp ctx cast then "Dynamic" else type_string cast.etype in + if (from_type = ret_type) then begin + gen_expression ctx true cast + end else begin + output ("((" ^ ret_type ^ ")("); + gen_expression ctx true cast; + output "))"; + end; + | TCast (e1,Some t) -> + let class_name = (join_class_path_remap (t_path t) "::" ) in + if (class_name="Array") then + output ("hx::TCastToArray(" ) + else + output ("hx::TCast< ::" ^ class_name ^ " >::cast(" ); + gen_expression ctx true e1; + output ")"; + );; (* let is_dynamic_haxe_method f = - match follow f.cf_type with - | TFun _ when f.cf_expr = None -> true - | _ -> - (match f.cf_expr with - | Some { eexpr = TFunction fd } when f.cf_set = MethodAccess true -> true - | Some { eexpr = TFunction fd } when f.cf_set = NormalAccess -> true - | _ -> false);; + match follow f.cf_type with + | TFun _ when f.cf_expr = None -> true + | _ -> + (match f.cf_expr with + | Some { eexpr = TFunction fd } when f.cf_set = MethodAccess true -> true + | Some { eexpr = TFunction fd } when f.cf_set = NormalAccess -> true + | _ -> false);; *) let is_dynamic_haxe_method f = - (match f.cf_expr, f.cf_kind with - | Some { eexpr = TFunction _ }, (Var _ | Method MethDynamic) -> true - | _ -> false);; + (match f.cf_expr, f.cf_kind with + | Some { eexpr = TFunction _ }, (Var _ | Method MethDynamic) -> true + | _ -> false);; let is_data_member field = - match field.cf_expr with - | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field - | _ -> true;; + match field.cf_expr with + | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field + | _ -> true;; let is_override class_def field = @@ -2066,698 +2520,822 @@ let is_override class_def field = let rec all_virtual_functions clazz = (List.fold_left (fun result elem -> match follow elem.cf_type, elem.cf_kind with - | _, Method MethDynamic -> result - | TFun (args,return_type), Method _ when not (is_override clazz elem.cf_name ) -> (elem,args,return_type) :: result + | _, Method MethDynamic -> result + | TFun (args,return_type), Method _ when not (is_override clazz elem.cf_name ) -> (elem,args,return_type) :: result | _,_ -> result ) [] clazz.cl_ordered_fields) - @ (match clazz.cl_super with + @ (match clazz.cl_super with | Some def -> all_virtual_functions (fst def) | _ -> [] ) ;; +let reflective class_def field = not ( + (Meta.has Meta.NativeGen class_def.cl_meta) || + (Meta.has Meta.Unreflective class_def.cl_meta) || + (Meta.has Meta.Unreflective field.cf_meta) || + (match field.cf_type with + | TInst (klass,_) -> Meta.has Meta.Unreflective klass.cl_meta + | _ -> false + ) +) +;; - (* external mem Dynamic & *) - -let gen_field ctx class_def class_name ptr_name is_static is_interface field = - let output = ctx.ctx_output in - ctx.ctx_real_this_ptr <- not is_static; - let remap_name = keyword_remap field.cf_name in - let decl = get_meta_string field.cf_meta Meta.Decl in - let has_decl = decl <> "" in - if (is_interface) then begin - (* Just the dynamic glue ... *) - match follow field.cf_type, field.cf_kind with - | _, Method MethDynamic -> () - | TFun (args,result), Method _ -> - if (is_static) then output "STATIC_"; - let ret = if ((type_string result ) = "Void" ) then "" else "return " in - output ("HX_DEFINE_DYNAMIC_FUNC" ^ (string_of_int (List.length args)) ^ - "(" ^ class_name ^ "," ^ remap_name ^ "," ^ ret ^ ")\n\n"); - | _ -> () - end else (match field.cf_expr with - (* Function field *) - | Some { eexpr = TFunction function_def } -> - let return_type = (type_string function_def.tf_type) in - let nargs = string_of_int (List.length function_def.tf_args) in - let is_void = (type_string function_def.tf_type ) = "Void" in - let ret = if is_void then "(void)" else "return " in - let output_i = ctx.ctx_writer#write_i in - let dump_src = if (Meta.has Meta.NoStack field.cf_meta) then begin - ctx.ctx_dump_stack_line <- false; - (fun()->()) - end else begin - ctx.ctx_dump_stack_line <- true; - (fun() -> - hx_stack_push ctx output_i ptr_name field.cf_name function_def.tf_expr.epos; - if (not is_static) then output_i ("HX_STACK_THIS(this);\n"); - List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") ) - function_def.tf_args ) - end in - - if (not (is_dynamic_haxe_method field)) then begin - (* The actual function definition *) - output return_type; - output (" " ^ class_name ^ "::" ^ remap_name ^ "( " ); - output (gen_arg_list function_def.tf_args "__o_"); - output ")"; - ctx.ctx_real_this_ptr <- true; - ctx.ctx_dynamic_this_ptr <- false; - let code = (get_code field.cf_meta Meta.FunctionCode) in - let tail_code = (get_code field.cf_meta Meta.FunctionTailCode) in - if (has_default_values function_def.tf_args) then begin - ctx.ctx_writer#begin_block; - generate_default_values ctx function_def.tf_args "__o_"; - dump_src(); + + + + +let field_arg_count field = + match follow field.cf_type, field.cf_kind with + | _, Method MethDynamic -> -1 + | TFun (args,return_type), Method _ -> List.length args + | _,_ -> -1 +;; + + + (* external mem Dynamic & *) + +let gen_field ctx class_def class_name ptr_name dot_name is_static is_interface field = + let output = ctx.ctx_output in + ctx.ctx_real_this_ptr <- not is_static; + let remap_name = keyword_remap field.cf_name in + let decl = get_meta_string field.cf_meta Meta.Decl in + let has_decl = decl <> "" in + let nativeGen = has_meta_key class_def.cl_meta Meta.NativeGen in + if (is_interface) then begin + (* Just the dynamic glue - not even that ... *) + () + end else (match field.cf_expr with + (* Function field *) + | Some { eexpr = TFunction function_def } -> + let return_type = (type_string function_def.tf_type) in + let nargs = string_of_int (List.length function_def.tf_args) in + let is_void = (type_string function_def.tf_type ) = "Void" in + let ret = if is_void then "(void)" else "return " in + let output_i = ctx.ctx_writer#write_i in + let orig_debug = ctx.ctx_debug_level in + let dump_src = if ((Meta.has Meta.NoStack field.cf_meta)||(Meta.has Meta.NoDebug field.cf_meta) || orig_debug<1 || nativeGen) then begin + ctx.ctx_debug_level <- 0; + (fun()->()) + end else begin + (fun() -> + hx_stack_push ctx output_i dot_name field.cf_name function_def.tf_expr.epos; + if (not is_static) then output_i ("HX_STACK_THIS(this)\n"); + List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\")\n") ) + function_def.tf_args ) + end in + + if (not (is_dynamic_haxe_method field)) then begin + (* The actual function definition *) + let real_void = is_void && (has_meta_key field.cf_meta Meta.Void) in + let fake_void = is_void && not real_void in + output (if real_void then "void" else return_type ); + output (" " ^ class_name ^ "::" ^ remap_name ^ "( " ); + output (gen_arg_list function_def.tf_args "__o_"); + output ")"; + ctx.ctx_real_this_ptr <- true; + ctx.ctx_real_void <- real_void; + ctx.ctx_dynamic_this_ptr <- false; + let code = (get_code field.cf_meta Meta.FunctionCode) in + let tail_code = (get_code field.cf_meta Meta.FunctionTailCode) in + if (has_default_values function_def.tf_args) then begin + ctx.ctx_writer#begin_block; + generate_default_values ctx function_def.tf_args "__o_"; + dump_src(); + output code; + gen_expression ctx false function_def.tf_expr; + output tail_code; + if (fake_void) then output "return null();\n"; + ctx.ctx_writer#end_block; + end else begin + let add_block = is_void || (code <> "") || (tail_code <> "") in + if (add_block) then ctx.ctx_writer#begin_block; + ctx.ctx_dump_src_pos <- dump_src; output code; - gen_expression ctx false function_def.tf_expr; + gen_expression ctx false (to_block function_def.tf_expr); output tail_code; - if (is_void) then output "return null();\n"; - ctx.ctx_writer#end_block; - end else begin - let add_block = is_void || (code <> "") || (tail_code <> "") in - if (add_block) then ctx.ctx_writer#begin_block; - ctx.ctx_dump_src_pos <- dump_src; - output code; - gen_expression ctx false (to_block function_def.tf_expr); - output tail_code; - if (add_block) then begin - if (is_void) then output "return null();\n"; - ctx.ctx_writer#end_block; - end; - end; - - output "\n\n"; - (* generate dynamic version too ... *) - if ( not (is_override class_def field.cf_name ) ) then begin - if (is_static) then output "STATIC_"; - output ("HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^ - remap_name ^ "," ^ ret ^ ")\n\n"); - end; - - end else begin - ctx.ctx_real_this_ptr <- false; - ctx.ctx_dynamic_this_ptr <- false; - let func_name = "__default_" ^ (remap_name) in - output ("HX_BEGIN_DEFAULT_FUNC(" ^ func_name ^ "," ^ class_name ^ ")\n"); - output return_type; - output (" run(" ^ (gen_arg_list function_def.tf_args "") ^ ")"); - ctx.ctx_dump_src_pos <- dump_src; - if (is_void) then begin - ctx.ctx_writer#begin_block; - gen_expression ctx false function_def.tf_expr; - output "return null();\n"; - ctx.ctx_writer#end_block; - end else - gen_expression ctx false (to_block function_def.tf_expr); - - output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n"); - output ("HX_END_DEFAULT_FUNC\n\n"); - - if (is_static) then - output ( "Dynamic " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); - end - - (* Data field *) - | _ when has_decl -> - if is_static then begin - output ( class_name ^ "::" ^ remap_name ^ "_decl "); - output ( " " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); - end - | _ -> - if is_static && (not (is_extern_field field)) then begin - gen_type ctx field.cf_type; - output ( " " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); - end - ) - ;; + if (add_block) then begin + if (fake_void) then output "return null();\n"; + ctx.ctx_writer#end_block; + end; + end; + + output "\n\n"; + let nonVirtual = has_meta_key field.cf_meta Meta.NonVirtual in + let doDynamic = (nonVirtual || not (is_override class_def field.cf_name ) ) && (reflective class_def field ) in + (* generate dynamic version too ... *) + if ( doDynamic ) then begin + if (is_static) then output "STATIC_"; + output ("HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^ + remap_name ^ "," ^ ret ^ ")\n\n"); + end; + + end else begin + ctx.ctx_real_this_ptr <- false; + ctx.ctx_dynamic_this_ptr <- false; + let func_name = "__default_" ^ (remap_name) in + output ("HX_BEGIN_DEFAULT_FUNC(" ^ func_name ^ "," ^ class_name ^ ")\n"); + output return_type; + output (" run(" ^ (gen_arg_list function_def.tf_args "__o_") ^ ")"); + ctx.ctx_dump_src_pos <- dump_src; + if (is_void) then begin + ctx.ctx_writer#begin_block; + generate_default_values ctx function_def.tf_args "__o_"; + gen_expression ctx false function_def.tf_expr; + output "return null();\n"; + ctx.ctx_writer#end_block; + end else if (has_default_values function_def.tf_args) then begin + ctx.ctx_writer#begin_block; + generate_default_values ctx function_def.tf_args "__o_"; + gen_expression ctx false function_def.tf_expr; + ctx.ctx_writer#end_block; + end else + gen_expression ctx false (to_block function_def.tf_expr); + + output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n"); + output ("HX_END_DEFAULT_FUNC\n\n"); + + if (is_static) then + output ( "Dynamic " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); + end; + ctx.ctx_debug_level <- orig_debug + + (* Data field *) + | _ when has_decl -> + if is_static then begin + output ( class_name ^ "::" ^ remap_name ^ "_decl "); + output ( " " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); + end + | _ -> + if is_static && (not (is_extern_field field)) then begin + gen_type ctx field.cf_type; + output ( " " ^ class_name ^ "::" ^ remap_name ^ ";\n\n"); + end + ) + ;; let gen_field_init ctx field = - let output = ctx.ctx_output in - let remap_name = keyword_remap field.cf_name in - (match field.cf_expr with - (* Function field *) - | Some { eexpr = TFunction function_def } -> - - if (is_dynamic_haxe_method field) then begin - let func_name = "__default_" ^ (remap_name) in - output ( " " ^ remap_name ^ " = new " ^ func_name ^ ";\n\n" ); - end - - (* Data field *) - | _ -> (match field.cf_expr with - | Some expr -> - find_local_functions_and_return_blocks_ctx ctx true expr; - output ( match remap_name with "__meta__" -> " __mClass->__meta__=" | _ -> " " ^ remap_name ^ "= "); - gen_expression ctx true expr; - output ";\n" - | _ -> ( ) - ); - ) - ;; + let output = ctx.ctx_output in + let remap_name = keyword_remap field.cf_name in + (match field.cf_expr with + (* Function field *) + | Some { eexpr = TFunction function_def } -> + + if (is_dynamic_haxe_method field) then begin + let func_name = "__default_" ^ (remap_name) in + output ( "\t" ^ remap_name ^ " = new " ^ func_name ^ ";\n\n" ); + end + + (* Data field *) + | _ -> (match field.cf_expr with + | Some expr -> + find_local_functions_and_return_blocks_ctx ctx true expr; + output ( match remap_name with + | "__meta__" -> "\t__mClass->__meta__=" + | "__rtti" -> "\t__mClass->__rtti__=" + | _ -> "\t" ^ remap_name ^ "= "); + gen_expression ctx true expr; + output ";\n" + | _ -> ( ) + ); + ) + ;; + +let has_field_init field = + match field.cf_expr with + (* Function field *) + | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field + (* Data field *) + | Some _ -> true + | _ -> false +;; + let gen_member_def ctx class_def is_static is_interface field = - let output = ctx.ctx_output in - let remap_name = keyword_remap field.cf_name in - - if (is_interface) then begin - match follow field.cf_type, field.cf_kind with - | _, Method MethDynamic -> () - | TFun (args,return_type), Method _ -> - output ( (if (not is_static) then "virtual " else "" ) ^ type_string return_type); - output (" " ^ remap_name ^ "( " ); - output (gen_tfun_interface_arg_list args); - output (if (not is_static) then ")=0;\n" else ");\n"); - output (if is_static then " static " else " "); - output ("Dynamic " ^ remap_name ^ "_dyn();\n" ); - | _ -> ( ) - end else begin - let decl = get_meta_string field.cf_meta Meta.Decl in - let has_decl = decl <> "" in + let output = ctx.ctx_output in + let remap_name = keyword_remap field.cf_name in + let nativeGen = has_meta_key class_def.cl_meta Meta.NativeGen in + + if (is_interface) then begin + match follow field.cf_type, field.cf_kind with + | _, Method MethDynamic -> () + | TFun (args,return_type), Method _ -> + output ( (if (not is_static) then " virtual " else " " ) ^ type_string return_type); + output (" " ^ remap_name ^ "( " ); + output (gen_tfun_interface_arg_list args); + output (if (not is_static) then ")=0;\n" else ");\n"); + if not nativeGen then begin + output (if is_static then "\t\tstatic " else "\t\t"); + output ("virtual Dynamic " ^ remap_name ^ "_dyn()=0;\n" ); + end + | _ -> ( ) + end else begin + let decl = get_meta_string field.cf_meta Meta.Decl in + let has_decl = decl <> "" in if (has_decl) then - output ( " typedef " ^ decl ^ ";\n" ); - output (if is_static then " static " else " "); + output ( " typedef " ^ decl ^ ";\n" ); + output (if is_static then "\t\tstatic " else "\t\t"); (match field.cf_expr with - | Some { eexpr = TFunction function_def } -> - if ( is_dynamic_haxe_method field ) then begin - if ( not (is_override class_def field.cf_name ) ) then begin - output ("Dynamic " ^ remap_name ^ ";\n"); - output (if is_static then " static " else " "); - output ("inline Dynamic &" ^ remap_name ^ "_dyn() " ^ "{return " ^ remap_name^ "; }\n") - end - end else begin - let return_type = (type_string function_def.tf_type) in - if (not is_static) then output "virtual "; - output return_type; - output (" " ^ remap_name ^ "( " ); - output (gen_arg_list function_def.tf_args "" ); - output ");\n"; - if ( not (is_override class_def field.cf_name ) ) then begin - output (if is_static then " static " else " "); - output ("Dynamic " ^ remap_name ^ "_dyn();\n" ) - end; - end; - output "\n"; - | _ when has_decl -> - output ( remap_name ^ "_decl " ^ remap_name ^ ";\n" ); - (* Variable access *) - | _ -> - (* Variable access *) - gen_type ctx field.cf_type; - output (" " ^ remap_name ^ ";\n" ); - - (* Add a "dyn" function for variable to unify variable/function access *) - (match follow field.cf_type with - | TFun (_,_) -> - output (if is_static then " static " else " "); - gen_type ctx field.cf_type; - output (" &" ^ remap_name ^ "_dyn() { return " ^ remap_name ^ ";}\n" ) - | _ -> (match field.cf_kind with - | Var { v_read = AccCall } when (not is_static) && (is_dynamic_accessor ("get_" ^ field.cf_name) "get" field class_def) -> - output ("\t\tDynamic get_" ^ field.cf_name ^ ";\n" ) - | _ -> () - ); - (match field.cf_kind with - | Var { v_write = AccCall } when (not is_static) && (is_dynamic_accessor ("set_" ^ field.cf_name) "set" field class_def) -> - output ("\t\tDynamic set_" ^ field.cf_name ^ ";\n" ) - | _ -> () - ) - ) - ); + | Some { eexpr = TFunction function_def } -> + let nonVirtual = has_meta_key field.cf_meta Meta.NonVirtual in + let doDynamic = (nonVirtual || not (is_override class_def field.cf_name ) ) && (reflective class_def field ) in + if ( is_dynamic_haxe_method field ) then begin + if ( doDynamic ) then begin + output ("Dynamic " ^ remap_name ^ ";\n"); + output (if is_static then "\t\tstatic " else "\t\t"); + output ("inline Dynamic &" ^ remap_name ^ "_dyn() " ^ "{return " ^ remap_name^ "; }\n") + end + end else begin + let return_type = (type_string function_def.tf_type) in + + if ( not is_static && not nonVirtual ) then output "virtual "; + output (if return_type="Void" && (has_meta_key field.cf_meta Meta.Void) then "void" else return_type ); + + output (" " ^ remap_name ^ "( " ); + output (gen_arg_list function_def.tf_args "" ); + output ");\n"; + if ( doDynamic ) then begin + output (if is_static then "\t\tstatic " else "\t\t"); + output ("Dynamic " ^ remap_name ^ "_dyn();\n" ) + end; + end; + output "\n"; + | _ when has_decl -> + output ( remap_name ^ "_decl " ^ remap_name ^ ";\n" ); + (* Variable access *) + | _ -> + (* Variable access *) + gen_type ctx field.cf_type; + output (" " ^ remap_name ^ ";\n" ); + + (* Add a "dyn" function for variable to unify variable/function access *) + (match follow field.cf_type with + | _ when nativeGen -> () + | TFun (_,_) -> + output (if is_static then "\t\tstatic " else "\t\t"); + gen_type ctx field.cf_type; + output (" &" ^ remap_name ^ "_dyn() { return " ^ remap_name ^ ";}\n" ) + | _ -> (match field.cf_kind with + | Var { v_read = AccCall } when (not is_static) && (is_dynamic_accessor ("get_" ^ field.cf_name) "get" field class_def) -> + output ("\t\tDynamic get_" ^ field.cf_name ^ ";\n" ) + | _ -> () + ); + (match field.cf_kind with + | Var { v_write = AccCall } when (not is_static) && (is_dynamic_accessor ("set_" ^ field.cf_name) "set" field class_def) -> + output ("\t\tDynamic set_" ^ field.cf_name ^ ";\n" ) + | _ -> () + ) + ) + ); end - ;; + ;; -let path_of_string verbatim path = - if verbatim then ( ["@verbatim"], path ) else - match List.rev (Str.split_delim (Str.regexp "/") path ) with - | [] -> ([],"") - | [single] -> ([],single) - | head :: rest -> (List.rev rest, head) +let path_of_string path = + ["@verbatim"], path ;; + (* - Get a list of all classes referred to by the class/enum definition - These are used for "#include"ing the appropriate header files, + Get a list of all classes referred to by the class/enum definition + These are used for "#include"ing the appropriate header files, or for building the dependencies in the Build.xml file *) let find_referenced_types ctx obj super_deps constructor_deps header_only for_depends include_super_args = - let types = ref PMap.empty in - let rec add_type in_path = - if ( not (PMap.mem in_path !types)) then begin - types := (PMap.add in_path () !types); - try - List.iter add_type (Hashtbl.find super_deps in_path); - with Not_found -> () - end - in - let add_extern_class klass = - let include_file = get_meta_string klass.cl_meta (if for_depends then Meta.Depend else Meta.Include) in + let types = ref PMap.empty in + let rec add_type in_path = + if ( not (PMap.mem in_path !types)) then begin + types := (PMap.add in_path () !types); + try + List.iter add_type (Hashtbl.find super_deps in_path); + with Not_found -> () + end + in + let add_extern_class klass = + let include_file = get_meta_string_path klass.cl_meta (if for_depends then Meta.Depend else Meta.Include) in if (include_file<>"") then - add_type ( path_of_string for_depends include_file ) + add_type ( path_of_string include_file ) else if (not for_depends) && (has_meta_key klass.cl_meta Meta.Include) then add_type klass.cl_path in - let rec visit_type in_type = - match (follow in_type) with - | TMono r -> (match !r with None -> () | Some t -> visit_type t) - (*| TEnum ({ e_path = ([],"Void") },[]) -> () - | TEnum ({ e_path = ([],"Bool") },[]) -> () *) - | 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 or Class class, for which we do a fully typed object *) - | TInst (klass,params) -> - (match klass.cl_path with - | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") -> List.iter visit_type params - | (["cpp"],"CppInt32__") -> add_type klass.cl_path; - | _ when klass.cl_extern -> add_extern_class klass - | _ -> (match klass.cl_kind with KTypeParameter _ -> () | _ -> add_type klass.cl_path); - ) - | TFun (args,haxe_type) -> visit_type haxe_type; - List.iter (fun (_,_,t) -> visit_type t; ) args; - | TAbstract (abs,pl) when abs.a_impl <> None -> - visit_type (Codegen.Abstract.get_underlying_type abs pl) - | _ -> () - in - let rec visit_types expression = - begin - let rec visit_expression = fun expression -> - (* Expand out TTypeExpr (ie, the name of a class, as used for static access etc ... *) - (match expression.eexpr with - | TTypeExpr type_def -> ( match type_def with - | TClassDecl class_def when class_def.cl_extern -> add_extern_class class_def - | _ -> add_type (t_path type_def) + let add_native_gen_class klass = + let include_file = get_meta_string_path klass.cl_meta (if for_depends then Meta.Depend else Meta.Include) in + if (include_file<>"") then + add_type ( path_of_string include_file ) + else if for_depends then + add_type klass.cl_path + else + add_type ( path_of_string ( (join_class_path klass.cl_path "/") ^ ".h") ) + in + let visited = ref [] in + let rec visit_type in_type = + 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) + | 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 *) + | TInst (klass,params) -> + (match klass.cl_path with + | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") + | (["cpp"],"Pointer") | (["cpp"],"ConstPointer") | (["cpp"],"Function") + | (["cpp"],"RawPointer") | (["cpp"],"RawConstPointer") -> List.iter visit_type params + | _ when is_native_gen_class klass -> add_native_gen_class klass + | _ when is_extern_class klass -> add_extern_class klass + | _ -> (match klass.cl_kind with KTypeParameter _ -> () | _ -> add_type klass.cl_path); + ) + | TFun (args,haxe_type) -> visit_type haxe_type; + List.iter (fun (_,_,t) -> visit_type t; ) args; + | _ -> () + end; + visited := List.tl !visited; + end + in + let rec visit_params expression = + begin + let rec visit_expression = fun expression -> + (* Expand out TTypeExpr (ie, the name of a class, as used for static access etc ... *) + (match expression.eexpr with + | TTypeExpr type_def -> ( match type_def with + | TClassDecl class_def when is_native_gen_class class_def -> add_native_gen_class class_def + | TClassDecl class_def when is_extern_class class_def -> add_extern_class class_def + | _ -> add_type (t_path type_def) ) - (* Must visit the types, Type.iter will visit the expressions ... *) - | TTry (e,catches) -> - List.iter (fun (v,_) -> visit_type v.v_type) catches - (* Must visit the enum param types, Type.iter will visit the rest ... *) - | TMatch (_,enum,cases,_) -> - add_type (fst enum).e_path; - List.iter (fun (case_ids,params,expression) -> - (match params with - | None -> () - | Some l -> List.iter (function None -> () | Some v -> visit_type v.v_type) l ) ) cases; - (* Must visit type too, Type.iter will visit the expressions ... *) + (* Must visit the types, Type.iter will visit the expressions ... *) + | TTry (e,catches) -> + List.iter (fun (v,_) -> visit_type v.v_type) catches + (* Must visit the enum param types, Type.iter will visit the rest ... *) +(* | TMatch (_,enum,cases,_) -> + add_type (fst enum).e_path; + List.iter (fun (case_ids,params,expression) -> + (match params with + | None -> () + | Some l -> List.iter (function None -> () | Some v -> visit_type v.v_type) l ) ) cases; *) + (* Must visit type too, Type.iter will visit the expressions ... *) | TNew (klass,params,_) -> begin visit_type (TInst (klass,params)); try let construct_type = Hashtbl.find constructor_deps klass.cl_path in - visit_type construct_type.cf_type + visit_type construct_type.cf_type with Not_found -> (); end - (* Must visit type too, Type.iter will visit the expressions ... *) - | TVars var_list -> - List.iter (fun (v, _) -> visit_type v.v_type) var_list - (* Must visit args too, Type.iter will visit the expressions ... *) - | TFunction func_def -> - List.iter (fun (v,_) -> visit_type v.v_type) func_def.tf_args; - | TConst TSuper -> - (match expression.etype with - | TInst (klass,params) -> - (try let construct_type = Hashtbl.find constructor_deps klass.cl_path in - visit_type construct_type.cf_type - with Not_found -> () ) - | _ -> print_endline ("TSuper : Odd etype?") - ) - | _ -> () - ); - Type.iter visit_expression expression; - visit_type (follow expression.etype) - in - visit_expression expression - end - in - let visit_field field = - (* Add the type of the expression ... *) - visit_type field.cf_type; - if (not header_only) then - (match field.cf_expr with - | Some expression -> visit_types expression | _ -> ()); - in - let visit_class class_def = - let fields = List.append class_def.cl_ordered_fields class_def.cl_ordered_statics in - let fields_and_constructor = List.append fields - (match class_def.cl_constructor with | Some expr -> [expr] | _ -> [] ) in - List.iter visit_field fields_and_constructor; - if (include_super_args) then + (* Must visit type too, Type.iter will visit the expressions ... *) + | TVar (v,_) -> + visit_type v.v_type + (* Must visit enum type too, Type.iter will visit the expressions ... *) + | TEnumParameter (_,ef,_) -> visit_type (follow ef.ef_type) + (* Must visit args too, Type.iter will visit the expressions ... *) + | TFunction func_def -> + List.iter (fun (v,_) -> visit_type v.v_type) func_def.tf_args; + | TConst TSuper -> + (match follow expression.etype with + | TInst (klass,params) -> + (try let construct_type = Hashtbl.find constructor_deps klass.cl_path in + visit_type construct_type.cf_type + with Not_found -> () ) + | _ -> print_endline ("TSuper : Odd etype ?" ^ ( (type_string expression.etype)) ) + ) + | _ -> () + ); + Type.iter visit_expression expression; + visit_type (follow expression.etype) + in + visit_expression expression + end + in + let visit_field field = + (* Add the type of the expression ... *) + visit_type field.cf_type; + if (not header_only) then + (match field.cf_expr with + | Some expression -> visit_params expression | _ -> ()); + in + let visit_class class_def = + let fields = List.append class_def.cl_ordered_fields class_def.cl_ordered_statics in + let fields_and_constructor = List.append fields + (match class_def.cl_constructor with | Some expr -> [expr] | _ -> [] ) in + List.iter visit_field fields_and_constructor; + if (include_super_args) then List.iter visit_field (List.map (fun (a,_,_) -> a ) (all_virtual_functions class_def )); - (* Add super & interfaces *) - add_type class_def.cl_path; - in - let visit_enum enum_def = - add_type enum_def.e_path; - PMap.iter (fun _ constructor -> - (match constructor.ef_type with - | TFun (args,_) -> - List.iter (fun (_,_,t) -> visit_type t; ) args; - | _ -> () ); - ) enum_def.e_constrs; - if (not header_only) then begin - let meta = Codegen.build_metadata ctx (TEnumDecl enum_def) in - match meta with Some expr -> visit_types expr | _ -> (); - end; - in - let inc_cmp i1 i2 = - String.compare (join_class_path i1 ".") (join_class_path i2 ".") - in - - (* Body of main function *) - (match obj with - | TClassDecl class_def -> visit_class class_def; - (match class_def.cl_init with Some expression -> visit_types expression | _ -> ()) - | TEnumDecl enum_def -> visit_enum enum_def - | TTypeDecl _ | TAbstractDecl _ -> (* These are expanded *) ()); - - List.sort inc_cmp (List.filter (fun path -> (include_class_header path) ) (pmap_keys !types)) - ;; + (* Add super & interfaces *) + if is_native_gen_class class_def then + add_native_gen_class class_def + else + add_type class_def.cl_path; + in + let visit_enum enum_def = + add_type enum_def.e_path; + PMap.iter (fun _ constructor -> + (match constructor.ef_type with + | TFun (args,_) -> + List.iter (fun (_,_,t) -> visit_type t; ) args; + | _ -> () ); + ) enum_def.e_constrs; + if (not header_only) then begin + let meta = Codegen.build_metadata ctx (TEnumDecl enum_def) in + match meta with Some expr -> visit_params expr | _ -> (); + end; + in + let inc_cmp i1 i2 = + String.compare (join_class_path i1 ".") (join_class_path i2 ".") + in + (* Body of main function *) + (match obj with + | TClassDecl class_def -> visit_class class_def; + (match class_def.cl_init with Some expression -> visit_params expression | _ -> ()) + | TEnumDecl enum_def -> visit_enum enum_def + | TTypeDecl _ | TAbstractDecl _ -> (* These are expanded *) ()); + List.sort inc_cmp (List.filter (fun path -> (include_class_header path) ) (pmap_keys !types)) + ;; + + +let generate_main_header output_main = + output_main "#include \n\n"; + output_main "#include \n\n"; + output_main "extern \"C\" void __hxcpp_main();\n\n"; + output_main "extern \"C\" void __hxcpp_lib_main();\n\n" +;; + +let generate_main_footer1 output_main = + output_main "void __hxcpp_main() {\n";; + +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 " __boot_all();\n"; + output_main " __hxcpp_main();\n"; + output_main " }\n" +;; let generate_main common_ctx member_types super_deps class_def file_info = - (* main routine should be a single static function *) - let main_expression = - (match class_def.cl_ordered_statics with - | [{ cf_expr = Some expression }] -> expression; - | _ -> assert false ) in + (* main routine should be a single static function *) + let main_expression = + (match class_def.cl_ordered_statics with + | [{ cf_expr = Some expression }] -> expression; + | _ -> assert false ) in ignore(find_referenced_types common_ctx (TClassDecl class_def) super_deps (Hashtbl.create 0) false false false); let depend_referenced = find_referenced_types common_ctx (TClassDecl class_def) super_deps (Hashtbl.create 0) false true false in - let generate_startup filename is_main = - (*make_class_directories base_dir ( "src" :: []);*) - let cpp_file = new_cpp_file common_ctx.file ([],filename) in - let output_main = (cpp_file#write) in - - output_main "#include \n\n"; - output_main "#include \n\n"; - - List.iter ( add_include cpp_file ) depend_referenced; - output_main "\n\n"; - - output_main ( if is_main then "HX_BEGIN_MAIN\n\n" else "HX_BEGIN_LIB_MAIN\n\n" ); - gen_expression (new_context common_ctx cpp_file false file_info) false main_expression; - output_main ";\n"; - output_main ( if is_main then "HX_END_MAIN\n\n" else "HX_END_LIB_MAIN\n\n" ); - cpp_file#close; - in - generate_startup "__main__" true; - generate_startup "__lib__" false + let generate_startup filename is_main = + (*make_class_directories base_dir ( "src" :: []);*) + let cpp_file = new_cpp_file common_ctx common_ctx.file ([],filename) in + let output_main = (cpp_file#write) in + + generate_main_header output_main; + + List.iter ( add_include cpp_file ) depend_referenced; + output_main "\n\n"; + + if is_main then output_main "\n#include \n\n"; + + generate_main_footer1 output_main; + gen_expression (new_context common_ctx cpp_file 1 file_info) false main_expression; + output_main ";\n"; + generate_main_footer2 output_main; + cpp_file#close; + in + generate_startup "__main__" true; + generate_startup "__lib__" false ;; let generate_dummy_main common_ctx = - let generate_startup filename is_main = - let main_file = new_cpp_file common_ctx.file ([],filename) in - let output_main = (main_file#write) in - output_main "#include \n\n"; - output_main "#include \n\n"; - output_main ( if is_main then "HX_BEGIN_MAIN\n\n" else "HX_BEGIN_LIB_MAIN\n\n" ); - output_main ( if is_main then "HX_END_MAIN\n\n" else "HX_END_LIB_MAIN\n\n" ); - main_file#close; - in - generate_startup "__main__" true; - generate_startup "__lib__" false + let generate_startup filename is_main = + let main_file = new_cpp_file common_ctx common_ctx.file ([],filename) in + let output_main = (main_file#write) in + generate_main_header output_main; + if is_main then output_main "\n#include \n\n"; + generate_main_footer1 output_main; + generate_main_footer2 output_main; + main_file#close; + in + generate_startup "__main__" true; + generate_startup "__lib__" false ;; -let generate_boot common_ctx boot_classes init_classes = - (* Write boot class too ... *) - let base_dir = common_ctx.file in - let boot_file = new_cpp_file base_dir ([],"__boot__") in - let output_boot = (boot_file#write) in - output_boot "#include \n\n"; - List.iter ( fun class_path -> - output_boot ("#include <" ^ - ( join_class_path class_path "/" ) ^ ".h>\n") - ) boot_classes; - - output_boot "\nvoid __boot_all()\n{\n"; - output_boot "hx::RegisterResources( hx::GetResources() );\n"; - List.iter ( fun class_path -> - output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__register();\n") ) boot_classes; - List.iter ( fun class_path -> - output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__init__();\n") ) (List.rev init_classes); +let generate_boot common_ctx boot_enums boot_classes nonboot_classes init_classes = + (* Write boot class too ... *) + let base_dir = common_ctx.file in + let boot_file = new_cpp_file common_ctx base_dir ([],"__boot__") in + let output_boot = (boot_file#write) in + output_boot "#include \n\n"; + List.iter ( fun class_path -> boot_file#add_include class_path ) + (boot_enums @ boot_classes @ nonboot_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"; + List.iter ( fun class_path -> + output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__register();\n") ) + (boot_enums @ boot_classes @ nonboot_classes); + let dump_boot = - List.iter ( fun class_path -> - output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__boot();\n") ) in + List.iter ( fun class_path -> + output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__boot();\n") ) in + + dump_boot boot_enums; + + List.iter ( fun class_path -> + output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__init__();\n") ) (List.rev init_classes); + dump_boot (List.filter (fun path -> is_cpp_class path ) (List.rev boot_classes)); dump_boot (List.filter (fun path -> not (is_cpp_class path) ) (List.rev boot_classes)); - output_boot "}\n\n"; - boot_file#close;; + output_boot "}\n\n"; + boot_file#close;; let generate_files common_ctx file_info = - (* Write __files__ class too ... *) - let base_dir = common_ctx.file in - let files_file = new_cpp_file base_dir ([],"__files__") in - let output_files = (files_file#write) in - output_files "#include \n\n"; - output_files "namespace hx {\n"; - output_files "const char *__hxcpp_all_files[] = {\n"; - output_files "#ifdef HXCPP_DEBUGGER\n"; - List.iter ( fun file -> output_files (" " ^ file ^ ",\n" ) ) ( List.sort String.compare ( pmap_keys !file_info) ); - output_files "#endif\n"; - output_files " 0 };\n"; - output_files "const char *__hxcpp_class_path[] = {\n"; - output_files "#ifdef HXCPP_DEBUGGER\n"; - List.iter ( fun file -> output_files (" \"" ^ file ^ "\",\n" ) ) (common_ctx.class_path @ common_ctx.std_path); - output_files "#endif\n"; - output_files " 0 };\n"; - output_files "} // namespace hx\n"; - files_file#close;; + (* Write __files__ class too ... *) + let base_dir = common_ctx.file in + let files_file = new_cpp_file common_ctx base_dir ([],"__files__") in + let output_files = (files_file#write) in + let types = common_ctx.types in + output_files "#include \n\n"; + output_files "namespace hx {\n"; + output_files "const char *__hxcpp_all_files[] = {\n"; + output_files "#ifdef HXCPP_DEBUGGER\n"; + List.iter ( fun file -> output_files ((const_char_star file)^",\n" ) ) + ( List.sort String.compare ( pmap_keys !file_info) ); + output_files "#endif\n"; + output_files " 0 };\n"; + output_files "\n"; + + output_files "const char *__hxcpp_all_files_fullpath[] = {\n"; + output_files "#ifdef HXCPP_DEBUGGER\n"; + List.iter ( fun file -> output_files ((const_char_star ( + Common.get_full_path (try Common.find_file common_ctx file with Not_found -> file) + ))^",\n" ) ) + ( List.sort String.compare ( pmap_keys !file_info) ); + output_files "#endif\n"; + output_files " 0 };\n"; + output_files "\n"; + + + output_files "const char *__hxcpp_all_classes[] = {\n"; + output_files "#ifdef HXCPP_DEBUGGER\n"; + List.iter ( fun object_def -> + (match object_def with + | TClassDecl class_def when is_extern_class class_def -> ( ) + | TClassDecl class_def when class_def.cl_interface -> ( ) + | TClassDecl class_def -> + output_files ((const_char_star (join_class_path class_def.cl_path "." )) ^ ",\n") + | _ -> ( ) + ) + ) types; + output_files "#endif\n"; + 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"; + + files_file#close;; let begin_header_file output_h def_string = - output_h ("#ifndef INCLUDED_" ^ def_string ^ "\n"); - output_h ("#define INCLUDED_" ^ def_string ^ "\n\n"); - output_h "#ifndef HXCPP_H\n"; - output_h "#include \n"; - output_h "#endif\n\n";; + output_h ("#ifndef INCLUDED_" ^ def_string ^ "\n"); + output_h ("#define INCLUDED_" ^ def_string ^ "\n\n"); + output_h "#ifndef HXCPP_H\n"; + output_h "#include \n"; + output_h "#endif\n\n";; let end_header_file output_h def_string = - output_h ("\n#endif /* INCLUDED_" ^ def_string ^ " */ \n");; + output_h ("\n#endif /* INCLUDED_" ^ def_string ^ " */ \n");; let new_placed_cpp_file common_ctx class_path = - let base_dir = common_ctx.file in - if (Common.defined common_ctx Define.Vcproj ) then begin - make_class_directories base_dir ("src"::[]); - cached_source_writer - ( base_dir ^ "/src/" ^ ( String.concat "-" (fst class_path) ) ^ "-" ^ - (snd class_path) ^ ".cpp") - end else - new_cpp_file common_ctx.file class_path;; + let base_dir = common_ctx.file in + + if (Common.defined common_ctx Define.Vcproj ) then begin + make_class_directories base_dir ("src"::[]); + cached_source_writer common_ctx + ( base_dir ^ "/src/" ^ ( String.concat "-" (fst class_path) ) ^ "-" ^ + (snd class_path) ^ (source_file_extension common_ctx) ) + end else + new_cpp_file common_ctx common_ctx.file class_path;; let generate_enum_files common_ctx enum_def super_deps meta file_info = - let class_path = enum_def.e_path in - let just_class_name = (snd class_path) in - let class_name = just_class_name ^ "_obj" in - let smart_class_name = ("::" ^ (join_class_path class_path "::") ) in - (*let cpp_file = new_cpp_file common_ctx.file class_path in*) - let cpp_file = new_placed_cpp_file common_ctx class_path in - let output_cpp = (cpp_file#write) in - let debug = false in - let ctx = new_context common_ctx cpp_file debug file_info in - - if (debug) then - print_endline ("Found enum definition:" ^ (join_class_path class_path "::" )); - - output_cpp "#include \n\n"; - - let referenced = find_referenced_types common_ctx (TEnumDecl enum_def) super_deps (Hashtbl.create 0) false false false in - List.iter (add_include cpp_file) referenced; - - gen_open_namespace output_cpp class_path; - output_cpp "\n"; - - PMap.iter (fun _ constructor -> - let name = keyword_remap constructor.ef_name in - match constructor.ef_type with - | TFun (args,_) -> - output_cpp (smart_class_name ^ " " ^ class_name ^ "::" ^ name ^ "(" ^ - (gen_tfun_arg_list args) ^")\n"); - output_cpp (" { return hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^ - (string_of_int constructor.ef_index) ^ ",hx::DynamicArray(0," ^ - (string_of_int (List.length args)) ^ ")" ); - List.iter (fun (arg,_,_) -> output_cpp (".Add(" ^ (keyword_remap arg) ^ ")")) args; - output_cpp "); }\n\n" - - | _ -> - output_cpp ( smart_class_name ^ " " ^ class_name ^ "::" ^ name ^ ";\n\n" ) - ) enum_def.e_constrs; - - - - - output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n"); - output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n"); - PMap.iter (fun _ constructor -> - let name = constructor.ef_name in - let idx = string_of_int constructor.ef_index in - output_cpp (" if (inName==" ^ (str name) ^ ") return " ^ idx ^ ";\n") ) enum_def.e_constrs; - output_cpp (" return super::__FindIndex(inName);\n"); - output_cpp ("}\n\n"); - - let constructor_arg_count constructor = - (match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 ) - in - - - (* Dynamic versions of constructors *) - let dump_dynamic_constructor _ constr = - let count = constructor_arg_count constr in - if (count>0) then begin - let nargs = string_of_int count in - output_cpp ("STATIC_HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^ - (keyword_remap constr.ef_name) ^ ",return)\n\n"); - end - in - PMap.iter dump_dynamic_constructor enum_def.e_constrs; - - - output_cpp ("int " ^ class_name ^ "::__FindArgCount(::String inName)\n{\n"); - PMap.iter (fun _ constructor -> - let name = constructor.ef_name in - let count = string_of_int (constructor_arg_count constructor) in - output_cpp (" if (inName==" ^ (str name) ^ ") return " ^ count ^ ";\n") ) enum_def.e_constrs; - output_cpp (" return super::__FindArgCount(inName);\n"); - output_cpp ("}\n\n"); - - (* Dynamic "Get" Field function - string version *) - output_cpp ("Dynamic " ^ class_name ^ "::__Field(const ::String &inName,bool inCallProp)\n{\n"); - let dump_constructor_test _ constr = - output_cpp (" if (inName==" ^ (str constr.ef_name) ^ ") return " ^ - (keyword_remap constr.ef_name) ); - if ( (constructor_arg_count constr) > 0 ) then output_cpp "_dyn()"; - output_cpp (";\n") - in - PMap.iter dump_constructor_test enum_def.e_constrs; - output_cpp (" return super::__Field(inName,inCallProp);\n}\n\n"); - - output_cpp "static ::String sStaticFields[] = {\n"; - let sorted = - List.sort (fun f1 f2 -> (PMap.find f1 enum_def.e_constrs ).ef_index - - (PMap.find f2 enum_def.e_constrs ).ef_index ) - (pmap_keys enum_def.e_constrs) in - - List.iter (fun name -> output_cpp (" " ^ (str name) ^ ",\n") ) sorted; - - output_cpp " ::String(null()) };\n\n"; - - (* ENUM - Mark static as used by GC *) - output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n"; - PMap.iter (fun _ constructor -> - let name = keyword_remap constructor.ef_name in - match constructor.ef_type with - | TFun (_,_) -> () - | _ -> output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") ) - enum_def.e_constrs; - output_cpp "};\n\n"; - - (* ENUM - Visit static as used by GC *) - output_cpp "static void sVisitStatic(HX_VISIT_PARAMS) {\n"; - output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); - PMap.iter (fun _ constructor -> - let name = keyword_remap constructor.ef_name in - match constructor.ef_type with - | TFun (_,_) -> () - | _ -> output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") ) - enum_def.e_constrs; - output_cpp "};\n\n"; - - output_cpp "static ::String sMemberFields[] = { ::String(null()) };\n"; - - output_cpp ("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 = str (join_class_path class_path ".") in - output_cpp ("\nhx::Static(__mClass) = hx::RegisterClass(" ^ text_name ^ - ", hx::TCanCast< " ^ class_name ^ " >,sStaticFields,sMemberFields,\n"); - output_cpp (" &__Create_" ^ class_name ^ ", &__Create,\n"); - output_cpp (" &super::__SGetClass(), &Create" ^ class_name ^ ", sMarkStatics, sVisitStatic);\n"); - output_cpp ("}\n\n"); - - output_cpp ("void " ^ class_name ^ "::__boot()\n{\n"); - (match meta with - | Some expr -> - let ctx = new_context common_ctx cpp_file false file_info in - find_local_functions_and_return_blocks_ctx ctx true expr; - output_cpp ("__mClass->__meta__ = "); - gen_expression ctx true expr; - output_cpp ";\n" - | _ -> () ); - PMap.iter (fun _ constructor -> - let name = constructor.ef_name in - match constructor.ef_type with - | TFun (_,_) -> () - | _ -> - output_cpp ( "hx::Static(" ^ (keyword_remap name) ^ ") = hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^ - (string_of_int constructor.ef_index) ^ ");\n" ) - ) enum_def.e_constrs; - output_cpp ("}\n\n"); - - - - - output_cpp "\n"; - gen_close_namespace output_cpp class_path; - cpp_file#close; - - let h_file = new_header_file common_ctx.file class_path in - let super = "hx::EnumBase_obj" in - let output_h = (h_file#write) in - let def_string = join_class_path class_path "_" in - ctx.ctx_output <- output_h; - - begin_header_file output_h def_string; - - List.iter (gen_forward_decl h_file ) referenced; - - gen_open_namespace output_h class_path; - - output_h "\n\n"; - output_h ("class " ^ class_name ^ " : public " ^ super ^ "\n"); - output_h ("{\n typedef " ^ super ^ " super;\n"); - output_h (" typedef " ^ class_name ^ " OBJ_;\n"); - output_h "\n public:\n"; - output_h (" " ^ class_name ^ "() {};\n"); - output_h (" HX_DO_ENUM_RTTI;\n"); - output_h (" static void __boot();\n"); - output_h (" static void __register();\n"); - output_h (" ::String GetEnumName( ) const { return " ^ - (str (join_class_path class_path ".")) ^ "; }\n" ); - output_h (" ::String __ToString() const { return " ^ - (str (just_class_name ^ ".") )^ " + tag; }\n\n"); - - - PMap.iter (fun _ constructor -> - let name = keyword_remap constructor.ef_name in - output_h ( " static " ^ smart_class_name ^ " " ^ name ); - match constructor.ef_type with - | TFun (args,_) -> - output_h ( "(" ^ (gen_tfun_arg_list args) ^");\n"); - output_h ( " static Dynamic " ^ name ^ "_dyn();\n"); - | _ -> - output_h ";\n"; - output_h ( " static inline " ^ smart_class_name ^ " " ^ name ^ + let class_path = enum_def.e_path in + let just_class_name = (snd class_path) in + let class_name = just_class_name ^ "_obj" in + let remap_class_name = ("::" ^ (join_class_path_remap class_path "::") ) in + (*let cpp_file = new_cpp_file common_ctx.file class_path in*) + let cpp_file = new_placed_cpp_file common_ctx class_path in + let output_cpp = (cpp_file#write) in + let debug = if (has_meta_key enum_def.e_meta Meta.NoDebug) || ( Common.defined common_ctx Define.NoDebug) + then 0 else 1 in + + let ctx = new_context common_ctx cpp_file debug file_info in + + if (debug>1) then + print_endline ("Found enum definition:" ^ (join_class_path class_path "::" )); + + output_cpp "#include \n\n"; + + let referenced = find_referenced_types common_ctx (TEnumDecl enum_def) super_deps (Hashtbl.create 0) false false false in + List.iter (add_include cpp_file) referenced; + + gen_open_namespace output_cpp class_path; + output_cpp "\n"; + + PMap.iter (fun _ constructor -> + let name = keyword_remap constructor.ef_name in + match constructor.ef_type with + | TFun (args,_) -> + output_cpp (remap_class_name ^ " " ^ class_name ^ "::" ^ name ^ "(" ^ + (gen_tfun_arg_list args) ^")\n"); + output_cpp ("\t{ return hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^ + (string_of_int constructor.ef_index) ^ ",hx::DynamicArray(0," ^ + (string_of_int (List.length args)) ^ ")" ); + List.iter (fun (arg,_,_) -> output_cpp (".Add(" ^ (keyword_remap arg) ^ ")")) args; + output_cpp "); }\n\n" + + | _ -> + output_cpp ( remap_class_name ^ " " ^ class_name ^ "::" ^ name ^ ";\n\n" ) + ) enum_def.e_constrs; + + + + + output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n"); + output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n"); + PMap.iter (fun _ constructor -> + let name = constructor.ef_name in + let idx = string_of_int constructor.ef_index in + output_cpp ("\tif (inName==" ^ (str name) ^ ") return " ^ idx ^ ";\n") ) enum_def.e_constrs; + output_cpp ("\treturn super::__FindIndex(inName);\n"); + output_cpp ("}\n\n"); + + let constructor_arg_count constructor = + (match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 ) + in + + + (* Dynamic versions of constructors *) + let dump_dynamic_constructor _ constr = + let count = constructor_arg_count constr in + if (count>0) then begin + let nargs = string_of_int count in + output_cpp ("STATIC_HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^ + (keyword_remap constr.ef_name) ^ ",return)\n\n"); + end + in + PMap.iter dump_dynamic_constructor enum_def.e_constrs; + + + output_cpp ("int " ^ class_name ^ "::__FindArgCount(::String inName)\n{\n"); + PMap.iter (fun _ constructor -> + let name = constructor.ef_name in + let count = string_of_int (constructor_arg_count constructor) in + output_cpp ("\tif (inName==" ^ (str name) ^ ") return " ^ count ^ ";\n") ) enum_def.e_constrs; + output_cpp ("\treturn super::__FindArgCount(inName);\n"); + output_cpp ("}\n\n"); + + (* Dynamic "Get" Field function - string version *) + output_cpp ("Dynamic " ^ class_name ^ "::__Field(const ::String &inName,hx::PropertyAccess inCallProp)\n{\n"); + let dump_constructor_test _ constr = + output_cpp ("\tif (inName==" ^ (str constr.ef_name) ^ ") return " ^ + (keyword_remap constr.ef_name) ); + if ( (constructor_arg_count constr) > 0 ) then output_cpp "_dyn()"; + output_cpp (";\n") + in + PMap.iter dump_constructor_test enum_def.e_constrs; + output_cpp ("\treturn super::__Field(inName,inCallProp);\n}\n\n"); + + output_cpp "static ::String sStaticFields[] = {\n"; + let sorted = + List.sort (fun f1 f2 -> (PMap.find f1 enum_def.e_constrs ).ef_index - + (PMap.find f2 enum_def.e_constrs ).ef_index ) + (pmap_keys enum_def.e_constrs) in + + List.iter (fun name -> output_cpp ("\t" ^ (str name) ^ ",\n") ) sorted; + + output_cpp "\t::String(null()) };\n\n"; + + (* ENUM - Mark static as used by GC *) + output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n"; + PMap.iter (fun _ constructor -> + let name = keyword_remap constructor.ef_name in + match constructor.ef_type with + | TFun (_,_) -> () + | _ -> output_cpp ("\tHX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") ) + enum_def.e_constrs; + output_cpp "};\n\n"; + + (* ENUM - Visit static as used by GC *) + output_cpp "#ifdef HXCPP_VISIT_ALLOCS\n"; + output_cpp "static void sVisitStatic(HX_VISIT_PARAMS) {\n"; + output_cpp ("\tHX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); + PMap.iter (fun _ constructor -> + let name = keyword_remap constructor.ef_name in + match constructor.ef_type with + | TFun (_,_) -> () + | _ -> output_cpp ("\tHX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") ) + enum_def.e_constrs; + output_cpp "};\n"; + output_cpp "#endif\n\n"; + + output_cpp "static ::String sMemberFields[] = { ::String(null()) };\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 = str (join_class_path class_path ".") in + output_cpp ("\nhx::Static(__mClass) = hx::RegisterClass(" ^ text_name ^ + ", hx::TCanCast< " ^ class_name ^ " >,sStaticFields,sMemberFields,\n"); + output_cpp ("\t&__Create_" ^ class_name ^ ", &__Create,\n"); + output_cpp ("\t&super::__SGetClass(), &Create" ^ class_name ^ ", sMarkStatics\n"); + output_cpp("#ifdef HXCPP_VISIT_ALLOCS\n , sVisitStatic\n#endif\n"); + output_cpp ("#ifdef HXCPP_SCRIPTABLE\n , 0\n#endif\n"); + output_cpp (");\n}\n\n"); + + output_cpp ("void " ^ class_name ^ "::__boot()\n{\n"); + (match meta with + | Some expr -> + let ctx = new_context common_ctx cpp_file 1 file_info in + find_local_functions_and_return_blocks_ctx ctx true expr; + output_cpp ("__mClass->__meta__ = "); + gen_expression ctx true expr; + output_cpp ";\n" + | _ -> () ); + PMap.iter (fun _ constructor -> + let name = constructor.ef_name in + match constructor.ef_type with + | TFun (_,_) -> () + | _ -> + output_cpp ( "hx::Static(" ^ (keyword_remap name) ^ ") = hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^ + (string_of_int constructor.ef_index) ^ ");\n" ) + ) enum_def.e_constrs; + output_cpp ("}\n\n"); + + + + + output_cpp "\n"; + gen_close_namespace output_cpp class_path; + cpp_file#close; + + let h_file = new_header_file common_ctx common_ctx.file class_path in + let super = "hx::EnumBase_obj" in + let output_h = (h_file#write) in + let def_string = join_class_path class_path "_" in + ctx.ctx_output <- output_h; + + begin_header_file output_h def_string; + + List.iter (gen_forward_decl h_file ) referenced; + + gen_open_namespace output_h class_path; + + output_h "\n\n"; + output_h ("class " ^ class_name ^ " : public " ^ super ^ "\n"); + output_h ("{\n\ttypedef " ^ super ^ " super;\n"); + output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n"); + output_h "\n\tpublic:\n"; + output_h ("\t\t" ^ class_name ^ "() {};\n"); + 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\t::String GetEnumName( ) const { return " ^ + (str (join_class_path class_path ".")) ^ "; }\n" ); + output_h ("\t\t::String __ToString() const { return " ^ + (str (just_class_name ^ ".") )^ " + tag; }\n\n"); + + + PMap.iter (fun _ constructor -> + let name = keyword_remap constructor.ef_name in + output_h ( "\t\tstatic " ^ remap_class_name ^ " " ^ name ); + match constructor.ef_type with + | TFun (args,_) -> + output_h ( "(" ^ (gen_tfun_arg_list args) ^");\n"); + output_h ( "\t\tstatic Dynamic " ^ name ^ "_dyn();\n"); + | _ -> + output_h ";\n"; + output_h ( "\t\tstatic inline " ^ remap_class_name ^ " " ^ name ^ "_dyn() { return " ^name ^ "; }\n" ); - ) enum_def.e_constrs; + ) enum_def.e_constrs; - output_h "};\n\n"; + output_h "};\n\n"; - gen_close_namespace output_h class_path; + gen_close_namespace output_h class_path; - end_header_file output_h def_string; - h_file#close; - let depend_referenced = find_referenced_types common_ctx (TEnumDecl enum_def) super_deps (Hashtbl.create 0) false true false in - depend_referenced;; + end_header_file output_h def_string; + h_file#close; + let depend_referenced = find_referenced_types common_ctx (TEnumDecl enum_def) super_deps (Hashtbl.create 0) false true false in + depend_referenced;; let list_iteri func in_list = @@ -2765,980 +3343,2441 @@ let list_iteri func in_list = List.iter (fun elem -> func !idx elem; idx := !idx + 1 ) in_list ;; +let has_new_gc_references class_def = + match class_def.cl_dynamic with + | Some _ -> true + | _ -> ( + let is_gc_reference field = + (should_implement_field field) && (is_data_member field) && + match type_string field.cf_type with + | "bool" | "int" | "Float" -> false + | _ -> true + in + List.exists is_gc_reference class_def.cl_ordered_fields + ) +;; + + +let rec has_gc_references class_def = + ( match class_def.cl_super with + | Some def when has_gc_references (fst def) -> true + | _ -> false ) + || has_new_gc_references class_def +;; + +let rec find_next_super_iteration class_def = + match class_def.cl_super with + | Some (klass,params) when has_new_gc_references klass -> class_string klass "_obj" params true + | Some (klass,_) -> find_next_super_iteration klass + | _ -> ""; +;; let has_init_field class_def = - match class_def.cl_init with - | Some _ -> true - | _ -> false;; + match class_def.cl_init with + | Some _ -> true + | _ -> false;; + + +let is_abstract_impl class_def = match class_def.cl_kind with + | KAbstractImpl _ -> true + | _ -> false +;; + +let variable_field field = + (match field.cf_expr with + | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field + | _ -> true) +;; + +let is_readable class_def field = + (match field.cf_kind with + | Var { v_read = AccNever } when (is_extern_field field) -> false + | Var { v_read = AccInline } -> false + | Var _ when is_abstract_impl class_def -> false + | _ -> true) +;; + +let is_writable class_def field = + (match field.cf_kind with + | Var { v_write = AccNever } when (is_extern_field field) -> false + | Var { v_read = AccInline } -> false + | Var _ when is_abstract_impl class_def -> false + | _ -> true) +;; + + +let statics_except_meta class_def = (List.filter (fun static -> static.cf_name <> "__meta__" && static.cf_name <> "__rtti") class_def.cl_ordered_statics);; + +let has_set_member_field class_def = + implement_dynamic_here class_def || ( + let reflect_fields = List.filter (reflective class_def) (class_def.cl_ordered_fields) in + let reflect_writable = List.filter (is_writable class_def) reflect_fields in + List.exists variable_field reflect_writable + ) +;; + + +let has_set_static_field class_def = + let reflect_fields = List.filter (reflective class_def) (class_def.cl_ordered_fields) in + let reflect_writable = List.filter (is_writable class_def) reflect_fields in + List.exists variable_field reflect_writable +;; + + +let has_get_fields class_def = + implement_dynamic_here class_def || ( + let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in + List.exists is_data_field class_def.cl_ordered_fields + ) +;; + +let has_get_member_field class_def = + implement_dynamic_here class_def || ( + let reflect_fields = List.filter (reflective class_def) (class_def.cl_ordered_fields) in + List.exists (is_readable class_def) reflect_fields + ) +;; + + +let has_get_static_field class_def = + let reflect_fields = List.filter (reflective class_def) (statics_except_meta class_def) in + List.exists (is_readable class_def) reflect_fields +;; + + + + + + + +let has_boot_field class_def = + List.exists has_field_init (List.filter should_implement_field class_def.cl_ordered_statics); +;; + let is_macro meta = - Meta.has Meta.Macro meta + Meta.has Meta.Macro meta ;; let access_str a = match a with - | AccNormal -> "AccNormal" - | AccNo -> "AccNo" - | AccNever -> "AccNever" - | AccResolve -> "AccResolve" - | AccCall -> "AccCall" - | AccInline -> "AccInline" - | AccRequire(_,_) -> "AccRequire" ;; - -let generate_class_files common_ctx member_types super_deps constructor_deps class_def file_info scriptable = - let class_path = class_def.cl_path in - let class_name = (snd class_path) ^ "_obj" in - let is_abstract_impl = match class_def.cl_kind with | KAbstractImpl _ -> true | _ -> false in - let smart_class_name = (snd class_path) in - (*let cpp_file = new_cpp_file common_ctx.file class_path in*) - let cpp_file = new_placed_cpp_file common_ctx class_path in - let output_cpp = (cpp_file#write) in - let debug = false in - let ctx = new_context common_ctx cpp_file debug file_info in - ctx.ctx_class_name <- "::" ^ (join_class_path class_def.cl_path "::"); - ctx.ctx_class_super_name <- (match class_def.cl_super with - | Some (klass, params) -> class_string klass "_obj" params + | AccNormal -> "AccNormal" + | AccNo -> "AccNo" + | AccNever -> "AccNever" + | AccResolve -> "AccResolve" + | AccCall -> "AccCall" + | AccInline -> "AccInline" + | AccRequire(_,_) -> "AccRequire" ;; + +let generate_class_files common_ctx member_types super_deps constructor_deps class_def file_info inScriptable = + let class_path = class_def.cl_path in + let nativeGen = has_meta_key class_def.cl_meta Meta.NativeGen in + let class_name = (snd class_path) ^ (if nativeGen then "" else "_obj") in + let dot_name = join_class_path class_path "." in + let smart_class_name = (snd class_path) in + (*let cpp_file = new_cpp_file common_ctx.file class_path in*) + let cpp_file = new_placed_cpp_file common_ctx class_path in + let output_cpp = (cpp_file#write) in + let debug = if (has_meta_key class_def.cl_meta Meta.NoDebug) || ( Common.defined common_ctx Define.NoDebug) + then 0 else 1 in + let scriptable = inScriptable && not class_def.cl_private in + let ctx = new_context common_ctx cpp_file debug file_info in + + + ctx.ctx_class_name <- "::" ^ (join_class_path class_def.cl_path "::"); + ctx.ctx_class_super_name <- (match class_def.cl_super with + | Some (klass, params) -> class_string klass "_obj" params true | _ -> ""); - ctx.ctx_class_member_types <- member_types; - if debug then print_endline ("Found class definition:" ^ ctx.ctx_class_name); - - let ptr_name = "hx::ObjectPtr< " ^ class_name ^ " >" in - let constructor_type_var_list = - match class_def.cl_constructor with - | Some definition -> - (match definition.cf_expr with - | Some { eexpr = TFunction function_def } -> - List.map (fun (v,o) -> gen_arg_type_name v.v_name o v.v_type "__o_") - function_def.tf_args; - | _ -> - (match follow definition.cf_type with - | TFun (args,_) -> List.map (fun (a,_,t) -> (type_string t,a) ) args - | _ -> []) - ) - | _ -> [] in - let constructor_var_list = List.map snd constructor_type_var_list in - let constructor_type_args = String.concat "," - (List.map (fun (t,a) -> t ^ " " ^ a) constructor_type_var_list) in - let constructor_args = String.concat "," constructor_var_list in - - let implement_dynamic = implement_dynamic_here class_def in - - output_cpp "#include \n\n"; - - let field_integer_dynamic = scriptable || (has_field_integer_lookup class_def) in - let field_integer_numeric = scriptable || (has_field_integer_numeric_lookup class_def) in - - let all_referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps constructor_deps false false scriptable in - List.iter ( add_include cpp_file ) all_referenced; - - - (* All interfaces (and sub-interfaces) implemented *) - let implemented_hash = Hashtbl.create 0 in - List.iter (fun imp -> - let rec descend_interface interface = - let imp_path = (fst interface).cl_path in - let interface_name = "::" ^ (join_class_path imp_path "::" ) in - if ( not (Hashtbl.mem implemented_hash interface_name) ) then begin - Hashtbl.add implemented_hash interface_name (); - List.iter descend_interface (fst interface).cl_implements; - end - in descend_interface imp - ) (real_interfaces class_def.cl_implements); - let implemented = hash_keys implemented_hash in + ctx.ctx_class_member_types <- member_types; + if (debug>1) then print_endline ("Found class definition:" ^ ctx.ctx_class_name); + + let ptr_name = "hx::ObjectPtr< " ^ class_name ^ " >" in + let constructor_arg_var_list = + match class_def.cl_constructor with + | Some definition -> + (match definition.cf_expr with + | Some { eexpr = TFunction function_def } -> + List.map (fun (v,o) -> (v.v_name, gen_arg_type_name v.v_name o v.v_type "__o_")) + function_def.tf_args; + | _ -> + (match follow definition.cf_type with + | TFun (args,_) -> List.map (fun (a,_,t) -> (a, (type_string t, a)) ) args + | _ -> []) + ) + | _ -> [] in + let constructor_type_var_list = + List.map snd constructor_arg_var_list in + let constructor_var_list = List.map snd constructor_type_var_list in + let constructor_type_args = String.concat "," + (List.map (fun (t,a) -> t ^ " " ^ a) constructor_type_var_list) in + let constructor_args = String.concat "," constructor_var_list in + + let implement_dynamic = implement_dynamic_here class_def in + + output_cpp "#include \n\n"; + + let force_field = scriptable && (has_get_member_field class_def) in + let field_integer_dynamic = force_field || (has_field_integer_lookup class_def) in + let field_integer_numeric = force_field || (has_field_integer_numeric_lookup class_def) in + + let all_referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps constructor_deps false false scriptable in + List.iter ( add_include cpp_file ) all_referenced; + + + (* All interfaces (and sub-interfaces) implemented *) + let implemented_hash = Hashtbl.create 0 in + List.iter (fun imp -> + let rec descend_interface interface = + let imp_path = (fst interface).cl_path in + let interface_name = "::" ^ (join_class_path_remap imp_path "::" ) in + if ( not (Hashtbl.mem implemented_hash interface_name) ) then begin + Hashtbl.add implemented_hash interface_name (); + List.iter descend_interface (fst interface).cl_implements; + end; + match (fst interface).cl_super with + | Some (interface,params) -> descend_interface (interface,params) + | _ -> () + in descend_interface imp + ) (real_interfaces class_def.cl_implements); + let implemented = hash_keys implemented_hash in if (scriptable) then output_cpp "#include \n"; - output_cpp ( get_code class_def.cl_meta Meta.CppFileCode ); - - gen_open_namespace output_cpp class_path; - output_cpp "\n"; - - output_cpp ( get_code class_def.cl_meta Meta.CppNamespaceCode ); - - if (not class_def.cl_interface) then begin - output_cpp ("Void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")\n{\n"); - (match class_def.cl_constructor with - | Some definition -> - (match definition.cf_expr with - | Some { eexpr = TFunction function_def } -> - hx_stack_push ctx output_cpp smart_class_name "new" function_def.tf_expr.epos; - if (has_default_values function_def.tf_args) then begin - generate_default_values ctx function_def.tf_args "__o_"; - gen_expression ctx false (to_block function_def.tf_expr); - output_cpp ";\n"; - end else begin - gen_expression ctx false (to_block function_def.tf_expr); - output_cpp ";\n"; - (*gen_expression (new_context common_ctx cpp_file debug ) false function_def.tf_expr;*) - end - | _ -> () - ) - | _ -> ()); - output_cpp " return null();\n"; - output_cpp "}\n\n"; - - (* Destructor goes in the cpp file so we can "see" the full definition of the member vars *) - output_cpp ( class_name ^ "::~" ^ class_name ^ "() { }\n\n"); - output_cpp ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return new " ^ class_name ^ "; }\n"); - - output_cpp (ptr_name ^ " " ^ class_name ^ "::__new(" ^constructor_type_args ^")\n"); - - let create_result () = - output_cpp ("{ " ^ ptr_name ^ " result = new " ^ class_name ^ "();\n"); - in - create_result (); - output_cpp (" result->__construct(" ^ constructor_args ^ ");\n"); - output_cpp (" return result;}\n\n"); - - output_cpp ("Dynamic " ^ class_name ^ "::__Create(hx::DynamicArray inArgs)\n"); - create_result (); - output_cpp (" result->__construct(" ^ (array_arg_list constructor_var_list) ^ ");\n"); - output_cpp (" return result;}\n\n"); - if ( (List.length implemented) > 0 ) then begin - output_cpp ("hx::Object *" ^ class_name ^ "::__ToInterface(const hx::type_info &inType) {\n"); - List.iter (fun interface_name -> - output_cpp (" if (inType==typeid( " ^ interface_name ^ "_obj)) " ^ - "return operator " ^ interface_name ^ "_obj *();\n"); - ) implemented; - output_cpp (" return super::__ToInterface(inType);\n}\n\n"); - end; - - end; - - (match class_def.cl_init with - | Some expression -> - output_cpp ("void " ^ class_name^ "::__init__() {\n"); - hx_stack_push ctx output_cpp smart_class_name "__init__" expression.epos; - gen_expression (new_context common_ctx cpp_file debug file_info) false (to_block expression); - output_cpp "}\n\n"; - | _ -> ()); - - let statics_except_meta = (List.filter (fun static -> static.cf_name <> "__meta__") class_def.cl_ordered_statics) in - let implemented_fields = List.filter should_implement_field statics_except_meta in - let dump_field_name = (fun field -> output_cpp (" " ^ (str field.cf_name) ^ ",\n")) in + output_cpp ( get_class_code class_def Meta.CppFileCode ); + let inc = get_meta_string_path class_def.cl_meta Meta.CppInclude in + if (inc<>"") then + output_cpp ("#include \"" ^ inc ^ "\"\n"); + + gen_open_namespace output_cpp class_path; + output_cpp "\n"; + + output_cpp ( get_class_code class_def Meta.CppNamespaceCode ); + + if (not class_def.cl_interface) && not nativeGen then begin + output_cpp ("Void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")\n{\n"); + (match class_def.cl_constructor with + | Some definition -> + (match definition.cf_expr with + | Some { eexpr = TFunction function_def } -> + if has_meta_key definition.cf_meta Meta.NoDebug then ctx.ctx_debug_level <- 0; + if ctx.ctx_debug_level >0 then begin + hx_stack_push ctx output_cpp dot_name "new" function_def.tf_expr.epos; + output_cpp "HX_STACK_THIS(this)\n"; + List.iter (fun (a,(t,o)) -> output_cpp ("HX_STACK_ARG(" ^ (keyword_remap o) ^ ",\"" ^ a ^"\")\n") ) constructor_arg_var_list; + end; + + if (has_default_values function_def.tf_args) then begin + generate_default_values ctx function_def.tf_args "__o_"; + gen_expression ctx false (to_block function_def.tf_expr); + output_cpp ";\n"; + end else begin + gen_expression ctx false (to_block function_def.tf_expr); + output_cpp ";\n"; + (*gen_expression (new_context common_ctx cpp_file debug ) false function_def.tf_expr;*) + end; + ctx.ctx_debug_level <- debug; + | _ -> () + ) + | _ -> ()); + output_cpp "\treturn null();\n"; + output_cpp "}\n\n"; + + (* Destructor goes in the cpp file so we can "see" the full definition of the member vars *) + output_cpp ( "//" ^ class_name ^ "::~" ^ class_name ^ "() { }\n\n"); + output_cpp ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return new " ^ class_name ^ "; }\n"); + + output_cpp (ptr_name ^ " " ^ class_name ^ "::__new(" ^constructor_type_args ^")\n"); + + let create_result () = + output_cpp ("{ " ^ ptr_name ^ " _result_ = new " ^ class_name ^ "();\n"); + in + create_result (); + output_cpp ("\t_result_->__construct(" ^ constructor_args ^ ");\n"); + output_cpp ("\treturn _result_;}\n\n"); + + output_cpp ("Dynamic " ^ class_name ^ "::__Create(hx::DynamicArray inArgs)\n"); + create_result (); + output_cpp ("\t_result_->__construct(" ^ (array_arg_list constructor_var_list) ^ ");\n"); + output_cpp ("\treturn _result_;}\n\n"); + if ( (List.length implemented) > 0 ) then begin + output_cpp ("hx::Object *" ^ class_name ^ "::__ToInterface(const hx::type_info &inType) {\n"); + List.iter (fun interface_name -> + output_cpp ("\tif (inType==typeid( " ^ interface_name ^ "_obj)) " ^ + "return operator " ^ interface_name ^ "_obj *();\n"); + ) implemented; + output_cpp ("\treturn super::__ToInterface(inType);\n}\n\n"); + + + List.iter (fun interface_name -> + output_cpp (class_name ^ "::operator " ^ interface_name ^ "_obj *()\n\t" ^ + "{ return new " ^ interface_name ^ "_delegate_< " ^ class_name ^" >(this); }\n" ); + ) implemented; + end; + + end; + + (match class_def.cl_init with + | Some expression -> + output_cpp ("void " ^ class_name^ "::__init__() {\n"); + hx_stack_push ctx output_cpp dot_name "__init__" expression.epos; + gen_expression (new_context common_ctx cpp_file debug file_info) false (to_block expression); + output_cpp "}\n\n"; + | _ -> ()); + + let statics_except_meta = statics_except_meta class_def in + let implemented_fields = List.filter should_implement_field statics_except_meta in + let dump_field_name = (fun field -> output_cpp ("\t" ^ (str field.cf_name) ^ ",\n")) in let implemented_instance_fields = List.filter should_implement_field class_def.cl_ordered_fields in - List.iter - (gen_field ctx class_def class_name smart_class_name false class_def.cl_interface) - class_def.cl_ordered_fields; - List.iter - (gen_field ctx class_def class_name smart_class_name true class_def.cl_interface) statics_except_meta; - output_cpp "\n"; - - - (* Initialise non-static variables *) - if (not class_def.cl_interface) then begin - output_cpp (class_name ^ "::" ^ class_name ^ "()\n{\n"); - if (implement_dynamic) then - output_cpp " HX_INIT_IMPLEMENT_DYNAMIC;\n"; - List.iter - (fun field -> let remap_name = keyword_remap field.cf_name in - match field.cf_expr with - | Some { eexpr = TFunction function_def } -> - if (is_dynamic_haxe_method field) then - output_cpp (" " ^ remap_name ^ " = new __default_" ^ remap_name ^ "(this);\n") - | _ -> () - ) - class_def.cl_ordered_fields; - output_cpp "}\n\n"; - - - let dump_field_iterator macro field = - if (is_data_member field) then begin - let remap_name = keyword_remap field.cf_name in - output_cpp (" " ^ macro ^ "(" ^ remap_name ^ ",\"" ^ field.cf_name^ "\");\n"); - - (match field.cf_kind with Var { v_read = AccCall } when (is_dynamic_accessor ("get_" ^ field.cf_name) "get" field class_def) -> - let name = "get_" ^ field.cf_name in - output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ()); - (match field.cf_kind with Var { v_write = AccCall } when (is_dynamic_accessor ("set_" ^ field.cf_name) "set" field class_def) -> - let name = "set_" ^ field.cf_name in - output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ()); - end - in - - - (* MARK function - explicitly mark all child pointers *) - output_cpp ("void " ^ class_name ^ "::__Mark(HX_MARK_PARAMS)\n{\n"); - output_cpp (" HX_MARK_BEGIN_CLASS(" ^ smart_class_name ^ ");\n"); - if (implement_dynamic) then - output_cpp " HX_MARK_DYNAMIC;\n"; - List.iter (dump_field_iterator "HX_MARK_MEMBER_NAME") implemented_instance_fields; - (match class_def.cl_super with Some _ -> output_cpp " super::__Mark(HX_MARK_ARG);\n" | _ -> () ); - output_cpp " HX_MARK_END_CLASS();\n"; - output_cpp "}\n\n"; - - (* Visit function - explicitly visit all child pointers *) - output_cpp ("void " ^ class_name ^ "::__Visit(HX_VISIT_PARAMS)\n{\n"); - if (implement_dynamic) then - output_cpp " HX_VISIT_DYNAMIC;\n"; - List.iter (dump_field_iterator "HX_VISIT_MEMBER_NAME") implemented_instance_fields; - (match class_def.cl_super with Some _ -> output_cpp " super::__Visit(HX_VISIT_ARG);\n" | _ -> () ); - output_cpp "}\n\n"; - - - let variable_field field = - (match field.cf_expr with - | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field - | _ -> true) - in - let is_readable field = - (match field.cf_kind with | Var { v_read = AccNever } | Var { v_read = AccInline } -> false - | Var _ when is_abstract_impl -> false - | _ -> true) in - let is_writable field = - (match field.cf_kind with | Var { v_write = AccNever } | Var { v_read = AccInline } -> false - | Var _ when is_abstract_impl -> false - | _ -> true) in - - let reflective field = not (Meta.has Meta.Unreflective field.cf_meta) in - let reflect_fields = List.filter reflective (statics_except_meta @ class_def.cl_ordered_fields) in - let reflect_writable = List.filter is_writable reflect_fields in - let reflect_readable = List.filter is_readable reflect_fields in - let reflect_write_variables = List.filter variable_field reflect_writable in - - let dump_quick_field_test fields = - if ( (List.length fields) > 0) then begin - let len = function (_,l,_) -> l in - let sfields = List.sort (fun f1 f2 -> (len f1)-(len f2)) fields in - let len_case = ref (-1) in - output_cpp " switch(inName.length) {\n"; - List.iter (fun (field,l,result) -> - if (l <> !len_case) then begin - if (!len_case>=0) then output_cpp " break;\n"; - output_cpp (" case " ^ (string_of_int l) ^ ":\n"); - len_case := l; - end; - output_cpp (" if (HX_FIELD_EQ(inName,\"" ^ (Ast.s_escape field) ^ "\") ) { " ^ result ^ " }\n"); - ) sfields; - output_cpp " }\n"; - end; - in - - - (* Dynamic "Get" Field function - string version *) - output_cpp ("Dynamic " ^ class_name ^ "::__Field(const ::String &inName,bool inCallProp)\n{\n"); - let get_field_dat = List.map (fun f -> - (f.cf_name, String.length f.cf_name, "return " ^ - (match f.cf_kind with - | Var { v_read = AccCall } when is_extern_field f -> (keyword_remap ("get_" ^ f.cf_name)) ^ "()" - | Var { v_read = AccCall } -> "inCallProp ? " ^ (keyword_remap ("get_" ^ f.cf_name)) ^ "() : " ^ - ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()") - | _ -> ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()") - ) ^ ";" - ) ) - in - dump_quick_field_test (get_field_dat reflect_readable); - if (implement_dynamic) then - output_cpp " HX_CHECK_DYNAMIC_GET_FIELD(inName);\n"; - output_cpp (" return super::__Field(inName,inCallProp);\n}\n\n"); - - (* Dynamic "Get" Field function - int version *) - if ( field_integer_numeric || field_integer_dynamic) then begin - let dump_static_ids = (fun field -> - let remap_name = keyword_remap field.cf_name in - output_cpp ("static int __id_" ^ remap_name ^ " = __hxcpp_field_to_id(\"" ^ - (field.cf_name) ^ "\");\n"); - ) in - List.iter dump_static_ids reflect_readable; - output_cpp "\n\n"; - - - let output_ifield return_type function_name all_fields = - output_cpp (return_type ^" " ^ class_name ^ "::" ^ function_name ^ "(int inFieldID)\n{\n"); - let dump_field_test = (fun f -> - let remap_name = keyword_remap f.cf_name in - output_cpp (" if (inFieldID==__id_" ^ remap_name ^ ") return " ^ - ( if (return_type="Float") then "hx::ToDouble( " else "" ) ^ - (match f.cf_kind with - | Var { v_read = AccCall } -> (keyword_remap ("get_" ^ f.cf_name)) ^ "()" - | _ -> (remap_name ^ if ( variable_field f) then "" else "_dyn()") - ) ^ ( if (return_type="Float") then " ) " else "" ) ^ ";\n"); - ) in - List.iter dump_field_test (List.filter (fun f -> all_fields || (is_numeric_field f)) reflect_readable); - if (implement_dynamic) then - output_cpp " HX_CHECK_DYNAMIC_GET_INT_FIELD(inFieldID);\n"; - output_cpp (" return super::" ^ function_name ^ "(inFieldID);\n}\n\n"); - in - - if (field_integer_dynamic) then output_ifield "Dynamic" "__IField" true; - if (field_integer_numeric) then output_ifield "double" "__INumField" false; - end; - - - (* Dynamic "Set" Field function *) - output_cpp ("Dynamic " ^ class_name ^ "::__SetField(const ::String &inName,const Dynamic &inValue,bool inCallProp)\n{\n"); - - let set_field_dat = List.map (fun f -> - let default_action = - (keyword_remap f.cf_name) ^ "=inValue.Cast< " ^ (type_string f.cf_type) ^ " >();" ^ - " return inValue;" in - (f.cf_name, String.length f.cf_name, - (match f.cf_kind with - | Var { v_write = AccCall } when is_extern_field f -> "return " ^ (keyword_remap ("set_" ^ f.cf_name)) ^ "(inValue);" - | Var { v_write = AccCall } -> "if (inCallProp) return " ^ (keyword_remap ("set_" ^ f.cf_name)) ^ "(inValue);" - ^ default_action - | _ -> default_action - ) + List.iter + (gen_field ctx class_def class_name smart_class_name dot_name false class_def.cl_interface) + class_def.cl_ordered_fields; + List.iter + (gen_field ctx class_def class_name smart_class_name dot_name true class_def.cl_interface) statics_except_meta; + output_cpp "\n"; + + let override_iteration = (not nativeGen) && (has_new_gc_references class_def) in + + (* Initialise non-static variables *) + if ( (not class_def.cl_interface) && (not nativeGen) ) then begin + output_cpp (class_name ^ "::" ^ class_name ^ "()\n{\n"); + if (implement_dynamic) then + output_cpp "\tHX_INIT_IMPLEMENT_DYNAMIC;\n"; + List.iter + (fun field -> let remap_name = keyword_remap field.cf_name in + match field.cf_expr with + | Some { eexpr = TFunction function_def } -> + if (is_dynamic_haxe_method field) then + output_cpp ("\t" ^ remap_name ^ " = new __default_" ^ remap_name ^ "(this);\n") + | _ -> () ) - ) in - - dump_quick_field_test (set_field_dat reflect_write_variables); - if (implement_dynamic) then begin - output_cpp (" try { return super::__SetField(inName,inValue,inCallProp); }\n"); - output_cpp (" catch(Dynamic e) { HX_DYNAMIC_SET_FIELD(inName,inValue); }\n"); - output_cpp " return inValue;\n}\n\n"; - end else - output_cpp (" return super::__SetField(inName,inValue,inCallProp);\n}\n\n"); - - (* For getting a list of data members (eg, for serialization) *) - let append_field = - (fun field -> output_cpp (" outFields->push(" ^( str field.cf_name )^ ");\n")) in - let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in - - output_cpp ("void " ^ class_name ^ "::__GetFields(Array< ::String> &outFields)\n{\n"); - List.iter append_field (List.filter is_data_field class_def.cl_ordered_fields); - if (implement_dynamic) then - output_cpp " HX_APPEND_DYNAMIC_FIELDS(outFields);\n"; - output_cpp " super::__GetFields(outFields);\n"; - output_cpp "};\n\n"; - - output_cpp "static ::String sStaticFields[] = {\n"; - List.iter dump_field_name implemented_fields; - output_cpp " String(null()) };\n\n"; + class_def.cl_ordered_fields; + output_cpp "}\n\n"; + + + let dump_field_iterator macro field = + if (is_data_member field) then begin + let remap_name = keyword_remap field.cf_name in + output_cpp ("\t" ^ macro ^ "(" ^ remap_name ^ ",\"" ^ field.cf_name^ "\");\n"); + + (match field.cf_kind with Var { v_read = AccCall } when (is_dynamic_accessor ("get_" ^ field.cf_name) "get" field class_def) -> + let name = "get_" ^ field.cf_name in + output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ()); + (match field.cf_kind with Var { v_write = AccCall } when (is_dynamic_accessor ("set_" ^ field.cf_name) "set" field class_def) -> + let name = "set_" ^ field.cf_name in + output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ()); + end + in + + + if (override_iteration) then begin + let super_needs_iteration = find_next_super_iteration class_def in + (* MARK function - explicitly mark all child pointers *) + output_cpp ("void " ^ class_name ^ "::__Mark(HX_MARK_PARAMS)\n{\n"); + output_cpp ("\tHX_MARK_BEGIN_CLASS(" ^ smart_class_name ^ ");\n"); + if (implement_dynamic) then + output_cpp "\tHX_MARK_DYNAMIC;\n"; + List.iter (dump_field_iterator "HX_MARK_MEMBER_NAME") implemented_instance_fields; + (match super_needs_iteration with + | "" -> () + | super -> output_cpp ("\t" ^ super^"::__Mark(HX_MARK_ARG);\n" ) ); + output_cpp "\tHX_MARK_END_CLASS();\n"; + output_cpp "}\n\n"; + + (* Visit function - explicitly visit all child pointers *) + output_cpp ("void " ^ class_name ^ "::__Visit(HX_VISIT_PARAMS)\n{\n"); + if (implement_dynamic) then + output_cpp "\tHX_VISIT_DYNAMIC;\n"; + List.iter (dump_field_iterator "HX_VISIT_MEMBER_NAME") implemented_instance_fields; + (match super_needs_iteration with + | "" -> () + | super -> output_cpp ("\t" ^ super ^ "::__Visit(HX_VISIT_ARG);\n") ); + output_cpp "}\n\n"; + end; + + let reflect_member_fields = List.filter (reflective class_def) class_def.cl_ordered_fields in + let reflect_member_readable = List.filter (is_readable class_def) reflect_member_fields in + let reflect_member_writable = List.filter (is_writable class_def) reflect_member_fields in + let reflect_write_member_variables = List.filter variable_field reflect_member_writable in + + let reflect_static_fields = List.filter (reflective class_def) (statics_except_meta) in + let reflect_static_readable = List.filter (is_readable class_def) reflect_static_fields in + let reflect_static_writable = List.filter (is_writable class_def) reflect_static_fields in + let reflect_write_static_variables = List.filter variable_field reflect_static_writable in + + let dump_quick_field_test fields = + if ( (List.length fields) > 0) then begin + let len = function (_,l,_) -> l in + let sfields = List.sort (fun f1 f2 -> (len f1)-(len f2)) fields in + let len_case = ref (-1) in + output_cpp "\tswitch(inName.length) {\n"; + List.iter (fun (field,l,result) -> + if (l <> !len_case) then begin + if (!len_case>=0) then output_cpp "\t\tbreak;\n"; + output_cpp ("\tcase " ^ (string_of_int l) ^ ":\n"); + len_case := l; + end; + output_cpp ("\t\tif (HX_FIELD_EQ(inName,\"" ^ (Ast.s_escape field) ^ "\") ) { " ^ result ^ " }\n"); + ) sfields; + output_cpp "\t}\n"; + end; + in + + let checkPropCall field = if ( (has_meta_key class_def.cl_meta Meta.NativeProperty) || + (has_meta_key field.cf_meta Meta.NativeProperty) || + (Common.defined common_ctx Define.ForceNativeProperty) ) + then + "inCallProp != hx::paccNever" + else + "inCallProp == hx::paccAlways" + in + + + + if (has_get_member_field class_def) then begin + (* Dynamic "Get" Field function - string version *) + output_cpp ("Dynamic " ^ 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 + | Var { v_read = AccCall } when is_extern_field f -> "if (" ^ (checkPropCall f) ^ ") return " ^(keyword_remap ("get_" ^ f.cf_name)) ^ "()" + | Var { v_read = AccCall } -> "return " ^ (checkPropCall f) ^ " ? " ^ (keyword_remap ("get_" ^ f.cf_name)) ^ "() : " ^ + ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()") + | _ -> "return " ^ ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()") + ) ^ ";" + ) ) + in + dump_quick_field_test (get_field_dat reflect_member_readable); + if (implement_dynamic) then + output_cpp "\tHX_CHECK_DYNAMIC_GET_FIELD(inName);\n"; + output_cpp ("\treturn super::__Field(inName,inCallProp);\n}\n\n"); + + (* Dynamic "Get" Field function - int version *) + if ( field_integer_numeric || field_integer_dynamic) then begin + let dump_static_ids = (fun field -> + let remap_name = keyword_remap field.cf_name in + output_cpp ("static int __id_" ^ remap_name ^ " = __hxcpp_field_to_id(\"" ^ + (field.cf_name) ^ "\");\n"); + ) in + List.iter dump_static_ids reflect_member_readable; + output_cpp "\n\n"; + + + let output_ifield return_type function_name all_fields = + output_cpp (return_type ^" " ^ class_name ^ "::" ^ function_name ^ "(int inFieldID)\n{\n"); + let dump_field_test = (fun f -> + let remap_name = keyword_remap f.cf_name in + output_cpp ("\tif (inFieldID==__id_" ^ remap_name ^ ") return " ^ + ( if (return_type="Float") then "hx::ToDouble( " else "" ) ^ + (match f.cf_kind with + | Var { v_read = AccCall } -> (keyword_remap ("get_" ^ f.cf_name)) ^ "()" + | _ -> (remap_name ^ if ( variable_field f) then "" else "_dyn()") + ) ^ ( if (return_type="Float") then " ) " else "" ) ^ ";\n"); + ) in + List.iter dump_field_test (List.filter (fun f -> all_fields || (is_numeric_field f)) reflect_member_readable); + if (implement_dynamic) then + output_cpp "\tHX_CHECK_DYNAMIC_GET_INT_FIELD(inFieldID);\n"; + output_cpp ("\treturn super::" ^ function_name ^ "(inFieldID);\n}\n\n"); + in + + if (field_integer_dynamic) then output_ifield "Dynamic" "__IField" true; + if (field_integer_numeric) then output_ifield "double" "__INumField" false; + end; + 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"); + let get_field_dat = List.map (fun f -> + (f.cf_name, String.length f.cf_name, + (match f.cf_kind with + | Var { v_read = AccCall } when is_extern_field f -> "if (" ^ (checkPropCall f) ^ ") { outValue = " ^(keyword_remap ("get_" ^ f.cf_name)) ^ "(); return true; }" + | Var { v_read = AccCall } -> "outValue = " ^ (checkPropCall f) ^ " ? " ^ (keyword_remap ("get_" ^ f.cf_name)) ^ "() : " ^ + ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()") ^ "; return true;"; + | _ -> "outValue = " ^ ((keyword_remap f.cf_name) ^ (if (variable_field f) then "" else "_dyn()") ^ "; return true; ") + ) + ) ) + in + dump_quick_field_test (get_field_dat reflect_static_readable); + output_cpp ("\treturn false;\n}\n\n"); + end; + + (* Dynamic "Set" Field function *) + if (has_set_member_field class_def) then begin + + output_cpp ("Dynamic " ^ class_name ^ "::__SetField(const ::String &inName,const Dynamic &inValue,hx::PropertyAccess inCallProp)\n{\n"); + + let set_field_dat = List.map (fun f -> + let default_action = + (keyword_remap f.cf_name) ^ "=inValue.Cast< " ^ (type_string f.cf_type) ^ " >();" ^ + " return inValue;" in + (f.cf_name, String.length f.cf_name, + (match f.cf_kind with + | Var { v_write = AccCall } -> "if (" ^ (checkPropCall f) ^ ") return " ^ (keyword_remap ("set_" ^ f.cf_name)) ^ "(inValue);" + ^ ( if is_extern_field f then "" else default_action ) + | _ -> default_action + ) + ) + ) in + + dump_quick_field_test (set_field_dat reflect_write_member_variables); + if (implement_dynamic) then begin + output_cpp ("\ttry { return super::__SetField(inName,inValue,inCallProp); }\n"); + output_cpp ("\tcatch(Dynamic e) { HX_DYNAMIC_SET_FIELD(inName,inValue); }\n"); + output_cpp "\treturn inValue;\n}\n\n"; + end else + output_cpp ("\treturn super::__SetField(inName,inValue,inCallProp);\n}\n\n"); + end; + + 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"); + + let set_field_dat = List.map (fun f -> + let default_action = + (keyword_remap f.cf_name) ^ "=ioValue.Cast< " ^ (type_string f.cf_type) ^ " >(); return true;" in + (f.cf_name, String.length f.cf_name, + (match f.cf_kind with + | Var { v_write = AccCall } -> "if (" ^ (checkPropCall f) ^ ") ioValue = " ^ (keyword_remap ("set_" ^ f.cf_name)) ^ "(ioValue);" + ^ ( if is_extern_field f then "" else " else " ^ default_action ) + | _ -> default_action + ) + ) + ) in + + dump_quick_field_test (set_field_dat reflect_write_static_variables); + output_cpp ("\treturn false;\n}\n\n"); + end; + + + + + (* For getting a list of data members (eg, for serialization) *) + if (has_get_fields class_def) then begin + let append_field = + (fun field -> output_cpp ("\toutFields->push(" ^( str field.cf_name )^ ");\n")) in + let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in + + output_cpp ("void " ^ class_name ^ "::__GetFields(Array< ::String> &outFields)\n{\n"); + List.iter append_field (List.filter is_data_field class_def.cl_ordered_fields); + if (implement_dynamic) then + output_cpp "\tHX_APPEND_DYNAMIC_FIELDS(outFields);\n"; + output_cpp "\tsuper::__GetFields(outFields);\n"; + output_cpp "};\n\n"; + end; + + let storage field = match type_string field.cf_type with + | "bool" -> "hx::fsBool" + | "int" -> "hx::fsInt" + | "Float" -> "hx::fsFloat" + | "::String" -> "hx::fsString" + | str -> "hx::fsObject" ^ " /*" ^ str ^ "*/ " + in + let dump_member_storage = (fun field -> + output_cpp ("\t{" ^ (storage field) ^ ",(int)offsetof(" ^ class_name ^"," ^ (keyword_remap field.cf_name) ^")," ^ + (str field.cf_name) ^ "},\n") + ) + in + let dump_static_storage = (fun field -> + output_cpp ("\t{" ^ (storage field) ^ ",(void *) &" ^ class_name ^"::" ^ (keyword_remap field.cf_name) ^"," ^ + (str field.cf_name) ^ "},\n") + ) + in + + output_cpp "#if HXCPP_SCRIPTABLE\n"; + + 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 sMemberStorageInfo[] = {\n"; + List.iter dump_member_storage stored_fields; + output_cpp "\t{ hx::fsUnknown, 0, null()}\n};\n"; + end else + output_cpp "static hx::StorageInfo *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 sStaticStorageInfo[] = {\n"; + List.iter dump_static_storage stored_statics; + output_cpp "\t{ hx::fsUnknown, 0, null()}\n};\n"; + end else + output_cpp "static hx::StaticInfo *sStaticStorageInfo = 0;\n"; + + output_cpp "#endif\n\n"; end; (* cl_interface *) - output_cpp "static ::String sMemberFields[] = {\n"; - List.iter dump_field_name implemented_instance_fields; - output_cpp " String(null()) };\n\n"; - - - (* Mark static variables as used *) - output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n"; - output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); - List.iter (fun field -> - if (is_data_member field) then - output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") ) - implemented_fields; - output_cpp "};\n\n"; - - (* Visit static variables *) - output_cpp "static void sVisitStatics(HX_VISIT_PARAMS) {\n"; - output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); - List.iter (fun field -> - if (is_data_member field) then - output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") ) - implemented_fields; - output_cpp "};\n\n"; - - if (scriptable ) then begin + let reflective_members = List.filter (reflective class_def) implemented_instance_fields in + let sMemberFields = if List.length reflective_members>0 then begin + output_cpp "static ::String sMemberFields[] = {\n"; + List.iter dump_field_name reflective_members; + output_cpp "\t::String(null()) };\n\n"; + "sMemberFields" + end else + "0 /* sMemberFields */"; + in + + if (not nativeGen) then begin + (* Mark static variables as used *) + output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n"; + output_cpp ("\tHX_MARK_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); + List.iter (fun field -> + if (is_data_member field) then + output_cpp ("\tHX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") ) + implemented_fields; + output_cpp "};\n\n"; + + (* Visit static variables *) + output_cpp "#ifdef HXCPP_VISIT_ALLOCS\n"; + output_cpp "static void sVisitStatics(HX_VISIT_PARAMS) {\n"; + output_cpp ("\tHX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n"); + List.iter (fun field -> + if (is_data_member field) then + output_cpp ("\tHX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") ) + implemented_fields; + output_cpp "};\n\n"; + output_cpp "#endif\n\n"; + end; + + let script_type t optional = if optional then "Object" else + match type_string t with + | "bool" -> "Int" + | "int" -> "Int" + | "Float" -> "Float" + | "::String" -> "String" + | "Null" -> "Void" + | "Void" -> "Void" + | _ -> "Object" + in + let script_signature t optional = match script_type t optional with + | "Bool" -> "b" + | "Int" -> "i" + | "Float" -> "f" + | "String" -> "s" + | "Void" -> "v" + | _ -> "o" + in + let script_size_type t optional = match script_type t optional with + | "Object" -> "void *" + | x -> x + in + + let generate_script_function isStatic field scriptName callName = + match follow field.cf_type with + | TFun (args,return_type) -> + output_cpp ("\nstatic void " ^ scriptName ^ "(hx::CppiaCtx *ctx) {\n"); + let ret = script_signature return_type false in + if (ret<>"v") then output_cpp ("ctx->return" ^ (script_type return_type false) ^ "("); + if isStatic then + output_cpp (class_name ^ "::" ^ callName ^ "(") + else + output_cpp ("((" ^ class_name ^ "*)ctx->getThis())->" ^ callName ^ "("); + + let (signature,_,_) = List.fold_left (fun (signature,sep,size) (_,opt,t) -> + output_cpp (sep ^ "ctx->get" ^ (script_type t opt) ^ "(" ^ size ^ ")"); + (signature ^ (script_signature t opt ), ",", (size^"+sizeof(" ^ (script_size_type t opt) ^ ")") ) ) (ret,"","sizeof(void*)") args + in + + output_cpp ")"; + if (ret<>"v") then output_cpp (")"); + output_cpp (";\n}\n"); + signature; + | _ -> "" + in + + + if (scriptable && not nativeGen) then begin let dump_script_field idx (field,f_args,return_t) = - let args = if (class_def.cl_interface) then - gen_tfun_interface_arg_list f_args - else - gen_tfun_arg_list f_args in - let names = List.map (fun (n,_,_) -> keyword_remap n) f_args in - let return_type = type_string return_t in - let ret = if (return_type="Void") then " " else "return " in - let name = keyword_remap field.cf_name in - let vtable = "__scriptVTable[" ^ (string_of_int idx) ^ "] " in - let args_varray = (List.fold_left (fun l n -> l ^ ".Add(" ^ n ^ ")") "Array()" names) in - let args_comma = List.fold_left (fun l n -> l ^ "," ^ n) "" names in - output_cpp (" " ^ return_type ^ " " ^ name ^ "( " ^ args ^ " ) { "); - if (class_def.cl_interface) then begin - output_cpp (" " ^ ret ^ "mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"),false)"); - if (List.length names <= 5) then - output_cpp ("->__run(" ^ (String.concat "," names) ^ ")") - else - output_cpp ("->__Run(" ^ args_varray ^ ")"); - output_cpp ";return null(); }\n"; - end else begin - output_cpp (" if (" ^ vtable ^ ") " ^ ret); - if (List.length names <= 5) then - output_cpp("hx::ScriptableCall" ^ (string_of_int (List.length names)) ^ - "("^ vtable ^ ",this" ^ args_comma ^ ");") - else - output_cpp("hx::ScriptableCallMult("^ vtable ^ ",this," ^ args_varray^ "->Pointer());"); - output_cpp (" else " ^ ret ^ class_name ^ "::" ^ name ^ "(" ^ (String.concat "," names)^ "); return null(); }\n"); - end + let args = if (class_def.cl_interface) then + gen_tfun_interface_arg_list f_args + else + gen_tfun_arg_list f_args in + let names = List.map (fun (n,_,_) -> keyword_remap n) f_args in + let return_type = type_string return_t in + let ret = if (return_type="Void") then " " else "return " in + let name = keyword_remap field.cf_name in + let vtable = "__scriptVTable[" ^ (string_of_int (idx+1) ) ^ "] " in + let args_varray = (List.fold_left (fun l n -> l ^ ".Add(" ^ n ^ ")") "Array()" names) in + output_cpp (" " ^ return_type ^ " " ^ name ^ "( " ^ args ^ " ) { "); + output_cpp ("\n\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__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" ); + ) f_args; + output_cpp ("\t\t" ^ ret ^ "__ctx->run" ^ (script_type return_t false) ^ "(" ^ vtable ^ ");\n" ); + output_cpp ("\t} else " ^ ret ); + + if (class_def.cl_interface) then begin + output_cpp (" mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), hx::paccNever)"); + if (List.length names <= 5) then + output_cpp ("->__run(" ^ (String.concat "," names) ^ ");") + else + output_cpp ("->__Run(" ^ args_varray ^ ");"); + end else + output_cpp (class_name ^ "::" ^ name ^ "(" ^ (String.concat "," names)^ ");"); + output_cpp ("return null(); }\n"); + if (class_def.cl_interface) then begin + output_cpp (" Dynamic " ^ name ^ "_dyn() { return mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), hx::paccNever); }\n\n"); + + end in + + let not_toString = fun (field,args,_) -> field.cf_name<>"toString" || class_def.cl_interface in + let functions = List.filter not_toString (all_virtual_functions class_def) in + let new_sctipt_functions = List.filter (fun (f,_,_) -> not (is_override class_def f.cf_name) ) functions in let sctipt_name = class_name ^ "__scriptable" in output_cpp ("class " ^ sctipt_name ^ " : public " ^ class_name ^ " {\n" ); output_cpp (" typedef "^sctipt_name ^" __ME;\n"); + output_cpp (" typedef "^class_name ^" super;\n"); + let has_funky_toString = List.exists (fun f -> f.cf_name="toString") class_def.cl_ordered_statics || + List.exists (fun f -> f.cf_name="toString" && field_arg_count f <> 0) class_def.cl_ordered_fields in + let super_string = if has_funky_toString then class_name ^ "::super" else class_name in + output_cpp (" typedef "^ super_string ^" __superString;\n"); if (class_def.cl_interface) then output_cpp (" HX_DEFINE_SCRIPTABLE_INTERFACE\n") else begin output_cpp (" HX_DEFINE_SCRIPTABLE(HX_ARR_LIST" ^ (string_of_int (List.length constructor_var_list) ) ^ ")\n"); - if (not implement_dynamic) then - output_cpp " HX_DEFINE_SCRIPTABLE_DYNAMIC;\n"; + if (not implement_dynamic) then + output_cpp "\tHX_DEFINE_SCRIPTABLE_DYNAMIC;\n"; end; - let functions = all_virtual_functions class_def in - list_iteri dump_script_field functions; + + list_iteri dump_script_field functions; output_cpp ("};\n\n"); - if (not class_def.cl_interface) then begin - output_cpp "static String __scriptableFunctionNames[] = {\n"; - List.iter (fun (f,_,_) -> output_cpp (" HX_CSTRING(\"" ^ f.cf_name ^ "\"),\n" ) ) functions; - output_cpp " String(null()) };\n"; - end; + if (List.length new_sctipt_functions) > 0 then begin + let sigs = Hashtbl.create 0 in + List.iter (fun (f,_,_) -> + let s = generate_script_function false f ("__s_" ^f.cf_name) (keyword_remap f.cf_name) in + Hashtbl.add sigs f.cf_name s + ) new_sctipt_functions; + + output_cpp "static hx::ScriptNamedFunction __scriptableFunctions[] = {\n"; + List.iter (fun (f,_,_) -> + 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 ^ "\"),\n" ) ) new_sctipt_functions; + output_cpp " hx::ScriptNamedFunction(0,0,0) };\n"; + end else + output_cpp "static hx::ScriptNamedFunction *__scriptableFunctions = 0;\n"; end; - (* Initialise static in boot function ... *) - if (not class_def.cl_interface) then begin - (* Remap the specialised "extern" classes back to the generic names *) - let class_name_text = match class_path with - | path -> join_class_path path "." in - - output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n"); - - output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); - output_cpp (" hx::Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text) ^ - ", hx::TCanCast< " ^ class_name ^ "> ,sStaticFields,sMemberFields,\n"); - output_cpp (" &__CreateEmpty, &__Create,\n"); - output_cpp (" &super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n"); - if (scriptable) then - output_cpp (" HX_SCRIPTABLE_REGISTER_CLASS(\""^class_name_text^"\"," ^ class_name ^ ");\n"); - output_cpp ("}\n\n"); + let class_name_text = join_class_path class_path "." in - end else begin - let class_name_text = join_class_path class_path "." in + (* 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"); + 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(0,0);\n"); + ); + end; - output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n"); + let reflective_statics = List.filter (reflective class_def) implemented_fields in + let sStaticFields = if List.length reflective_statics > 0 then begin + output_cpp "static ::String sStaticFields[] = {\n"; + List.iter dump_field_name reflective_statics; + output_cpp "\t::String(null()) };\n\n"; + "sStaticFields"; + end else + "0 /* sStaticFields */" + in - output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); - output_cpp (" hx::Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text) ^ - ", hx::TCanCast< " ^ class_name ^ "> ,0,sMemberFields,\n"); - output_cpp (" 0, 0,\n"); - output_cpp (" &super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n"); + output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); + output_cpp ("\thx::Static(__mClass) = new hx::Class_obj();\n"); + output_cpp ("\t__mClass->mName = " ^ (str 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" )); + output_cpp ("\t__mClass->mSetStaticField = &" ^ ( + if (has_set_static_field class_def) then class_name ^ "::__SetStatic;\n" else "hx::Class_obj::SetNoStaticField;\n" )); + output_cpp ("\t__mClass->mMarkFunc = 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 ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = sVisitStatics;\n#endif\n"); + output_cpp ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mMemberStorageInfo = sMemberStorageInfo;\n#endif\n"); + output_cpp ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mStaticStorageInfo = sStaticStorageInfo;\n#endif\n"); + output_cpp ("\thx::RegisterClass(__mClass->mName, __mClass);\n"); + if (scriptable) then + output_cpp (" HX_SCRIPTABLE_REGISTER_CLASS(\""^class_name_text^"\"," ^ class_name ^ ");\n"); + output_cpp ("}\n\n"); + + end else if not nativeGen then begin + 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__mClass->mName = " ^ (str class_name_text) ^ ";\n"); + output_cpp ("\t__mClass->mSuper = &super::__SGetClass();\n"); + output_cpp ("\t__mClass->mMarkFunc = 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 ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = sVisitStatics;\n#endif\n"); + output_cpp ("\thx::RegisterClass(__mClass->mName, __mClass);\n"); if (scriptable) then output_cpp (" HX_SCRIPTABLE_REGISTER_INTERFACE(\""^class_name_text^"\"," ^ class_name ^ ");\n"); - output_cpp ("}\n\n"); - end; + output_cpp ("}\n\n"); + end; - output_cpp ("void " ^ class_name ^ "::__boot()\n{\n"); - List.iter (gen_field_init ctx ) (List.filter should_implement_field class_def.cl_ordered_statics); - output_cpp ("}\n\n"); + if (has_boot_field class_def) then begin + output_cpp ("void " ^ class_name ^ "::__boot()\n{\n"); + List.iter (gen_field_init ctx ) (List.filter should_implement_field class_def.cl_ordered_statics); + output_cpp ("}\n\n"); + end; - gen_close_namespace output_cpp class_path; + gen_close_namespace output_cpp class_path; - cpp_file#close; + cpp_file#close; - let h_file = new_header_file common_ctx.file class_path in - let super = match class_def.cl_super with - | Some (klass,params) -> (class_string klass "_obj" params) - | _ -> if (class_def.cl_interface) then "hx::Interface" else "hx::Object" - in - let output_h = (h_file#write) in - let def_string = join_class_path class_path "_" in - ctx.ctx_output <- output_h; + let h_file = new_header_file common_ctx common_ctx.file class_path in + let super = match class_def.cl_super with + | Some (klass,params) -> (class_string klass "_obj" params true) + | _ when nativeGen -> "" + | _ -> if (class_def.cl_interface) then "hx::Interface" else "hx::Object" + in + let output_h = (h_file#write) in + let def_string = join_class_path class_path "_" in + ctx.ctx_output <- output_h; - begin_header_file output_h def_string; + begin_header_file output_h def_string; - (* Include the real header file for the super class *) - (match class_def.cl_super with - | Some super -> - let super_path = (fst super).cl_path in - output_h ("#include <" ^ ( join_class_path super_path "/" ) ^ ".h>\n") - | _ -> () ); + (* Include the real header file for the super class *) + (match class_def.cl_super with + | Some super -> + let super_path = (fst super).cl_path in + h_file#add_include super_path + | _ -> () ); - (* And any interfaces ... *) - List.iter (fun imp-> - let imp_path = (fst imp).cl_path in - output_h ("#include <" ^ ( join_class_path imp_path "/" ) ^ ".h>\n") ) - (real_interfaces class_def.cl_implements); + (* And any interfaces ... *) + List.iter (fun imp-> h_file#add_include (fst imp).cl_path) + (real_interfaces class_def.cl_implements); (* Only need to foreward-declare classes that are mentioned in the header file - (ie, not the implementation) *) + (ie, not the implementation) *) let referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps (Hashtbl.create 0) true false scriptable in - List.iter ( gen_forward_decl h_file ) referenced; + List.iter ( gen_forward_decl h_file ) referenced; - output_h ( get_code class_def.cl_meta Meta.HeaderCode ); + output_h ( get_class_code class_def Meta.HeaderCode ); + let inc = get_meta_string_path class_def.cl_meta Meta.HeaderInclude in + if (inc<>"") then + output_h ("#include \"" ^ inc ^ "\"\n"); - gen_open_namespace output_h class_path; - output_h "\n\n"; - output_h ( get_code class_def.cl_meta Meta.HeaderNamespaceCode ); + gen_open_namespace output_h class_path; + output_h "\n\n"; + output_h ( get_class_code class_def Meta.HeaderNamespaceCode ); let extern_class = Common.defined common_ctx Define.DllExport in - let attribs = "HXCPP_" ^ (if extern_class then "EXTERN_" else "") ^ "CLASS_ATTRIBUTES " in - - output_h ("class " ^ attribs ^ " " ^ class_name ^ " : public " ^ super ); - output_h "{\n public:\n"; - output_h (" typedef " ^ super ^ " super;\n"); - output_h (" typedef " ^ class_name ^ " OBJ_;\n"); - - if (not class_def.cl_interface) then begin - output_h (" " ^ class_name ^ "();\n"); - output_h (" Void __construct(" ^ constructor_type_args ^ ");\n"); - output_h "\n public:\n"; - output_h (" static " ^ptr_name^ " __new(" ^constructor_type_args ^");\n"); - output_h (" static Dynamic __CreateEmpty();\n"); - output_h (" static Dynamic __Create(hx::DynamicArray inArgs);\n"); - output_h (" ~" ^ class_name ^ "();\n\n"); - output_h (" HX_DO_RTTI;\n"); - if (field_integer_dynamic) then output_h " Dynamic __IField(int inFieldID);\n"; - if (field_integer_numeric) then output_h " double __INumField(int inFieldID);\n"; - if (implement_dynamic) then - output_h (" HX_DECLARE_IMPLEMENT_DYNAMIC;\n"); - output_h (" static void __boot();\n"); - output_h (" static void __register();\n"); - output_h (" void __Mark(HX_MARK_PARAMS);\n"); - output_h (" void __Visit(HX_VISIT_PARAMS);\n"); - - List.iter (fun interface_name -> - output_h (" inline operator " ^ interface_name ^ "_obj *()\n " ^ - "{ return new " ^ interface_name ^ "_delegate_< " ^ class_name ^" >(this); }\n" ); - ) implemented; - - if ( (List.length implemented) > 0 ) then - output_h " hx::Object *__ToInterface(const hx::type_info &inType);\n"; - - if (has_init_field class_def) then - output_h " static void __init__();\n\n"; - output_h (" ::String __ToString() const { return " ^ (str smart_class_name) ^ "; }\n\n"); - end else begin - output_h (" HX_DO_INTERFACE_RTTI;\n"); - output_h (" static void __boot();\n"); + let attribs = "HXCPP_" ^ (if extern_class then "EXTERN_" else "") ^ "CLASS_ATTRIBUTES " in + + if (super="") then begin + output_h ("class " ^ attribs ^ " " ^ class_name); + output_h "{\n\tpublic:\n"; + end else begin + output_h ("class " ^ attribs ^ " " ^ class_name ^ " : public " ^ super ); + output_h "{\n\tpublic:\n"; + output_h ("\t\ttypedef " ^ super ^ " super;\n"); + output_h ("\t\ttypedef " ^ class_name ^ " OBJ_;\n"); + end; + + if (not class_def.cl_interface && not nativeGen) then begin + output_h ("\t\t" ^ class_name ^ "();\n"); + output_h ("\t\tVoid __construct(" ^ constructor_type_args ^ ");\n"); + output_h "\n\tpublic:\n"; + let new_arg = if (has_gc_references class_def) then "true" else "false" in + output_h ("\t\tinline void *operator new( size_t inSize, bool inContainer=" ^ new_arg + ^",const char *inName=" ^ (const_char_star class_name_text )^ ")\n" ); + output_h ("\t\t\t{ return hx::Object::operator new(inSize,inContainer,inName); }\n" ); + output_h ("\t\tstatic " ^ptr_name^ " __new(" ^constructor_type_args ^");\n"); + output_h ("\t\tstatic Dynamic __CreateEmpty();\n"); + output_h ("\t\tstatic Dynamic __Create(hx::DynamicArray inArgs);\n"); + if (scriptable) then + 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\tDynamic __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"); + if (has_set_member_field class_def) then + output_h ("\t\tDynamic __SetField(const ::String &inString,const Dynamic &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"); + if (has_get_fields class_def) then + output_h ("\t\tvoid __GetFields(Array< ::String> &outFields);\n"); + + if (field_integer_dynamic) then output_h "\t\tDynamic __IField(int inFieldID);\n"; + if (field_integer_numeric) then output_h "\t\tdouble __INumField(int inFieldID);\n"; + if (implement_dynamic) then + output_h ("\t\tHX_DECLARE_IMPLEMENT_DYNAMIC;\n"); + output_h ("\t\tstatic void __register();\n"); + if (override_iteration) then begin + output_h ("\t\tvoid __Mark(HX_MARK_PARAMS);\n"); + output_h ("\t\tvoid __Visit(HX_VISIT_PARAMS);\n"); + end; + + if ( (List.length implemented) > 0 ) then begin + output_h "\t\thx::Object *__ToInterface(const hx::type_info &inType);\n"; + + List.iter (fun interface_name -> + output_h ("\t\toperator " ^ interface_name ^ "_obj *();\n") + ) implemented; + end; + + if (has_init_field class_def) then + output_h "\t\tstatic void __init__();\n\n"; + output_h ("\t\t::String __ToString() const { return " ^ (str smart_class_name) ^ "; }\n\n"); + end else if not nativeGen then begin + output_h ("\t\tHX_DO_INTERFACE_RTTI;\n"); + end; + if (has_boot_field class_def) then + output_h ("\t\tstatic void __boot();\n"); + + + (match class_def.cl_array_access with + | Some t -> output_h ("\t\ttypedef " ^ (type_string t) ^ " __array_access;\n") + | _ -> ()); + + + let interface = class_def.cl_interface in + List.iter (gen_member_def ctx class_def false interface) (List.filter should_implement_field class_def.cl_ordered_fields); + List.iter (gen_member_def ctx class_def true interface) (List.filter should_implement_field class_def.cl_ordered_statics); + + output_h ( get_class_code class_def Meta.HeaderClassCode ); + output_h "};\n\n"; + + if (class_def.cl_interface && not nativeGen) then begin + output_h ("#define DELEGATE_" ^ (join_class_path class_path "_" ) ^ " \\\n"); + List.iter (fun field -> + match follow field.cf_type, field.cf_kind with + | _, Method MethDynamic -> () + | TFun (args,return_type), Method _ -> + let remap_name = keyword_remap field.cf_name in + output_h ( "virtual " ^ (type_string return_type) ^ " " ^ remap_name ^ "( " ); + output_h (gen_tfun_interface_arg_list args); + output_h (") { return mDelegate->" ^ remap_name^ "("); + output_h (String.concat "," (List.map (fun (name,opt,typ) -> (keyword_remap name)) args)); + output_h ");} \\\n"; + output_h ("virtual Dynamic " ^ remap_name ^ "_dyn() { return mDelegate->" ^ + remap_name ^ "_dyn();} \\\n"); + | _ -> () + ) class_def.cl_ordered_fields; + output_h ("\n\n"); + output_h ("template\n"); + output_h ("class " ^ smart_class_name ^ "_delegate_ : public " ^ class_name^"\n"); + output_h "{\n\tprotected:\n"; + output_h ("\t\tIMPL *mDelegate;\n"); + output_h "\tpublic:\n"; + output_h ("\t\t" ^ smart_class_name ^ "_delegate_(IMPL *inDelegate) : mDelegate(inDelegate) {}\n"); + output_h ("\t\thx::Object *__GetRealObject() { return mDelegate; }\n"); + output_h ("\t\tvoid __Visit(HX_VISIT_PARAMS) { HX_VISIT_OBJECT(mDelegate); }\n"); + let rec dump_delegate interface = + output_h ("\t\tDELEGATE_" ^ (join_class_path interface.cl_path "_" ) ^ "\n"); + match interface.cl_super with | Some super -> dump_delegate (fst super) | _ -> (); + in + dump_delegate class_def; + output_h "};\n\n"; end; - (match class_def.cl_array_access with - | Some t -> output_h (" typedef " ^ (type_string t) ^ " __array_access;\n") - | _ -> ()); - - - let interface = class_def.cl_interface in - List.iter (gen_member_def ctx class_def false interface) (List.filter should_implement_field class_def.cl_ordered_fields); - List.iter (gen_member_def ctx class_def true interface) (List.filter should_implement_field class_def.cl_ordered_statics); - - output_h ( get_code class_def.cl_meta Meta.HeaderClassCode ); - - output_h "};\n\n"; - - if (class_def.cl_interface) then begin - output_h ("#define DELEGATE_" ^ (join_class_path class_path "_" ) ^ " \\\n"); - List.iter (fun field -> - match follow field.cf_type, field.cf_kind with - | _, Method MethDynamic -> () - | TFun (args,return_type), Method _ -> - (* TODO : virtual ? *) - let remap_name = keyword_remap field.cf_name in - output_h ( "virtual " ^ (type_string return_type) ^ " " ^ remap_name ^ "( " ); - output_h (gen_tfun_interface_arg_list args); - output_h (") { return mDelegate->" ^ remap_name^ "("); - output_h (String.concat "," (List.map (fun (name,opt,typ) -> (keyword_remap name)) args)); - output_h ");} \\\n"; - output_h ("virtual Dynamic " ^ remap_name ^ "_dyn() { return mDelegate->" ^ - remap_name ^ "_dyn();} \\\n"); - | _ -> () - ) class_def.cl_ordered_fields; - output_h ("\n\n"); - output_h ("template\n"); - output_h ("class " ^ smart_class_name ^ "_delegate_ : public " ^ class_name^"\n"); - output_h "{\n protected:\n"; - output_h (" IMPL *mDelegate;\n"); - output_h " public:\n"; - output_h (" " ^ smart_class_name ^ "_delegate_(IMPL *inDelegate) : mDelegate(inDelegate) {}\n"); - output_h (" hx::Object *__GetRealObject() { return mDelegate; }\n"); - output_h (" void __Visit(HX_VISIT_PARAMS) { HX_VISIT_OBJECT(mDelegate); }\n"); - let rec dump_delegate interface = - output_h (" DELEGATE_" ^ (join_class_path interface.cl_path "_" ) ^ "\n"); - match interface.cl_super with | Some super -> dump_delegate (fst super) | _ -> (); - in - dump_delegate class_def; - output_h "};\n\n"; - end; - - - gen_close_namespace output_h class_path; - - end_header_file output_h def_string; - h_file#close; - let depend_referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps constructor_deps false true false in - depend_referenced;; + gen_close_namespace output_h class_path; + + end_header_file output_h def_string; + h_file#close; + let depend_referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps constructor_deps false true false in + depend_referenced;; + let write_resources common_ctx = - let resource_file = new_cpp_file common_ctx.file ([],"__resources__") in - resource_file#write "#include \n\n"; - - let idx = ref 0 in - Hashtbl.iter (fun _ data -> - resource_file#write_i ("static unsigned char __res_" ^ (string_of_int !idx) ^ "[] = {\n"); - for i = 0 to String.length data - 1 do - let code = Char.code (String.unsafe_get data i) in - resource_file#write (Printf.sprintf "0x%.2x, " code); - if ( (i mod 10) = 9) then resource_file#write "\n"; - done; - resource_file#write ("};\n"); - incr idx; - ) common_ctx.resources; - - idx := 0; - resource_file#write "hx::Resource __Resources[] ="; - resource_file#begin_block; - Hashtbl.iter (fun name data -> - resource_file#write_i - ("{ " ^ (str name) ^ "," ^ (string_of_int (String.length data)) ^ "," ^ - "__res_" ^ (string_of_int !idx) ^ " },\n"); - incr idx; - ) common_ctx.resources; - - resource_file#write_i "{String(null()),0,0}"; - resource_file#end_block_line; - resource_file#write ";\n\n"; - resource_file#write "namespace hx { Resource *GetResources() { return __Resources; } } \n\n"; - resource_file#close;; - - - -let write_build_data filename classes main_deps build_extra exe_name = - let buildfile = open_out filename in - let add_class_to_buildfile class_def = - let class_path = fst class_def in - let deps = snd class_def in - let cpp = (join_class_path class_path "/") ^ ".cpp" in - output_string buildfile ( " \n" ); - let project_deps = List.filter (fun path -> not (is_internal_class path) ) deps in - List.iter (fun path-> output_string buildfile (" + let id = "__res_" ^ (string_of_int !idx) in + let resource_file = new_cpp_file common_ctx common_ctx.file (["resources"],id) in + resource_file#write "namespace hx {\n"; + resource_file#write_i ("unsigned char " ^ id ^ "[] = {\n"); + resource_file#write_i "0xff, 0xff, 0xff, 0xff,\n"; + for i = 0 to String.length data - 1 do + let code = Char.code (String.unsafe_get data i) in + resource_file#write (Printf.sprintf "%d," code); + if ( (i mod 10) = 9) then resource_file#write "\n"; + done; + resource_file#write ("0x00 };\n"); + incr idx; + resource_file#write ("}\n"); + resource_file#close; + ) common_ctx.resources; + + + let resource_file = new_cpp_file common_ctx common_ctx.file ([],"__resources__") in + resource_file#write "#include \n\n"; + resource_file#write "namespace hx { \n\n"; + + idx := 0; + Hashtbl.iter (fun _ data -> + let id = "__res_" ^ (string_of_int !idx) in + resource_file#write_i ("extern unsigned char " ^ id ^ "[];\n"); + incr idx; + ) common_ctx.resources; + + resource_file#write "}\n\n"; + + idx := 0; + 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 + ("{ " ^ (str name) ^ "," ^ (string_of_int (String.length data)) ^ "," ^ + "hx::" ^ id ^ " + 4 },\n"); + incr idx; + ) common_ctx.resources; + + resource_file#write_i "{::String(null()),0,0}"; + resource_file#end_block_line; + resource_file#write ";\n\n"; + resource_file#write "namespace hx { Resource *GetResources() { return __Resources; } } \n\n"; + resource_file#close;; + + + +let write_build_data common_ctx filename classes main_deps boot_deps build_extra extern_src exe_name = + let buildfile = open_out filename in + let include_prefix = get_include_prefix common_ctx true in + let add_class_to_buildfile class_path deps = + let cpp = (join_class_path class_path "/") ^ (source_file_extension common_ctx) in + output_string buildfile ( " \n" ); + let project_deps = List.filter (fun path -> not (is_internal_class path) ) deps in + List.iter (fun path-> output_string buildfile (" file - | _ -> "include/" ^ (join_class_path path "/") ^ ".h" ) - ^ "\"/>\n") ) project_deps; - output_string buildfile ( " \n" ) - in - - output_string buildfile "\n"; - output_string buildfile "\n"; - output_string buildfile "\n"; - List.iter add_class_to_buildfile classes; - add_class_to_buildfile ( ( [] , "__boot__") , [] ); - add_class_to_buildfile ( ( [] , "__files__") , [] ); - add_class_to_buildfile ( ( [] , "__resources__") , [] ); - output_string buildfile "\n"; - output_string buildfile "\n"; - output_string buildfile "\n"; - add_class_to_buildfile ( ( [] , "__lib__") , main_deps ); - output_string buildfile "\n"; - output_string buildfile "\n"; - output_string buildfile "\n"; - add_class_to_buildfile ( ( [] , "__main__") , main_deps ); - output_string buildfile "\n"; - output_string buildfile ("\n"); - output_string buildfile "\n"; - output_string buildfile build_extra; - output_string buildfile "\n"; - close_out buildfile;; - -let write_build_options filename defines = - let writer = cached_source_writer filename in - writer#write ( defines ^ "\n"); - let cmd = Unix.open_process_in "haxelib path hxcpp" in - writer#write (Pervasives.input_line cmd); - Pervasives.ignore (Unix.close_process_in cmd); - writer#close;; + | _ -> "include/" ^ include_prefix ^ (join_class_path path "/") ^ ".h" ) + ^ "\"/>\n") ) project_deps; + output_string buildfile ( " \n" ) + in + let add_classdef_to_buildfile (class_path, deps, _) = add_class_to_buildfile class_path deps in + + output_string buildfile "\n"; + output_string buildfile ("\n"); + output_string buildfile "\n"; + output_string buildfile "\n"; + List.iter add_classdef_to_buildfile classes; + add_class_to_buildfile ( [] , "__boot__") boot_deps; + add_class_to_buildfile ( [] , "__files__") []; + add_class_to_buildfile ( [] , "__resources__") []; + output_string buildfile "\n"; + output_string buildfile "\n"; + output_string buildfile "\n"; + add_class_to_buildfile ( [] , "__lib__") main_deps; + output_string buildfile "\n"; + output_string buildfile "\n"; + output_string buildfile "\n"; + add_class_to_buildfile ( [] , "__main__") main_deps; + output_string buildfile "\n"; + output_string buildfile "\n"; + let idx = ref 0 in + Hashtbl.iter (fun _ data -> + let id = "__res_" ^ (string_of_int !idx) in + output_string buildfile ("\n"); + incr idx; + ) common_ctx.resources; + output_string buildfile "\n"; + output_string buildfile "\n"; + List.iter (fun src -> output_string buildfile ("\n") ) extern_src; + output_string buildfile "\n"; + output_string buildfile ("\n"); + output_string buildfile "\n"; + output_string buildfile build_extra; + output_string buildfile "\n"; + close_out buildfile;; + +let write_build_options common_ctx filename defines = + let writer = cached_source_writer common_ctx filename in + PMap.iter ( fun name value -> match name with + | "true" | "sys" | "dce" | "cpp" | "debug" -> () + | _ -> writer#write (name ^ "="^(escape_command value)^ "\n" ) ) defines; + let cmd = Unix.open_process_in "haxelib path hxcpp" in + writer#write ("hxcpp=" ^ (Pervasives.input_line cmd)); + Pervasives.ignore (Unix.close_process_in cmd); + writer#close;; let create_member_types common_ctx = - let result = Hashtbl.create 0 in - let add_member class_name interface member = - match follow member.cf_type, member.cf_kind with - | _, Var _ when interface -> () - | _, Method MethDynamic when interface -> () - | TFun (_,ret), _ -> + let result = Hashtbl.create 0 in + let add_member class_name interface member = + match follow member.cf_type, member.cf_kind with + | _, Var _ when interface -> () + | _, Method MethDynamic when interface -> () + | TFun (_,ret), _ -> (*print_endline (class_name ^ "." ^ member.cf_name ^ "=" ^ (type_string ret) );*) - Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string ret) - | _,_ when not interface -> - Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string member.cf_type) + Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string ret) + | _,_ when not interface -> + Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string member.cf_type) | _ -> () - in - List.iter (fun object_def -> - (match object_def with - | TClassDecl class_def -> - let class_name = "::" ^ (join_class_path class_def.cl_path "::") in - let rec add_all_fields class_def = - (match class_def.cl_super with Some super -> add_all_fields (fst super) | _->();); - List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_fields; - List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_statics - in - add_all_fields class_def - | _ -> ( ) - ) ) common_ctx.types; - result;; + in + List.iter (fun object_def -> + (match object_def with + | TClassDecl class_def -> + let class_name = "::" ^ (join_class_path class_def.cl_path "::") in + let rec add_all_fields class_def = + (match class_def.cl_super with Some super -> add_all_fields (fst super) | _->();); + List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_fields; + List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_statics + in + add_all_fields class_def + | _ -> ( ) + ) ) common_ctx.types; + result;; (* Builds inheritance tree, so header files can include parents defs. *) let create_super_dependencies common_ctx = - let result = Hashtbl.create 0 in - List.iter (fun object_def -> - (match object_def with - | TClassDecl class_def when not class_def.cl_extern -> - let deps = ref [] in - (match class_def.cl_super with Some super -> + let result = Hashtbl.create 0 in + List.iter (fun object_def -> + (match object_def with + | TClassDecl class_def when not class_def.cl_extern -> + let deps = ref [] in + (match class_def.cl_super with Some super -> if not (fst super).cl_extern then - deps := ((fst super).cl_path) :: !deps - | _ ->() ); - List.iter (fun imp -> deps := (fst imp).cl_path :: !deps) (real_interfaces class_def.cl_implements); - Hashtbl.add result class_def.cl_path !deps; - | TEnumDecl enum_def when not enum_def.e_extern -> - Hashtbl.add result enum_def.e_path []; - | _ -> () ); - ) common_ctx.types; - result;; + deps := ((fst super).cl_path) :: !deps + | _ ->() ); + List.iter (fun imp -> if not (fst imp).cl_extern then deps := (fst imp).cl_path :: !deps) (real_interfaces class_def.cl_implements); + Hashtbl.add result class_def.cl_path !deps; + | TEnumDecl enum_def when not enum_def.e_extern -> + Hashtbl.add result enum_def.e_path []; + | _ -> () ); + ) common_ctx.types; + result;; let create_constructor_dependencies common_ctx = - let result = Hashtbl.create 0 in - List.iter (fun object_def -> - (match object_def with - | TClassDecl class_def when not class_def.cl_extern -> - (match class_def.cl_constructor with - | Some func_def -> Hashtbl.add result class_def.cl_path func_def - | _ -> () ) - | _ -> () ); - ) common_ctx.types; - result;; + let result = Hashtbl.create 0 in + List.iter (fun object_def -> + (match object_def with + | TClassDecl class_def when not class_def.cl_extern -> + (match class_def.cl_constructor with + | Some func_def -> Hashtbl.add result class_def.cl_path func_def + | _ -> () ) + | _ -> () ); + ) common_ctx.types; + result;; +(* + + Exports can now be done with macros and a class list let rec s_type t = let result = - match follow t with - | TMono r -> (match !r with | None -> "Dynamic" | Some t -> s_type t) - | TEnum (e,tl) -> Ast.s_type_path e.e_path ^ s_type_params tl - | TInst (c,tl) -> Ast.s_type_path c.cl_path ^ s_type_params tl - | TType (t,tl) -> Ast.s_type_path t.t_path ^ s_type_params tl - | TAbstract (a,tl) -> Ast.s_type_path a.a_path ^ s_type_params tl - | TFun ([],t) -> "Void -> " ^ s_fun t false - | TFun (l,t) -> - String.concat " -> " (List.map (fun (s,b,t) -> - (if b then "?" else "") ^ (""(*if s = "" then "" else s ^ " : "*)) ^ s_fun t true - ) l) ^ " -> " ^ s_fun t false - | TAnon a -> - let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type f.cf_type) :: acc) a.a_fields [] in - "{" ^ (if not (is_closed a) then "+" else "") ^ String.concat "," fl ^ " }" - | TDynamic t2 -> "Dynamic" ^ s_type_params (if t == t2 then [] else [t2]) - | TLazy f -> s_type (!f()) + match t with + | TMono r -> (match !r with | None -> "Dynamic" | Some t -> s_type t) + | TEnum (e,tl) -> Ast.s_type_path e.e_path ^ s_type_params tl + | TInst (c,tl) -> Ast.s_type_path c.cl_path ^ s_type_params tl + | TType (t,tl) -> Ast.s_type_path t.t_path ^ s_type_params tl + | TAbstract (abs,pl) when abs.a_impl <> None -> + s_type (Abstract.get_underlying_type abs pl); + | TAbstract (a,tl) -> Ast.s_type_path a.a_path ^ s_type_params tl + | TFun ([],t) -> "Void -> " ^ s_fun t false + | TFun (l,t) -> + String.concat " -> " (List.map (fun (s,b,t) -> + (if b then "?" else "") ^ (""(*if s = "" then "" else s ^ " : "*)) ^ s_fun t true + ) l) ^ " -> " ^ s_fun t false + | TAnon a -> + let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type f.cf_type) :: acc) a.a_fields [] in + "{" ^ (if not (is_closed a) then "+" else "") ^ String.concat "," fl ^ " }" + | TDynamic t2 -> "Dynamic" ^ s_type_params (if t == t2 then [] else [t2]) + | TLazy f -> s_type (!f()) in if result="Array" then "haxe.io.BytesData" else result and s_fun t void = - match follow t with - | TFun _ -> "(" ^ s_type t ^ ")" - | TEnum ({ e_path = ([],"Void") },[]) when void -> "(" ^ s_type t ^ ")" - | TAbstract ({ a_path = ([],"Void") },[]) when void -> "(" ^ s_type t ^ ")" - | TMono r -> (match !r with | None -> s_type t | Some t -> s_fun t void) - | TLazy f -> s_fun (!f()) void - | _ -> (s_type t) + match follow t with + | TFun _ -> "(" ^ s_type t ^ ")" + | TAbstract ({ a_path = ([],"Void") },[]) when void -> "(" ^ s_type t ^ ")" + | TMono r -> (match !r with | None -> s_type t | Some t -> s_fun t void) + | TLazy f -> s_fun (!f()) void + | _ -> (s_type t) and s_type_params = function - | [] -> "" - | l -> "<" ^ String.concat ", " (List.map s_type l) ^ ">" + | [] -> "" + | l -> "< " ^ String.concat ", " (List.map s_type l) ^ " >" ;; - - - let gen_extern_class common_ctx class_def file_info = - let file = new_source_file common_ctx.file "extern" ".hx" class_def.cl_path in + let file = new_source_file common_ctx common_ctx.file "extern" ".hx" class_def.cl_path in let path = class_def.cl_path in - let filterPath = fst path @ [snd path] in - let rec remove_prefix field t = match t with - | TInst ({cl_path=[f],suffix } as cval ,tl) when f=field -> - TInst ( { cval with cl_path = ([],suffix) }, List.map (remove_prefix field) tl) - | TInst ({cl_path=cpath,suffix } as cval ,tl) when cpath=filterPath -> - TInst ( { cval with cl_path = ([],suffix) }, List.map (remove_prefix field) tl) - | TInst (cval,tl) -> TInst ( cval, List.map (remove_prefix field) tl) - (*| TInst ({cl_path=prefix} as cval ,tl) -> + + let rec remove_all_prefix class_def field t = + let path = class_def.cl_path in + let filterPath = fst path @ [snd path] in + let rec remove_prefix t = match t with + | TInst ({cl_path=[f],suffix } as cval ,tl) when f=field -> + TInst ( { cval with cl_path = ([],suffix) }, List.map remove_prefix tl) + | TInst ({cl_path=cpath,suffix } as cval ,tl) when cpath=filterPath -> + TInst ( { cval with cl_path = ([],suffix) }, List.map remove_prefix tl) + | TInst (cval,tl) -> TInst ( cval, List.map remove_prefix tl) + (*| TInst ({cl_path=prefix} as cval ,tl) -> TInst ( { cval with cl_path = ([],snd cval.cl_path) }, List.map (remove_prefix field) tl)*) - | t -> Type.map (remove_prefix field) t + | t -> Type.map remove_prefix t + in + let t = remove_prefix t in + let superred = (match class_def.cl_super with + | Some (super,_) -> remove_all_prefix super field t + | _ -> t ) in - let params = function [] -> "" | l -> "<" ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ ">") in + List.fold_left ( fun t (impl,_) -> remove_all_prefix impl field t ) superred class_def.cl_implements; + (* + remove_prefix t + *) + in + + + let params = function [] -> "" | l -> "< " ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ " >") in let output = file#write in let print_field stat f = - let s_type t = s_type (remove_prefix f.cf_name t) in + let s_type t = s_type (remove_all_prefix class_def f.cf_name t) in let args = function TFun (args,_) -> - String.concat "," (List.map (fun (name,opt,t) -> (if opt then "?" else "") ^ name ^":"^ (s_type t)) args) | _ -> "" in + String.concat "," (List.map (fun (name,opt,t) -> (if opt then "?" else "") ^ name ^":"^ (s_type t)) args) | _ -> "" in let ret = function TFun (_,ret) -> s_type ret | _ -> "Dynamic" in let override = if (is_override class_def f.cf_name ) then "override " else "" in - output ("\t" ^ (if stat then "static " else "") ^ (if f.cf_public then "public " else "") ); + output ("\t" ^ (if stat then "static " else "") ^ (if f.cf_public then "public " else "") ); let s_access mode op name = match mode with | AccNormal -> "default" | AccNo -> "null" | AccNever -> "never" | AccResolve -> "resolve" | AccCall -> op ^ "_" ^ name - | AccInline -> "default" + | AccInline -> "default" | AccRequire (n,_) -> "require " ^ n in (match f.cf_kind, f.cf_name with - | Var { v_read = AccInline; v_write = AccNever },_ -> - (match f.cf_expr with Some expr -> - output ("inline var " ^ f.cf_name ^ ":" ^ (s_type f.cf_type) ^ "=" ); - let ctx = (new_extern_context common_ctx file false file_info) in - gen_expression ctx true expr; - | _ -> () ) - | Var { v_read = AccNormal; v_write = AccNormal },_ -> output ("var " ^ f.cf_name ^ ":" ^ (s_type f.cf_type)) - | Var v,_ -> output ("var " ^ f.cf_name ^ "(" ^ (s_access v.v_read "get" f.cf_name) ^ "," ^ (s_access v.v_write "set" f.cf_name) ^ "):" ^ (s_type f.cf_type)) - | Method _, "new" -> output ("function new(" ^ (args f.cf_type) ^ "):Void") - | Method MethDynamic, _ -> output ("dynamic function " ^ f.cf_name ^ (params f.cf_params) ^ "(" ^ (args f.cf_type) ^ "):" ^ (ret f.cf_type) ) - | Method _, _ -> output (override ^ "function " ^ f.cf_name ^ (params f.cf_params) ^ "(" ^ (args f.cf_type) ^ "):" ^ (ret f.cf_type) ) + | Var { v_read = AccInline; v_write = AccNever },_ -> + (match f.cf_expr with Some expr -> + output ("inline var " ^ f.cf_name ^ ":" ^ (s_type f.cf_type) ^ "=" ); + let ctx = (new_extern_context common_ctx file 1 file_info) in + gen_expression ctx true expr; + | _ -> () ) + | Var { v_read = AccNormal; v_write = AccNormal },_ -> output ("var " ^ f.cf_name ^ ":" ^ (s_type f.cf_type)) + | Var v,_ -> output ("var " ^ f.cf_name ^ "(" ^ (s_access v.v_read "get" f.cf_name) ^ "," ^ (s_access v.v_write "set" f.cf_name) ^ "):" ^ (s_type f.cf_type)) + | Method _, "new" -> output ("function new(" ^ (args f.cf_type) ^ "):Void") + | Method MethDynamic, _ -> output ("dynamic function " ^ f.cf_name ^ (params f.cf_params) ^ "(" ^ (args f.cf_type) ^ "):" ^ (ret f.cf_type) ) + | Method _, _ -> output (override ^ "function " ^ f.cf_name ^ (params f.cf_params) ^ "(" ^ (args f.cf_type) ^ "):" ^ (ret f.cf_type) ) ); - output ";\n\n"; - in + output ";\n\n"; + in - let s_type t = s_type (remove_prefix "*" t) in + let s_type t = s_type (remove_all_prefix class_def "*" t) in let c = class_def in - output ( "package " ^ (String.concat "." (fst path)) ^ ";\n" ); - output ( "@:include extern " ^ (if c.cl_private then "private " else "") ^ (if c.cl_interface then "interface" else "class") - ^ " " ^ (snd path) ^ (params c.cl_types) ); - (match c.cl_super with None -> () | Some (c,pl) -> output (" extends " ^ (s_type (TInst (c,pl))))); - List.iter (fun (c,pl) -> output ( " implements " ^ (s_type (TInst (c,pl))))) (real_interfaces c.cl_implements); - (match c.cl_dynamic with None -> () | Some t -> output (" implements Dynamic<" ^ (s_type t) ^ ">")); - (match c.cl_array_access with None -> () | Some t -> output (" implements ArrayAccess<" ^ (s_type t) ^ ">")); - output "{\n"; - (match c.cl_constructor with - | None -> () - | Some f -> print_field false f); + output ( "package " ^ (String.concat "." (fst path)) ^ ";\n" ); + output ( "@:include extern " ^ (if c.cl_private then "private " else "") ^ (if c.cl_interface then "interface" else "class") + ^ " " ^ (snd path) ^ (params c.cl_params) ); + (match c.cl_super with None -> () | Some (c,pl) -> output (" extends " ^ (s_type (TInst (c,pl))))); + List.iter (fun (c,pl) -> output ( " implements " ^ (s_type (TInst (c,pl))))) (real_interfaces c.cl_implements); + (match c.cl_dynamic with None -> () | Some t -> output (" implements Dynamic< " ^ (s_type t) ^ " >")); + (match c.cl_array_access with None -> () | Some t -> output (" implements ArrayAccess< " ^ (s_type t) ^ " >")); + output "{\n"; + (match c.cl_constructor with + | None -> () + | Some f -> print_field false f); let is_public f = f.cf_public in - List.iter (print_field false) (List.filter is_public c.cl_ordered_fields); - List.iter (print_field true) (List.filter is_public c.cl_ordered_statics); - output "}"; + List.iter (print_field false) (List.filter is_public c.cl_ordered_fields); + List.iter (print_field true) (List.filter is_public c.cl_ordered_statics); + output "}"; output "\n"; - file#close + file#close ;; let gen_extern_enum common_ctx enum_def file_info = - let path = enum_def.e_path in - let file = new_source_file common_ctx.file "extern" ".hx" path in + let path = enum_def.e_path in + let file = new_source_file common_ctx common_ctx.file "extern" ".hx" path in let output = file#write in - let params = function [] -> "" | l -> "<" ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ ">") in - output ( "package " ^ (String.concat "." (fst path)) ^ ";\n" ); - output ( "@:include extern " ^ (if enum_def.e_private then "private " else "") - ^ " enum " ^ (snd path) ^ (params enum_def.e_types) ); - output " {\n"; - PMap.iter (fun _ constructor -> - let name = keyword_remap constructor.ef_name in - match constructor.ef_type with - | TFun (args,_) -> - output ( name ^ "(" ); - output ( String.concat "," (List.map (fun (arg,_,t) -> arg ^ ":" ^ (s_type t) ) args) ); - output ");\n\n"; - | _ -> output ( name ^ ";\n\n" ) - ) enum_def.e_constrs; + let params = function [] -> "" | l -> "< " ^ (String.concat "," (List.map (fun (n,t) -> n) l) ^ " >") in + output ( "package " ^ (String.concat "." (fst path)) ^ ";\n" ); + output ( "@:include extern " ^ (if enum_def.e_private then "private " else "") + ^ " enum " ^ (snd path) ^ (params enum_def.e_params) ); + output " {\n"; + let sorted_items = List.sort (fun f1 f2 -> (f1.ef_index - f2.ef_index ) ) (pmap_values enum_def.e_constrs) in + List.iter (fun constructor -> + let name = keyword_remap constructor.ef_name in + match constructor.ef_type with + | TFun (args,_) -> + output ( name ^ "(" ); + output ( String.concat "," (List.map (fun (arg,_,t) -> arg ^ ":" ^ (s_type t) ) args) ); + output ");\n\n"; + | _ -> output ( name ^ ";\n\n" ) + ) sorted_items; + + output "}\n"; + file#close +;; +*) - output "}\n"; - file#close +let is_this expression = + match (remove_parens expression).eexpr with + | TConst TThis -> true + | _ -> false ;; +let is_super expression = + match (remove_parens expression).eexpr with + | TConst TSuper -> true + | _ -> false +;; -(* The common_ctx contains the haxe AST in the "types" field and the resources *) -let generate common_ctx = - make_base_directory common_ctx.file; - - let debug = false in - let exe_classes = ref [] in - let boot_classes = ref [] in - let init_classes = ref [] in - let file_info = ref PMap.empty in - let class_text path = join_class_path path "::" in - let member_types = create_member_types common_ctx in - let super_deps = create_super_dependencies common_ctx in - let constructor_deps = create_constructor_dependencies common_ctx in - let main_deps = ref [] in - let build_xml = ref "" in - let scriptable = (Common.defined common_ctx Define.Scriptable) in - let gen_externs = scriptable || (Common.defined common_ctx Define.DllExport) in - if (gen_externs) then begin - make_base_directory (common_ctx.file ^ "/extern"); - end; +let is_assign_op op = + match op with + | OpAssign + | OpAssignOp _ -> true + | _ -> false +;; - List.iter (fun object_def -> - (match object_def with - | TClassDecl class_def when class_def.cl_extern -> +let rec script_type_string haxe_type = + match haxe_type with + | TType ({ t_path = ([],"Null") },[t]) -> + (match follow t with + | TAbstract ({ a_path = [],"Int" },_) + | TAbstract ({ a_path = [],"Float" },_) + | TAbstract ({ a_path = [],"Bool" },_) + | TInst ({ cl_path = [],"Int" },_) + | TInst ({ cl_path = [],"Float" },_) + | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" + | _ -> script_type_string t) + | TInst ({cl_path=[],"Null"},[t]) -> + (match follow t with + | TAbstract ({ a_path = [],"Int" },_) + | TAbstract ({ a_path = [],"Float" },_) + | TAbstract ({ a_path = [],"Bool" },_) + | TInst ({ cl_path = [],"Int" },_) + | TInst ({ cl_path = [],"Float" },_) + | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" + | _ -> script_type_string t ) + | _ -> + match follow haxe_type with + | TType ({t_path = [],"Array"},params) -> "Array" + | TInst ({cl_path=[],"Array"},params) -> + (match params with + | [t] -> + (match type_string_suff "" t false with + | "int" -> "Array.int" + | "Float" -> "Array.Float" + | "bool" -> "Array.bool" + | "::String" -> "Array.String" + | "unsigned char" -> "Array.unsigned char" + | "Dynamic" -> "Array.Any" + | _ -> "Array.Object" + ) + | _ -> "Array.Object" + ) + | TAbstract (abs,pl) when abs.a_impl <> None -> + script_type_string (Abstract.get_underlying_type abs pl); + | _ -> + type_string_suff "" haxe_type false +;; + +type array_of = + | ArrayInterface of int + | ArrayData of string + | ArrayObject + | ArrayAny + | ArrayNone +;; + +let is_template_type t = + false +;; + +let rec is_dynamic_in_cppia ctx expr = + match expr.eexpr with + | TCast(_,None) -> true + | _ -> is_dynamic_in_cpp ctx expr +;; + +type cppia_op = + | IaFunction + | IaVar + | IaToInterface + | IaToDynArray + | IaToDataArray + | IaToInterfaceArray + | IaFun + | IaCast + | IaBlock + | IaBreak + | IaContinue + | IaIsNull + | IaNotNull + | IaSet + | IaCall + | IaCallGlobal + | IaCallStatic + | IaCallMember + | IaCallSuper + | IaCallThis + | IaCallSuperNew + | IaCreateEnum + | IaADef + | IaIf + | IaIfElse + | IaFStatic + | IaFName + | IaFThisInst + | IaFLink + | IaFThisName + | IaFEnum + | IaThrow + | IaArrayI + | IaPlusPlus + | IaPlusPlusPost + | IaMinusMinus + | IaMinusMinusPost + | IaNeg + | IaBitNot + | IaLogicNot + | IaTVars + | IaVarDecl + | IaVarDeclI + | IaNew + | IaReturn + | IaRetVal + | IaPosInfo + | IaObjDef + | IaClassOf + | IaWhile + | IaFor + | IaEnumI + | IaSwitch + | IaTry + | IaImplDynamic + | IaConstInt + | IaConstFloat + | IaConstString + | IaConstFalse + | IaConstTrue + | IaConstNull + | IaConsThis + | IaConstSuper + | IaCastInt + | IaCastBool + | IaInterface + | IaClass + | IaAccessNormal + | IaAccessNot + | IaAccessResolve + | IaAccessCall + | IaEnum + | IaInline + | IaMain + | IaNoMain + | IaResources + | IaReso + | IaNoCast + | IaAccessCallNative + + | IaBinOp of Ast.binop +;; + +let cppia_op_info = function + | IaFunction -> ("FUNCTION", 1) + | IaVar -> ("VAR", 2) + | IaToInterface -> ("TOINTERFACE", 3) + | IaToDynArray -> ("TODYNARRAY", 4) + | IaToDataArray -> ("TODATAARRAY", 5) + | IaToInterfaceArray -> ("TOINTERFACEARRAY", 6) + | IaFun -> ("FUN", 7) + | IaCast -> ("CAST", 8) + | IaBlock -> ("BLOCK", 9) + | IaBreak -> ("BREAK", 10) + | IaContinue -> ("CONTINUE", 11) + | IaIsNull -> ("ISNULL", 12) + | IaNotNull -> ("NOTNULL", 13) + | IaSet -> ("SET", 14) + | IaCall -> ("CALL", 15) + | IaCallGlobal -> ("CALLGLOBAL", 16) + | IaCallStatic -> ("CALLSTATIC", 17) + | IaCallMember -> ("CALLMEMBER", 18) + | IaCallSuper -> ("CALLSUPER", 19) + | IaCallThis -> ("CALLTHIS", 20) + | IaCallSuperNew -> ("CALLSUPERNEW", 21) + | IaCreateEnum -> ("CREATEENUM", 22) + | IaADef -> ("ADEF", 23) + | IaIf -> ("IF", 24) + | IaIfElse -> ("IFELSE", 25) + | IaFName -> ("FNAME", 27) + | IaFStatic -> ("FSTATIC", 28) + | IaFThisInst -> ("FTHISINST", 29) + | IaFLink -> ("FLINK", 30) + | IaFThisName -> ("FTHISNAME", 31) + | IaFEnum -> ("FENUM", 32) + | IaThrow -> ("THROW", 33) + | IaArrayI -> ("ARRAYI", 34) + | IaPlusPlus -> ("++", 35) + | IaPlusPlusPost -> ("+++", 36) + | IaMinusMinus -> ("--", 37) + | IaMinusMinusPost -> ("---", 38) + | IaNeg -> ("NEG", 39) + | IaBitNot -> ("~", 40) + | IaLogicNot -> ("!", 41) + | IaTVars -> ("TVARS", 42) + | IaVarDecl -> ("VARDECL", 43) + | IaVarDeclI -> ("VARDECLI", 44) + | IaNew -> ("NEW", 45) + | IaReturn -> ("RETURN", 46) + | IaRetVal -> ("RETVAL", 47) + | IaPosInfo -> ("POSINFO", 48) + | IaObjDef -> ("OBJDEF", 49) + | IaClassOf -> ("CLASSOF", 50) + | IaWhile -> ("WHILE", 51) + | IaFor -> ("FOR", 52) + | IaEnumI -> ("ENUMI", 53) + | IaSwitch -> ("SWITCH", 54) + | IaTry -> ("TRY", 55) + | IaImplDynamic -> ("IMPLDYNAMIC", 56) + | IaConstInt -> ("i", 57) + | IaConstFloat -> ("f", 58) + | IaConstString -> ("s", 59) + | IaConstFalse -> ("false", 60) + | IaConstTrue -> ("true", 61) + | IaConstNull -> ("NULL", 62) + | IaConsThis -> ("THIS", 63) + | IaConstSuper -> ("SUPER", 64) + | IaCastInt -> ("CASTINT", 65) + | IaCastBool -> ("CASTBOOL", 66) + | IaInterface -> ("INTERFACE", 67) + | IaClass -> ("CLASS", 68) + | IaAccessNormal -> ("N", 69) + | IaAccessNot -> ("n", 70) + | IaAccessResolve -> ("R", 71) + | IaAccessCall -> ("C", 72) + | IaEnum -> ("ENUM", 73) + | IaInline -> ("INLINE", 74) + | IaMain -> ("MAIN", 75) + | IaNoMain -> ("NOMAIN", 76) + | IaResources -> ("RESOURCES", 77) + | IaReso -> ("RESO", 78) + | IaNoCast -> ("NOCAST", 79) + | IaAccessCallNative -> ("V", 80) + + | IaBinOp OpAdd -> ("+", 101) + | IaBinOp OpMult -> ("*", 102) + | IaBinOp OpDiv -> ("/", 103) + | IaBinOp OpSub -> ("-", 104) + | IaBinOp OpAssign -> ("=", 105) + | IaBinOp OpEq -> ("==", 106) + | IaBinOp OpNotEq -> ("!=", 107) + | IaBinOp OpGte -> (">=", 108) + | IaBinOp OpLte -> ("<=", 109) + | IaBinOp OpGt -> (">", 110) + | IaBinOp OpLt -> ("<", 111) + | IaBinOp OpAnd -> ("&", 112) + | IaBinOp OpOr -> ("|", 113) + | IaBinOp OpXor -> ("^", 114) + | IaBinOp OpBoolAnd -> ("&&", 115) + | IaBinOp OpBoolOr -> ("||", 116) + | IaBinOp OpShr -> (">>", 117) + | IaBinOp OpUShr -> (">>>", 118) + | IaBinOp OpShl -> ("<<", 119) + | IaBinOp OpMod -> ("%", 120) + | IaBinOp OpInterval -> ("...", 121) + | IaBinOp OpArrow -> ("=>", 122) + | IaBinOp OpAssignOp OpAdd -> ("+=", 201) + | IaBinOp OpAssignOp OpMult -> ("*=", 202) + | IaBinOp OpAssignOp OpDiv -> ("/=", 203) + | IaBinOp OpAssignOp OpSub -> ("-=", 204) + + + | IaBinOp OpAssignOp OpAnd -> ("&=", 212) + | IaBinOp OpAssignOp OpOr -> ("|=", 213) + | IaBinOp OpAssignOp OpXor -> ("^=", 214) + | IaBinOp OpAssignOp OpBoolAnd -> ("&&=", 215) + | IaBinOp OpAssignOp OpBoolOr -> ("||=", 216) + | IaBinOp OpAssignOp OpShr -> (">>=", 217) + | IaBinOp OpAssignOp OpUShr -> (">>>=", 218) + | IaBinOp OpAssignOp OpShl -> ("<<=", 219) + | IaBinOp OpAssignOp OpMod -> ("%=", 220) + + | IaBinOp OpAssignOp OpInterval + | IaBinOp OpAssignOp OpAssign + | IaBinOp OpAssignOp OpEq + | IaBinOp OpAssignOp OpNotEq + | IaBinOp OpAssignOp OpGte + | IaBinOp OpAssignOp OpLte + | IaBinOp OpAssignOp OpGt + | IaBinOp OpAssignOp OpLt + | IaBinOp OpAssignOp OpAssignOp _ + | IaBinOp OpAssignOp OpArrow -> assert false +;; + +class script_writer common_ctx ctx filename asciiOut = + object(this) + val debug = asciiOut + val indent_str = if asciiOut then "\t" else "" + val mutable indent = "" + val mutable indents = [] + val mutable just_finished_block = false + val mutable classCount = 0 + val mutable return_type = TMono(ref None) + val buffer = Buffer.create 0 + val identTable = Hashtbl.create 0 + val fileTable = Hashtbl.create 0 + val identBuffer = Buffer.create 0 + + method stringId name = + try ( Hashtbl.find identTable name ) + with Not_found -> begin + let size = Hashtbl.length identTable in + Hashtbl.add identTable name size; + Buffer.add_string identBuffer ((string_of_int (String.length name)) ^ " " ^ name ^ "\n"); + size; + end + method incClasses = classCount <- classCount +1 + + method stringText name = (string_of_int (this#stringId name)) ^ " " + val typeTable = Hashtbl.create 0 + val typeBuffer = Buffer.create 0 + method typeId name = + let name = if name="::hx::Class" then "::Class" else name in + try ( Hashtbl.find typeTable name ) + with Not_found -> begin + let size = Hashtbl.length typeTable in + Hashtbl.add typeTable name size; + Buffer.add_string typeBuffer ((string_of_int (String.length name)) ^ " " ^ name ^ "\n"); + size; + end + method write str = if asciiOut then + Buffer.add_string buffer str + else begin + let push i = Buffer.add_char buffer (Char.chr i) in + let pushI32 i = push (Int32.to_int (Int32.logand i (Int32.of_int 255))) in + List.iter (fun i -> + if ((Int32.compare i Int32.zero) >= 0) && ((Int32.compare i (Int32.of_int 254)) < 0) then + pushI32 i + else if ((Int32.compare i Int32.zero) >= 0) && ((Int32.compare i (Int32.of_int 65536)) < 0) then begin + push 254; + pushI32 i; + pushI32 (Int32.shift_right i 8); + end else begin + push 255; + pushI32 i; + pushI32 (Int32.shift_right i 8); + pushI32 (Int32.shift_right i 16); + pushI32 (Int32.shift_right i 24); + end + ) (List.map Int32.of_string (Str.split (Str.regexp "[\n\t ]+") str) ); + end; + just_finished_block <- false + method typeTextString typeName = (string_of_int (this#typeId typeName)) ^ " " + method typeText typeT = (string_of_int (this#typeId (script_type_string typeT))) ^ " " + method writeType typeT = this#write (this#typeText typeT) + method boolText value = if value then "1" else "0" + method writeBool value = this#write (if value then "1 " else "0 ") + method staticText value = if value then "1" else "0" + method writeData str = Buffer.add_string buffer str; + method wint ival = this#write ((string_of_int ival)^" ") + method ident name = this#wint (this#stringId name) + method instText clazz = match clazz.cl_path with + | ([],"Array") -> string_of_int (this#typeId "Array< ::Dynamic >") ^ " " + | _ -> this#typeText (TInst(clazz,[])) + method instName clazz = this#write (this#instText clazz) + method enumText e = this#typeText (TEnum(e,[])) + method enumName e = this#write (this#enumText e) + method close = + let out_file = open_out_bin filename in + output_string out_file (if asciiOut then "CPPIA\n" else "CPPIB\n"); + let idents = Buffer.contents identBuffer in + output_string out_file ((string_of_int (Hashtbl.length identTable)) ^ "\n"); + output_string out_file idents; + let types = Buffer.contents typeBuffer in + output_string out_file ((string_of_int (Hashtbl.length typeTable)) ^ "\n"); + output_string out_file types; + output_string out_file ( (string_of_int classCount) ^ "\n" ); + let contents = Buffer.contents buffer in + output_string out_file contents; + close_out out_file + method fileId file = + try ( Hashtbl.find fileTable file ) + with Not_found -> begin + let stripped_file = strip_file common_ctx file in + let result = this#stringId stripped_file in + Hashtbl.add fileTable file result; + result; + end + method constText c = match c with + | TInt i -> (this#op IaConstInt) ^ (Printf.sprintf "%ld " i) + | TFloat f -> (this#op IaConstFloat) ^ (this#stringText f) + | TString s -> (this#op IaConstString) ^ (this#stringText s) + | TBool true -> (this#op IaConstTrue) + | TBool false -> (this#op IaConstFalse) + | TNull -> (this#op IaConstNull) + | TThis -> (this#op IaConsThis) + | TSuper -> (this#op IaConstSuper) + + method get_array_type t = + match follow t with + | TInst ({cl_path=[],"Array"},[param]) -> + let typeName = type_string_suff "" param false in + (match typeName with + | "::String" -> ArrayData "String" + | "int" | "Float" | "bool" | "String" | "unsigned char" -> + ArrayData typeName + | "cpp::ArrayBase" | "Dynamic" -> ArrayAny + | _ when is_interface_type param -> ArrayInterface (this#typeId (script_type_string param)) + | _ -> ArrayObject + ) + | TAbstract (abs,pl) when abs.a_impl <> None -> + this#get_array_type (Abstract.get_underlying_type abs pl); + | _ -> ArrayNone; + + method pushReturn inType = + let oldReturnType = return_type in + return_type <- inType; + fun () -> return_type <- oldReturnType; + method fileText file = string_of_int (this#fileId file) + method indent_one = this#write indent_str + method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents + method pop_indent = match indents with + | h::tail -> indents <- tail; indent <- String.concat "" indents + | [] -> indent <- "/*?*/"; + method write_i x = this#write (indent ^ x) + method get_indent = indent + method begin_expr = this#push_indent + method end_expr = if not just_finished_block then this#write "\n"; this#pop_indent; just_finished_block <- true + method op x = match cppia_op_info x with + | (name,index) -> (if debug then name else string_of_int index) ^ " " + method writeOp o = this#write (this#op o) + method writeOpLine o = this#write ((this#op o) ^ "\n") + method voidFunc isStatic isDynamic funcName fieldExpression = + this#write ( (this#op IaFunction) ^ (this#staticText isStatic) ^ " " ^(this#boolText isDynamic) ^ " " ^(this#stringText funcName) ^ " "); + this#write ((this#typeTextString "Void") ^ "0\n"); + this#gen_expression fieldExpression + method func isStatic isDynamic funcName ret args isInterface fieldExpression = + this#write ( (this#op IaFunction) ^ (this#staticText isStatic) ^ " " ^(this#boolText isDynamic) ^ " " ^(this#stringText funcName) ^ " "); + this#write ((this#typeText ret) ^ (string_of_int (List.length args)) ^ " "); + List.iter (fun (name,opt,typ) -> this#write ( (this#stringText name) ^ (this#boolText opt) ^ " " ^ (this#typeText typ) ^ " " )) args; + this#write "\n"; + if (not isInterface) then begin + match fieldExpression with + | Some ({ eexpr = TFunction function_def } as e) -> this#gen_expression e + | _ -> print_endline ("Missing function body for " ^ funcName ); + end + method var readAcc writeAcc isExtern isStatic name varType varExpr = + this#write ( (this#op IaVar) ^ (this#staticText isStatic) ^ " " ^ (this#op readAcc) ^ (this#op writeAcc) ^ + (this#boolText isExtern) ^ " " ^ (this#stringText name)^ (this#typeText varType) ^ + (match varExpr with Some _ -> "1\n" | _ -> "0\n" ) ); + match varExpr with + | Some expression -> this#gen_expression expression + | _ -> () + method implDynamic = this#writeOpLine IaImplDynamic; + method writeVar v = + this#ident v.v_name; + this#wint v.v_id; + this#writeBool v.v_capture; + this#writeType v.v_type; + method writeList prefix len = this#write (prefix ^" " ^ (string_of_int (len)) ^ "\n"); + method writePos expr = if debug then + this#write ( (this#fileText expr.epos.pfile) ^ "\t" ^ (string_of_int (Lexer.get_error_line expr.epos) ) ^ indent); + method checkCast toType expr forceCast fromGenExpression= + let write_cast text = + if (not fromGenExpression) then + this#writePos expr; + this#write (text ^"\n" ); + this#begin_expr; + this#gen_expression expr; + this#end_expr; + true; + in + let was_cast = + if (is_interface_type toType) then begin + if (is_dynamic_in_cppia ctx expr) then begin + write_cast ( (this#op IaToInterface) ^ (this#typeText toType) ^ " " ^ (this#typeTextString "Dynamic") ) + end else if (not (is_matching_interface_type toType expr.etype)) then begin + write_cast ( (this#op IaToInterface) ^ (this#typeText toType) ^ " " ^ (this#typeText expr.etype) ) + end else + false + end else begin + let get_array_expr_type expr = + if is_dynamic_in_cppia ctx expr then + ArrayNone + else + this#get_array_type expr.etype + in + match (this#get_array_type toType), (get_array_expr_type expr) with + | ArrayAny, _ -> false + | ArrayObject, ArrayData _ -> write_cast (this#op IaToDynArray) + | ArrayData t, ArrayNone + | ArrayData t, ArrayObject + | ArrayData t, ArrayAny -> write_cast ((this#op IaToDataArray) ^ (this#typeTextString ("Array." ^ t))) + | ArrayInterface t, ArrayNone + | ArrayInterface t, ArrayAny -> write_cast ((this#op IaToInterfaceArray) ^ (string_of_int t)) + | _,_ -> (* a0,a1 -> + let arrayString a = + match a with + | ArrayNone -> "ArrayNone" + | ArrayAny -> "ArrayAny" + | ArrayObject -> "ArrayObject" + | ArrayData _ -> "ArrayData" + | ArrayInterface _ -> "ArrayInterface" + in + this#write ("NOCAST " ^ (arrayString a0) ^ "=" ^ (arrayString a1)); *) + false + end + in + + if (not was_cast) then begin + if (forceCast) then begin + let op =match (type_string expr.etype) with + | "int" -> IaCastInt + | "bool" -> IaCastBool + | _ when is_interface_type toType -> IaNoCast + | _ -> IaCast + in + this#writeOpLine op; + end; + this#gen_expression expr; + end + method gen_expression expr = + let expression = remove_parens expr in + this#begin_expr; + (*this#write ( (this#fileText expression.epos.pfile) ^ "\t" ^ (string_of_int (Lexer.get_error_line expression.epos) ) ^ indent);*) + this#writePos expression; + (match expression.eexpr with + | TFunction function_def -> this#write ( (this#op IaFun) ^ (this#typeText function_def.tf_type) ^ (string_of_int (List.length function_def.tf_args)) ^ "\n" ); + List.iter (fun(arg,init) -> + this#write (indent ^ indent_str ); + this#writeVar arg; + match init with + | Some const -> this#write ("1 " ^ (this#constText const) ^ "\n") + | _ -> this#write "0\n"; + ) function_def.tf_args; + let pop = this#pushReturn function_def.tf_type in + this#gen_expression function_def.tf_expr; + pop (); + | TBlock expr_list -> this#writeList (this#op IaBlock) (List.length expr_list); + List.iter this#gen_expression expr_list; + | TConst const -> this#write (this#constText const) + | TBreak -> this#writeOp IaBreak + | TContinue -> this#writeOp IaContinue + + | TBinop (op,e1,e2) when op=OpAssign -> + this#writeOpLine IaSet; + this#gen_expression e1; + this#checkCast e1.etype e2 false false; + | TBinop (OpEq ,e1, { eexpr = TConst TNull } ) -> this#writeOpLine IaIsNull; + this#gen_expression e1; + | TBinop (OpNotEq ,e1, { eexpr = TConst TNull }) -> this#writeOpLine IaNotNull; + this#gen_expression e1; + | TBinop (OpEq , { eexpr = TConst TNull }, e1) -> this#writeOpLine IaIsNull; + this#gen_expression e1; + | TBinop (OpNotEq, { eexpr = TConst TNull }, e1) -> this#writeOpLine IaNotNull; + this#gen_expression e1; + | TBinop (op,e1,e2) -> this#writeOpLine (IaBinOp op); + this#gen_expression e1; + this#gen_expression e2; + | TThrow e -> this#writeOpLine IaThrow; + this#gen_expression e; + | TArrayDecl expr_list -> + this#write ( (this#op IaADef) ^ (this#typeText expression.etype) ^ " " ^(string_of_int (List.length expr_list))^"\n"); + List.iter this#gen_expression expr_list; + | TIf (e,e1,e2) -> + (match e2 with + | None -> + this#writeOpLine IaIf; + this#gen_expression e; + this#gen_expression e1; + | Some elze -> + this#writeOpLine IaIfElse; + this#gen_expression e; + this#gen_expression e1; + this#gen_expression elze; ) + | TCall (func, arg_list) -> + let argN = (string_of_int (List.length arg_list)) ^ " " in + let is_real_function field = + match field.cf_kind with + | Method MethNormal | Method MethInline-> true + | _ -> false; + in + let gen_call () = + (match (remove_parens func).eexpr with + | TField ( { eexpr = TLocal { v_name = "__global__" }}, field ) -> + this#write ( (this#op IaCallGlobal) ^ (this#stringText (field_name field)) ^ argN ^ "\n"); + | TField (obj,FStatic (class_def,field) ) when is_real_function field -> + this#write ( (this#op IaCallStatic) ^ (this#instText class_def) ^ " " ^ (this#stringText field.cf_name) ^ + argN ^ "\n"); + | TField (obj,FInstance (_,_,field) ) when (is_this obj) && (is_real_function field) -> + this#write ( (this#op IaCallThis) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^ + argN ^ "\n"); + | TField (obj,FInstance (_,_,field) ) when is_super obj -> + this#write ( (this#op IaCallSuper) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^ + argN ^ "\n"); + | TField (obj,FInstance (_,_,field) ) when is_real_function field -> + this#write ( (this#op IaCallMember) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^ + argN ^ "\n"); + this#gen_expression obj; + | TField (obj,FDynamic (name) ) when (is_internal_member name || (type_string obj.etype = "::String" && name="cca") ) -> + this#write ( (this#op IaCallMember) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText name) ^ + argN ^ "\n"); + this#gen_expression obj; + | TConst TSuper -> this#write ((this#op IaCallSuperNew) ^ (this#typeText func.etype) ^ " " ^ argN ^ "\n"); + | TField (_,FEnum (enum,field)) -> this#write ((this#op IaCreateEnum) ^ (this#enumText enum) ^ " " ^ (this#stringText field.ef_name) ^ argN ^ "\n"); + | _ -> this#write ( (this#op IaCall) ^ argN ^ "\n"); + this#gen_expression func; + ); + let matched_args = match func.etype with + | TFun (args,_) -> + ( try ( + List.iter2 (fun (_,_,protoT) arg -> this#checkCast protoT arg false false) args arg_list; + true; ) + with Invalid_argument _ -> (*print_endline "Bad count?";*) false ) + | _ -> false + in + if not matched_args then + List.iter this#gen_expression arg_list; + in + (match (remove_parens func).eexpr with + | TField(obj,field) when is_array_or_dyn_array obj.etype && (field_name field)="map" -> + (match this#get_array_type expression.etype with + | ArrayData t -> + this#write ( (this#op IaToDataArray) ^ (this#typeTextString ("Array." ^ t)) ^ "\n"); + this#begin_expr; + this#writePos func; + gen_call(); + this#end_expr; + | ArrayInterface t -> + this#write ( (this#op IaToInterfaceArray) ^ (string_of_int t) ^ "\n"); + this#begin_expr; + this#writePos func; + gen_call(); + this#end_expr; + | _ -> gen_call(); + ) + | _ -> gen_call(); + ); + | TField (obj, acc) -> + let typeText = this#typeText obj.etype in + (match acc with + | FDynamic name -> this#write ( (this#op IaFName) ^ typeText ^ " " ^ (this#stringText name) ^ "\n"); + this#gen_expression obj; + | FStatic (class_def,field) -> this#write ( (this#op IaFStatic) ^ (this#instText class_def) ^ " " ^ (this#stringText field.cf_name) ); + | FInstance (_,_,field) when is_this obj -> this#write ( (this#op IaFThisInst) ^ typeText ^ " " ^ (this#stringText field.cf_name) ); + | FInstance (_,_,field) -> this#write ( (this#op IaFLink) ^ typeText ^ " " ^ (this#stringText field.cf_name) ^ "\n"); + this#gen_expression obj; + + | FClosure (_,field) when is_this obj -> this#write ( (this#op IaFThisName) ^typeText ^ " " ^ (this#stringText field.cf_name) ^ "\n") + | FAnon (field) when is_this obj -> this#write ( (this#op IaFThisName) ^typeText ^ " " ^ (this#stringText field.cf_name) ^ "\n") + + | FClosure (_,field) + | FAnon (field) -> this#write ( (this#op IaFName) ^typeText ^ " " ^ (this#stringText field.cf_name) ^ "\n"); + this#gen_expression obj; + + | FEnum (enum,field) -> this#write ( (this#op IaFEnum) ^ (this#enumText enum) ^ " " ^ (this#stringText field.ef_name) ); + ) + | TArray (e1, e2) -> this#write ((this#op IaArrayI) ^ (this#typeText e1.etype) ^ "\n"); + this#gen_expression e1; + this#gen_expression e2; + | TUnop (op, flag, e) -> + this#writeOpLine (match op,flag with + | Increment, Prefix -> IaPlusPlus + | Increment, _ -> IaPlusPlusPost + | Decrement, Prefix -> IaMinusMinus + | Decrement, _ -> IaMinusMinusPost + | Not, _ -> IaLogicNot + | Neg, _ -> IaNeg + | NegBits, _ -> IaBitNot ); + this#gen_expression e; + (* TODO - lval op-assign local/member/array *) + | TLocal var -> this#write ((this#op IaVar) ^ (string_of_int var.v_id) ); + + | TVar (tvar,optional_init) -> + this#write ( (this#op IaTVars) ^ (string_of_int (1)) ^ "\n"); + this#write ("\t\t" ^ indent); + (match optional_init with + | None -> this#writeOp IaVarDecl; + this#writeVar tvar; + | Some init ->this#writeOp IaVarDeclI; + let init = remove_parens init in + this#writeVar tvar; + this#write (" " ^ (this#typeText init.etype)); + this#write "\n"; + this#checkCast tvar.v_type init false false); + | TNew (clazz,params,arg_list) -> + this#write ((this#op IaNew) ^ (this#typeText (TInst(clazz,params))) ^ (string_of_int (List.length arg_list)) ^ "\n"); + let rec matched_args clazz = match clazz.cl_constructor, clazz.cl_super with + | None, Some super -> matched_args (fst super) + | None, _ -> false + | Some ctr, _ -> + (match ctr.cf_type with + | TFun(args,_) -> + ( try ( + List.iter2 (fun (_,_,protoT) arg -> this#checkCast protoT arg false false) args arg_list; + true; ) + with Invalid_argument _ -> (*print_endline "Bad count?";*) false ) + | _ -> false + ) + in + if not (matched_args clazz) then + List.iter this#gen_expression arg_list; + + | TReturn optval -> (match optval with + | None -> this#writeOpLine IaReturn; + | Some value -> this#write ( (this#op IaRetVal) ^ (this#typeText value.etype) ^ "\n"); + this#checkCast return_type value false false; + ) + | TObjectDecl ( + ("fileName" , { eexpr = (TConst (TString file)) }) :: + ("lineNumber" , { eexpr = (TConst (TInt line)) }) :: + ("className" , { eexpr = (TConst (TString class_name)) }) :: + ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) -> + this#write ( (this#op IaPosInfo) ^ (this#stringText file) ^ (Printf.sprintf "%ld" line) ^ " " ^ + (this#stringText class_name) ^ " " ^ (this#stringText meth)) + + | TObjectDecl values ->this#write ( (this#op IaObjDef) ^ (string_of_int (List.length values))); + this#write " "; + List.iter (fun (name,_) -> this#write (this#stringText name) ) values; + this#write "\n"; + List.iter (fun (_,e) -> this#gen_expression e ) values; + | TTypeExpr type_expr -> + let klass = "::" ^ (join_class_path (t_path type_expr) "::" ) in + this#write ((this#op IaClassOf) ^ (string_of_int (this#typeId klass))) + | TWhile (e1,e2,flag) -> this#write ( (this#op IaWhile) ^ (if flag=NormalWhile then "1" else "0" ) ^ "\n"); + this#gen_expression e1; + this#gen_expression e2; + | TFor (tvar,init,loop) -> this#writeOp IaFor; + this#writeVar tvar; + this#write "\n"; + this#gen_expression init; + this#gen_expression loop; + | TEnumParameter (expr,ef,i) -> + let enum = match follow ef.ef_type with + | TEnum(en,_) | TFun(_,TEnum(en,_)) -> en + | _ -> assert false + in + this#write ( (this#op IaEnumI) ^ (this#typeText (TEnum(enum,[])) ) ^ (string_of_int i) ^ "\n"); + this#gen_expression expr; + | TSwitch (condition,cases,optional_default) -> + this#write ( (this#op IaSwitch) ^ (string_of_int (List.length cases)) ^ " " ^ + (match optional_default with None -> "0" | Some _ -> "1") ^ "\n"); + this#gen_expression condition; + List.iter (fun (cases_list,expression) -> + this#writeList ("\t\t\t"^indent) (List.length cases_list); + List.iter (fun value -> this#gen_expression value ) cases_list; + this#gen_expression expression; + ) cases; + (match optional_default with None -> () | Some expr -> this#gen_expression expr); + | TTry (e,catches) -> + this#writeList (this#op IaTry) (List.length catches); + this#gen_expression e; + List.iter ( fun (tvar,catch_expr) -> + this#write ("\t\t\t"^indent); + this#writeVar tvar; + this#write "\n"; + this#gen_expression catch_expr; + ) catches; + | TCast (cast,None) -> this#checkCast expression.etype cast true true; + | TCast (cast,Some _) -> this#checkCast expression.etype cast true true; + | TParenthesis _ -> error "Unexpected parens" expression.epos + | TMeta(_,_) -> error "Unexpected meta" expression.epos + ); + this#end_expr; +end;; + +let generate_script_class common_ctx script class_def = + script#incClasses; + script#writeOp (if class_def.cl_interface then IaInterface else IaClass ); + script#instName class_def; + (match class_def.cl_super with + | None -> script#ident "" + | Some (c,_) -> script#instName c); + script#wint (List.length class_def.cl_implements); + List.iter (fun(c,_) -> script#instName c) class_def.cl_implements; + script#write "\n"; + (* Looks like some map impl classes have their bodies discarded - not sure best way to filter *) + let non_dodgy_function field = + class_def.cl_interface || + match field.cf_kind, field.cf_expr with + | Var _, _ -> true + | Method MethDynamic, _ -> true + | Method _, Some _ -> true + | _ -> false + in + let ordered_statics = List.filter non_dodgy_function class_def.cl_ordered_statics in + let ordered_fields = List.filter non_dodgy_function class_def.cl_ordered_fields in + script#write ((string_of_int ( (List.length ordered_fields) + + (List.length ordered_statics) + + (match class_def.cl_constructor with Some _ -> 1 | _ -> 0 ) + + (if (implement_dynamic_here class_def) then 1 else 0) + + (match class_def.cl_init with Some _ -> 1 | _ -> 0 ) ) ) + ^ "\n"); + + let generate_field isStatic field = + match field.cf_kind, follow field.cf_type with + | Var { v_read = AccInline; v_write = AccNever },_ -> + script#writeOpLine IaInline; + | Var v,_ -> + let mode_code mode = match mode with + | AccNormal -> IaAccessNormal + | AccNo -> IaAccessNot + | AccNever -> IaAccessNot + | AccResolve -> IaAccessResolve + | AccCall -> if ( (has_meta_key class_def.cl_meta Meta.NativeProperty) || + (has_meta_key field.cf_meta Meta.NativeProperty) || + (Common.defined common_ctx Define.ForceNativeProperty) ) + then IaAccessCallNative else IaAccessCall; + | AccInline -> IaAccessNormal + | AccRequire (_,_) -> IaAccessNormal + in + let isExtern = is_extern_field field in + script#var (mode_code v.v_read) (mode_code v.v_write) isExtern isStatic field.cf_name field.cf_type field.cf_expr + | Method MethDynamic, TFun(args,ret) -> + script#func isStatic true field.cf_name ret args class_def.cl_interface field.cf_expr + | Method _, TFun(args,ret) when field.cf_name="new" -> + script#func true false "new" (TInst(class_def,[])) args false field.cf_expr + | Method _, TFun (args,ret) -> + script#func isStatic false field.cf_name ret args class_def.cl_interface field.cf_expr + | Method _, _ -> print_endline ("Unknown method type " ^ (join_class_path class_def.cl_path "." ) + ^ "." ^field.cf_name ) + in + (match class_def.cl_constructor with + | Some field -> generate_field true field + | _ -> () ); + (match class_def.cl_init with + | Some expression -> script#voidFunc true false "__init__" expression + | _ -> () ); + + List.iter (generate_field false) ordered_fields; + List.iter (generate_field true) ordered_statics; + if (implement_dynamic_here class_def) then + script#implDynamic; + script#write "\n"; +;; + +let generate_script_enum common_ctx script enum_def meta = + script#incClasses; + let sorted_items = List.sort (fun f1 f2 -> (f1.ef_index - f2.ef_index ) ) (pmap_values enum_def.e_constrs) in + script#writeList ((script#op IaEnum) ^ (script#enumText enum_def)) (List.length sorted_items); + + List.iter (fun constructor -> + let name = script#stringText constructor.ef_name in + match constructor.ef_type with + | TFun (args,_) -> + script#write ( name ^ " " ^ (string_of_int (List.length args)) ); + List.iter (fun (arg,_,t) -> script#write ( " " ^ (script#stringText arg) ^ " " ^ (script#typeText t) ) ) args; + script#write "\n"; + | _ -> script#write ( name ^ " 0\n" ) + ) sorted_items; + + match meta with + | Some expr -> script#write "1\n"; + script#gen_expression expr + | _ -> script#write "0\n"; + script#write "\n" +;; + + +let generate_cppia common_ctx = + let debug = 1 in + let null_file = new source_writer common_ctx ignore (fun () -> () ) in + let ctx = new_context common_ctx null_file debug (ref PMap.empty) in + ctx.ctx_class_member_types <- create_member_types common_ctx; + let script = new script_writer common_ctx ctx common_ctx.file common_ctx.debug in + ignore (script#stringId ""); + ignore (script#typeId ""); + + List.iter (fun object_def -> + (match object_def with + | TClassDecl class_def when class_def.cl_extern -> () (*if (gen_externs) then gen_extern_class common_ctx class_def;*) - | TClassDecl class_def -> - let name = class_text class_def.cl_path in - if (gen_externs) then gen_extern_class common_ctx class_def file_info; - let is_internal = is_internal_class class_def.cl_path in - let is_generic_def = match class_def.cl_kind with KGeneric -> true | _ -> false in - if (is_internal || (is_macro class_def.cl_meta) || is_generic_def) then - ( if debug then print_endline (" internal class " ^ name )) - else begin - build_xml := !build_xml ^ (get_code class_def.cl_meta Meta.BuildXml); - boot_classes := class_def.cl_path :: !boot_classes; - if (has_init_field class_def) then - init_classes := class_def.cl_path :: !init_classes; - let deps = generate_class_files common_ctx + | TClassDecl class_def -> + let is_internal = is_internal_class class_def.cl_path in + if (is_internal || (is_macro class_def.cl_meta)) then + ( if (debug>1) then print_endline (" internal class " ^ (join_class_path class_def.cl_path ".") )) + else begin + ctx.ctx_class_name <- "::" ^ (join_class_path class_def.cl_path "::"); + generate_script_class common_ctx script class_def + end + | TEnumDecl enum_def when enum_def.e_extern -> () + | TEnumDecl enum_def -> + let is_internal = is_internal_class enum_def.e_path in + if (is_internal) then + (if (debug>1) then print_endline (" internal enum " ^ (join_class_path enum_def.e_path ".") )) + else begin + let meta = Codegen.build_metadata common_ctx object_def in + if (enum_def.e_extern) then + (if (debug>1) then print_endline ("external enum " ^ (join_class_path enum_def.e_path ".") )); + ctx.ctx_class_name <- "*"; + generate_script_enum common_ctx script enum_def meta + end + | TTypeDecl _ | TAbstractDecl _ -> (* already done *) () + ); + ) common_ctx.types; + + (match common_ctx.main with + | None -> script#writeOpLine IaNoMain; + | Some e -> script#writeOpLine IaMain; + script#gen_expression e + ); + + script#write ( (script#op IaResources) ^ (string_of_int (Hashtbl.length common_ctx.resources)) ^ "\n"); + Hashtbl.iter (fun name data -> + script#write ((script#op IaReso) ^ (script#stringText name) ^ (string_of_int (String.length data)) ^ "\n"); + ) common_ctx.resources; + Hashtbl.iter (fun _ data -> script#writeData data) common_ctx.resources; + + script#close +;; + + +(* + The common_ctx contains the haxe AST in the "types" field and the resources +*) +let generate_source common_ctx = + make_base_directory common_ctx.file; + + let debug = 1 in + let exe_classes = ref [] in + let boot_classes = ref [] in + let boot_enums = ref [] in + let nonboot_classes = ref [] in + let init_classes = ref [] in + let file_info = ref PMap.empty in + let class_text path = join_class_path path "::" in + let member_types = create_member_types common_ctx in + let super_deps = create_super_dependencies common_ctx in + let constructor_deps = create_constructor_dependencies common_ctx in + let main_deps = ref [] in + let extern_src = ref [] in + let build_xml = ref "" in + let scriptable = (Common.defined common_ctx Define.Scriptable) in + + List.iter (fun object_def -> + (match object_def with + | TClassDecl class_def when is_extern_class class_def -> + build_xml := !build_xml ^ (get_class_code class_def Meta.BuildXml); + let source = get_meta_string_path class_def.cl_meta Meta.SourceFile in + if (source<>"") then + extern_src := source :: !extern_src; + | TClassDecl class_def -> + let name = class_text class_def.cl_path in + let is_internal = is_internal_class class_def.cl_path in + if (is_internal || (is_macro class_def.cl_meta)) then + ( if (debug>1) then print_endline (" internal class " ^ name )) + else begin + build_xml := !build_xml ^ (get_class_code class_def Meta.BuildXml); + if (has_init_field class_def) then + init_classes := class_def.cl_path :: !init_classes; + if (has_boot_field class_def) then + boot_classes := class_def.cl_path :: !boot_classes + else if not (has_meta_key class_def.cl_meta Meta.NativeGen) then + nonboot_classes := class_def.cl_path :: !nonboot_classes; + let deps = generate_class_files common_ctx member_types super_deps constructor_deps class_def file_info scriptable in - exe_classes := (class_def.cl_path, deps) :: !exe_classes; - end - | TEnumDecl enum_def when enum_def.e_extern -> () - | TEnumDecl enum_def -> - let name = class_text enum_def.e_path in - if (gen_externs) then gen_extern_enum common_ctx enum_def file_info; - let is_internal = is_internal_class enum_def.e_path in - if (is_internal) then - (if debug then print_endline (" internal enum " ^ name )) - else begin - let meta = Codegen.build_metadata common_ctx object_def in - if (enum_def.e_extern) then - (if debug then print_endline ("external enum " ^ name )); - boot_classes := enum_def.e_path :: !boot_classes; - let deps = generate_enum_files common_ctx enum_def super_deps meta file_info in - exe_classes := (enum_def.e_path, deps) :: !exe_classes; - end - | TTypeDecl _ | TAbstractDecl _ -> (* already done *) () - ); - ) common_ctx.types; - - - (match common_ctx.main with - | None -> generate_dummy_main common_ctx - | Some e -> - let main_field = { cf_name = "__main__"; cf_type = t_dynamic; cf_expr = Some e; cf_pos = e.epos; cf_public = true; cf_meta = []; cf_overloads = []; cf_doc = None; cf_kind = Var { v_read = AccNormal; v_write = AccNormal; }; cf_params = [] } in - let class_def = { null_class with cl_path = ([],"@Main"); cl_ordered_statics = [main_field] } in - main_deps := find_referenced_types common_ctx (TClassDecl class_def) super_deps constructor_deps false true false; - generate_main common_ctx member_types super_deps class_def file_info - ); - - generate_boot common_ctx !boot_classes !init_classes; - - generate_files common_ctx file_info; - - write_resources common_ctx; - - - let output_name = match common_ctx.main_class with - | Some path -> (snd path) - | _ -> "output" in - - write_build_data (common_ctx.file ^ "/Build.xml") !exe_classes !main_deps !build_xml output_name; - let cmd_defines = ref "" in - PMap.iter ( fun name value -> match name with - | "true" | "sys" | "dce" | "cpp" | "debug" -> () - | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines; - write_build_options (common_ctx.file ^ "/Options.txt") !cmd_defines; - if ( not (Common.defined common_ctx Define.NoCompilation) ) then begin - let old_dir = Sys.getcwd() in - Sys.chdir common_ctx.file; - let cmd = ref "haxelib run hxcpp Build.xml haxe" in - if (common_ctx.debug) then cmd := !cmd ^ " -Ddebug"; + exe_classes := (class_def.cl_path, deps, object_def) :: !exe_classes; + end + | TEnumDecl enum_def when enum_def.e_extern -> () + | TEnumDecl enum_def -> + let name = class_text enum_def.e_path in + let is_internal = is_internal_class enum_def.e_path in + if (is_internal) then + (if (debug>1) then print_endline (" internal enum " ^ name )) + else begin + let meta = Codegen.build_metadata common_ctx object_def in + if (enum_def.e_extern) then + (if (debug>1) then print_endline ("external enum " ^ name )); + boot_enums := enum_def.e_path :: !boot_enums; + let deps = generate_enum_files common_ctx enum_def super_deps meta file_info in + exe_classes := (enum_def.e_path, deps, object_def) :: !exe_classes; + end + | TTypeDecl _ | TAbstractDecl _ -> (* already done *) () + ); + ) common_ctx.types; + + + (match common_ctx.main with + | None -> generate_dummy_main common_ctx + | Some e -> + let main_field = { cf_name = "__main__"; cf_type = t_dynamic; cf_expr = Some e; cf_pos = e.epos; cf_public = true; cf_meta = []; cf_overloads = []; cf_doc = None; cf_kind = Var { v_read = AccNormal; v_write = AccNormal; }; cf_params = [] } in + let class_def = { null_class with cl_path = ([],"@Main"); cl_ordered_statics = [main_field] } in + main_deps := find_referenced_types common_ctx (TClassDecl class_def) super_deps constructor_deps false true false; + generate_main common_ctx member_types super_deps class_def file_info + ); + + generate_boot common_ctx !boot_enums !boot_classes !nonboot_classes !init_classes; + + generate_files common_ctx file_info; + + write_resources common_ctx; + + (* Output class info if requested *) + if (scriptable || (Common.defined common_ctx Define.DllExport) ) then begin + let filename = + try + let value = Common.defined_value common_ctx Define.DllExport in + if value="1" then raise Not_found; + value + with Not_found -> "export_classes.info" + in + if (filename <> "") then begin + let escape s = + let b = Buffer.create 0 in + for i = 0 to String.length s - 1 do + let c = String.unsafe_get s i in + match c with + | '\\' -> Buffer.add_char b c; Buffer.add_char b c; + | ' ' -> Buffer.add_char b '\\'; Buffer.add_char b 's'; + | '\n' -> Buffer.add_char b '\\'; Buffer.add_char b 'n'; + | _ -> Buffer.add_char b c; + done; + Buffer.contents b; + in + + let exeClasses = open_out filename in + let out = output_string exeClasses in + let outline str = output_string exeClasses (str ^ "\n") in + let spath path = (join_class_path path ".") in + let rec stype = function + | TMono r -> (match !r with None -> "Dynamic" | Some t -> stype t) + | TAbstract ({ a_path = ([],"Void") },[]) -> "void" + | TAbstract ({ a_path = ([],"Bool") },[]) -> "bool" + | TAbstract ({ a_path = ([],"Float") },[]) -> "float" + | TAbstract ({ a_path = ([],"Int") },[]) -> "int" + | TAbstract( { a_path = ([], "EnumValue") }, _ ) -> "Dynamic" + | TEnum (enum,params) -> spath enum.e_path + | TInst (klass,params) -> + (match klass.cl_path, params with + (* Array class *) + (*| ([],"Array") when is_dynamic_array_param (List.hd params) -> "Dynamic" *) + | _,_ when is_dynamic_type_param klass.cl_kind -> "Dynamic" + | ([],"Array"), [t] -> "Array<" ^ (stype t) ^ ">" + | (["haxe";"io"],"Unsigned_char__"),_ -> "uint8" + | ([],"EnumValue"),_ -> "Dynamic" + | ([],"Null"),[t] when cant_be_null t -> "Null<" ^ (stype t) ^ ">" + | ([],"Null"),[t] -> (stype t) + | _ -> spath klass.cl_path + ) + | TType (type_def,params) -> + (match type_def.t_path, params with + | ([],"Null"),[t] when cant_be_null t -> "Null<" ^ (stype t) ^ ">" + | ([],"Array"), [t] -> "Array< " ^ (stype (follow t) ) ^ " >" + | _,_ -> stype (apply_params type_def.t_params params type_def.t_type) + ) + | TLazy func -> stype ((!func)()) + | TAbstract (abs,pl) when abs.a_impl <> None -> + stype (Abstract.get_underlying_type abs pl) + | TAbstract (abs,_) -> spath abs.a_path + | TFun (args,ret) -> "fun<" ^ (List.fold_left (fun s (_,opt,t) -> s ^ (if opt then "?" else "") ^ (stype t) ^ ",") "" args) ^ (stype ret) ^ ">" + | _ -> "Dynamic" + in + List.iter (fun (name,_,def) -> + match def with + | TClassDecl class_def -> + outline ((if class_def.cl_interface then "interface " else "class ") ^ (spath name) ); + (match class_def.cl_super with + | Some (super,_) -> outline ("super " ^ (spath super.cl_path) ) + | _ -> () ); + List.iter ( fun(c,_) -> out ("implements " ^ (spath c.cl_path) ^ "\n") ) class_def.cl_implements; + (match class_def.cl_dynamic with None -> () | Some t -> outline ("implementsdynamic " ^ (stype t))); + (match class_def.cl_array_access with None -> () | Some t -> outline ("arrayaccess " ^ (stype t))); + + let args = function + | TFun (args,_) -> + List.iter (fun (name,opt,t) -> + outline ("arg " ^ name ^ (if opt then " ? " else " : ") ^ (stype t) ) + ) args; + | _ -> () in + let ret = function TFun (_,ret) -> stype ret | _ -> "Dynamic" in + + let print_field stat f = + let pub = if f.cf_public then "pub " else "priv " in + let stat = pub ^ ( if stat then "s " else "m " ) in + (match f.cf_kind, f.cf_name with + | Var { v_read = AccInline; v_write = AccNever },_ -> + outline ("inlinevar " ^ f.cf_name ^ " " ^ (stype f.cf_type) ) + | Var { v_read = AccNormal; v_write = AccNormal },_ -> + outline ("var " ^ stat ^ f.cf_name ^ " " ^ (stype f.cf_type) ) + | Var v,_ -> + let saccess = function | AccNormal -> "v" | AccNo -> "0" | AccNever -> "!" + | AccResolve -> "r" | AccCall -> "c" | AccInline -> "i" | AccRequire (_,_) -> "v" in + outline ("property " ^ stat ^ (saccess v.v_read) ^ " " ^ (saccess v.v_write) + ^ " " ^ f.cf_name ^ " " ^ (stype f.cf_type) ) + | Method _, "new" -> + outline ("function " ^ stat ^ "new " ^ (ret f.cf_type) ); + args f.cf_type + | Method MethDynamic, _ -> + outline ("dynamicfunction " ^ stat ^ f.cf_name ^ " " ^ (ret f.cf_type) ); + args f.cf_type + | Method _, _ -> + outline ("function " ^ stat ^ f.cf_name ^ " " ^ (ret f.cf_type) ); + args f.cf_type + ) in + (match class_def.cl_constructor with | None -> () | Some f -> print_field false f); + List.iter (print_field false) class_def.cl_ordered_fields; + List.iter (print_field true) class_def.cl_ordered_statics; + | TEnumDecl enum_def -> + out ("enum " ^ (spath name) ^ "\n"); + let sorted_items = List.sort (fun f1 f2 -> (f1.ef_index - f2.ef_index ) ) (pmap_values enum_def.e_constrs) in + List.iter (fun constructor -> + outline ("constructor " ^ constructor.ef_name); + match constructor.ef_type with + | TFun (args,_) -> List.iter (fun (arg,_,t) -> outline ("eparam " ^ arg ^ " " ^ (stype t) ) ) args; + | _ -> () + ) sorted_items; + | _ -> () + ) !exe_classes; + + (* Output file info too *) + List.iter ( fun file -> + let full_path = Common.get_full_path (try Common.find_file common_ctx file with Not_found -> file) in + out ("file " ^ (escape file) ^ " " ^ (escape full_path) ^"\n") ) + ( List.sort String.compare ( pmap_keys !file_info) ); + close_out exeClasses; + end; + end; + + let output_name = match common_ctx.main_class with + | Some path -> (snd path) + | _ -> "output" in + + write_build_data common_ctx (common_ctx.file ^ "/Build.xml") !exe_classes !main_deps (!boot_enums@ !boot_classes) !build_xml !extern_src output_name; + let cmd_defines = ref "" in + PMap.iter ( fun name value -> match name with + | "true" | "sys" | "dce" | "cpp" | "debug" -> () + | _ -> cmd_defines := !cmd_defines ^ " -D" ^ name ^ "=\"" ^ (escape_command value) ^ "\"" ) common_ctx.defines; + write_build_options common_ctx (common_ctx.file ^ "/Options.txt") common_ctx.defines; + if ( not (Common.defined common_ctx Define.NoCompilation) ) then begin + let old_dir = Sys.getcwd() in + Sys.chdir common_ctx.file; + let cmd = ref "haxelib run hxcpp Build.xml haxe" in + if (common_ctx.debug) then cmd := !cmd ^ " -Ddebug"; cmd := !cmd ^ !cmd_defines; + cmd := List.fold_left (fun cmd path -> cmd ^ " -I\"" ^ (escape_command path) ^ "\"" ) !cmd common_ctx.class_path; print_endline !cmd; - if common_ctx.run_command !cmd <> 0 then failwith "Build failed"; - Sys.chdir old_dir; - end - ;; + if common_ctx.run_command !cmd <> 0 then failwith "Build failed"; + Sys.chdir old_dir; + end + ;; +let generate common_ctx = + if (Common.defined common_ctx Define.Cppia) then + generate_cppia common_ctx + else + generate_source common_ctx +;; diff --git a/gencs.ml b/gencs.ml index 6f239446b0145c828c3ea545cff7736a1a693e0c..4d51e792d6b722d809a8029f54e37637dc1d6846 100644 --- a/gencs.ml +++ b/gencs.ml @@ -23,69 +23,78 @@ open Gencommon.ReflectionCFs open Ast open Common +open Type open Gencommon open Gencommon.SourceWriter -open Type open Printf open Option - -let is_cs_basic_type t = - match follow t with - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | TInst( { cl_path = ([], "Int") }, [] ) - | TAbstract ({ a_path = ([], "Int") },[]) - | TInst( { cl_path = ([], "Float") }, [] ) - | TAbstract ({ a_path = ([], "Float") },[]) - | TEnum( { e_path = ([], "Bool") }, [] ) - | TAbstract ({ a_path = ([], "Bool") },[]) -> - true - | TAbstract _ when like_float t -> - true - | TEnum(e, _) when not (Meta.has Meta.Class e.e_meta) -> true - | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true - | _ -> false +open ExtString + +let netname_to_hx name = + let len = String.length name in + let chr = String.get name 0 in + String.make 1 (Char.uppercase chr) ^ (String.sub name 1 (len-1)) + +let rec is_cs_basic_type t = + match follow t with + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) + | TAbstract ({ a_path = (["cs"], "Int64") },[]) + | TAbstract ({ a_path = (["cs"], "UInt64") },[]) + | TAbstract ({ a_path = ([], "Int") },[]) + | TAbstract ({ a_path = ([], "Float") },[]) + | TAbstract ({ a_path = ([], "Bool") },[]) -> + true + | TAbstract ({ a_path = (["cs"], "Pointer") },_) -> + false + | TAbstract _ when like_float t -> + true + | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> + is_cs_basic_type (Abstract.get_underlying_type a pl) + | TEnum(e, _) when not (Meta.has Meta.Class e.e_meta) -> true + | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true + | _ -> false (* see http://msdn.microsoft.com/en-us/library/2sk3x8a7(v=vs.71).aspx *) let cs_binops = - [Ast.OpAdd, "op_Addition"; - Ast.OpSub, "op_Subtraction"; - Ast.OpMult, "op_Multiply"; - Ast.OpDiv, "op_Division"; - Ast.OpMod, "op_Modulus"; - Ast.OpXor, "op_ExclusiveOr"; - Ast.OpOr, "op_BitwiseOr"; - Ast.OpAnd, "op_BitwiseAnd"; - Ast.OpBoolAnd, "op_LogicalAnd"; - Ast.OpBoolOr, "op_LogicalOr"; - Ast.OpAssign, "op_Assign"; - Ast.OpShl, "op_LeftShift"; - Ast.OpShr, "op_RightShift"; - Ast.OpShr, "op_SignedRightShift"; - Ast.OpUShr, "op_UnsignedRightShift"; - Ast.OpEq, "op_Equality"; - Ast.OpGt, "op_GreaterThan"; - Ast.OpLt, "op_LessThan"; - Ast.OpNotEq, "op_Inequality"; - Ast.OpGte, "op_GreaterThanOrEqual"; - Ast.OpLte, "op_LessThanOrEqual"; - Ast.OpAssignOp Ast.OpMult, "op_MultiplicationAssignment"; - Ast.OpAssignOp Ast.OpSub, "op_SubtractionAssignment"; - Ast.OpAssignOp Ast.OpXor, "op_ExclusiveOrAssignment"; - Ast.OpAssignOp Ast.OpShl, "op_LeftShiftAssignment"; - Ast.OpAssignOp Ast.OpMod, "op_ModulusAssignment"; - Ast.OpAssignOp Ast.OpAdd, "op_AdditionAssignment"; - Ast.OpAssignOp Ast.OpAnd, "op_BitwiseAndAssignment"; - Ast.OpAssignOp Ast.OpOr, "op_BitwiseOrAssignment"; - (* op_Comma *) - Ast.OpAssignOp Ast.OpDiv, "op_DivisionAssignment";] + [Ast.OpAdd, "op_Addition"; + Ast.OpSub, "op_Subtraction"; + Ast.OpMult, "op_Multiply"; + Ast.OpDiv, "op_Division"; + Ast.OpMod, "op_Modulus"; + Ast.OpXor, "op_ExclusiveOr"; + Ast.OpOr, "op_BitwiseOr"; + Ast.OpAnd, "op_BitwiseAnd"; + Ast.OpBoolAnd, "op_LogicalAnd"; + Ast.OpBoolOr, "op_LogicalOr"; + Ast.OpAssign, "op_Assign"; + Ast.OpShl, "op_LeftShift"; + Ast.OpShr, "op_RightShift"; + Ast.OpShr, "op_SignedRightShift"; + Ast.OpUShr, "op_UnsignedRightShift"; + Ast.OpEq, "op_Equality"; + Ast.OpGt, "op_GreaterThan"; + Ast.OpLt, "op_LessThan"; + Ast.OpNotEq, "op_Inequality"; + Ast.OpGte, "op_GreaterThanOrEqual"; + Ast.OpLte, "op_LessThanOrEqual"; + Ast.OpAssignOp Ast.OpMult, "op_MultiplicationAssignment"; + Ast.OpAssignOp Ast.OpSub, "op_SubtractionAssignment"; + Ast.OpAssignOp Ast.OpXor, "op_ExclusiveOrAssignment"; + Ast.OpAssignOp Ast.OpShl, "op_LeftShiftAssignment"; + Ast.OpAssignOp Ast.OpMod, "op_ModulusAssignment"; + Ast.OpAssignOp Ast.OpAdd, "op_AdditionAssignment"; + Ast.OpAssignOp Ast.OpAnd, "op_BitwiseAndAssignment"; + Ast.OpAssignOp Ast.OpOr, "op_BitwiseOrAssignment"; + (* op_Comma *) + Ast.OpAssignOp Ast.OpDiv, "op_DivisionAssignment";] let cs_unops = - [Ast.Decrement, "op_Decrement"; - Ast.Increment, "op_Increment"; - Ast.Not, "op_UnaryNegation"; - Ast.Neg, "op_UnaryMinus"; - Ast.NegBits, "op_OnesComplement"] + [Ast.Decrement, "op_Decrement"; + Ast.Increment, "op_Increment"; + Ast.Neg, "op_UnaryNegation"; + Ast.Not, "op_LogicalNot"; + Ast.NegBits, "op_OnesComplement"] let binops_names = List.fold_left (fun acc (op,n) -> PMap.add n op acc) PMap.empty cs_binops let unops_names = List.fold_left (fun acc (op,n) -> PMap.add n op acc) PMap.empty cs_unops @@ -94,54 +103,88 @@ let get_item = "get_Item" let set_item = "set_Item" let is_tparam t = - match follow t with - | TInst( { cl_kind = KTypeParameter _ }, [] ) -> true - | _ -> false - -let rec is_int_float t = - match follow t with - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | TInst( { cl_path = ([], "Int") }, [] ) - | TAbstract ({ a_path = ([], "Int") },[]) - | TInst( { cl_path = ([], "Float") }, [] ) - | TAbstract ({ a_path = ([], "Float") },[]) -> - true - | TAbstract _ when like_float t -> - true - | TInst( { cl_path = (["haxe"; "lang"], "Null") }, [t] ) -> is_int_float t - | _ -> false + match follow t with + | TInst( { cl_kind = KTypeParameter _ }, [] ) -> true + | _ -> false + +let rec is_int_float gen t = + match follow (gen.greal_type t) with + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TAbstract ({ a_path = ([], "Int") },[]) + | TAbstract ({ a_path = ([], "Float") },[]) -> + true + | TAbstract _ when like_float t && not (like_i64 t) -> + true + | TInst( { cl_path = (["haxe"; "lang"], "Null") }, [t] ) -> is_int_float gen t + | _ -> false + +let is_bool t = + match follow t with + | TAbstract ({ a_path = ([], "Bool") },[]) -> + true + | _ -> false + +let is_exactly_bool gen t = + match gen.gfollow#run_f t with + | TAbstract ({ a_path = ([], "Bool") },[]) -> + true + | _ -> false + +let is_dynamic gen t = + match follow (gen.greal_type t) with + | TDynamic _ -> true + | _ -> false + +let is_pointer gen t = + match follow (gen.greal_type t) with + | TAbstract( ( {a_path = ["cs"], "Pointer"}, _ ) ) + | TInst( {cl_path = ["cs"], "Pointer"}, _ ) -> true + | _ -> false let rec is_null t = - match t with - | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) - | TType( { t_path = ([], "Null") }, _ ) -> true - | TType( t, tl ) -> is_null (apply_params t.t_types tl t.t_type) - | TMono r -> - (match !r with - | Some t -> is_null t - | _ -> false) - | TLazy f -> - is_null (!f()) - | _ -> false + match t with + | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) + | TType( { t_path = ([], "Null") }, _ ) -> true + | TType( t, tl ) -> is_null (apply_params t.t_params tl t.t_type) + | TMono r -> + (match !r with + | Some t -> is_null t + | _ -> false) + | TLazy f -> + is_null (!f()) + | _ -> false + +let rec get_ptr e = match e.eexpr with + | TParenthesis e | TMeta(_,e) + | TCast(e,_) -> get_ptr e + | TCall( { eexpr = TLocal({ v_name = "__ptr__" }) }, [ e ] ) -> + Some e + | _ -> None let parse_explicit_iface = - let regex = Str.regexp "\\." in - let parse_explicit_iface str = - let split = Str.split regex str in - let rec get_iface split pack = - match split with - | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) - | pack_piece :: tl -> get_iface tl (pack_piece :: pack) - | _ -> assert false - in - get_iface split [] - in parse_explicit_iface + let regex = Str.regexp "\\." in + let parse_explicit_iface str = + let split = Str.split regex str in + let rec get_iface split pack = + match split with + | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) + | pack_piece :: tl -> get_iface tl (pack_piece :: pack) + | _ -> assert false + in + get_iface split [] + in parse_explicit_iface let is_string t = - match follow t with - | TInst( { cl_path = ([], "String") }, [] ) -> true - | _ -> false + match follow t with + | TInst( { cl_path = ([], "String") }, [] ) -> true + | _ -> false + +let rec change_md = function + | TAbstractDecl(a) when Meta.has Meta.Delegate a.a_meta && not (Meta.has Meta.CoreType a.a_meta) -> + change_md (t_to_md a.a_this) + | TClassDecl( { cl_kind = KAbstractImpl ({ a_this = TInst(impl,_) } as a) }) when Meta.has Meta.Delegate a.a_meta -> + TClassDecl impl + | md -> md (* ******************************************* *) (* CSharpSpecificESynf *) @@ -149,130 +192,180 @@ let is_string t = (* - Some CSharp-specific syntax filters that must run before ExpressionUnwrap + Some CSharp-specific syntax filters that must run before ExpressionUnwrap - dependencies: - It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions - It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr + dependencies: + It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions + It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr *) module CSharpSpecificESynf = struct - let name = "csharp_specific_e" - - let priority = solve_deps name [DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter TryCatchWrapper.priority] - - let get_cl_from_t t = - match follow t with - | TInst(cl,_) -> cl - | _ -> assert false - - let traverse 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 is_var = alloc_var "__is__" t_dynamic in - - let rec run e = - match e.eexpr with - (* Std.is() *) - | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, - [ 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"}) ) }, - [ obj; { eexpr = TTypeExpr(md) }] - ) -> - let mk_is obj md = - { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [ - obj; - { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos } - ] ) } - in - let obj = run obj in - (match follow_module follow md with - | TClassDecl{ cl_path = ([], "Float") } -> - (* on the special case of seeing if it is a Float, we need to test if both it is a float and if it is an Int *) - let mk_is local = - mk_paren { - eexpr = TBinop(Ast.OpBoolOr, mk_is local md, mk_is local (TClassDecl (get_cl_from_t basic.tint))); - etype = basic.tbool; - epos = e.epos - } - in - - let ret = match obj.eexpr with - | TLocal(v) -> mk_is obj - | _ -> - let var = mk_temp gen "is" obj.etype in - let added = { obj with eexpr = TVars([var, Some(obj)]); etype = basic.tvoid } in - let local = mk_local var obj.epos in - { - eexpr = TBlock([ added; mk_is local ]); - etype = basic.tbool; - epos = e.epos - } - in - ret - | TClassDecl{ cl_path = ([], "Int") } -> - { - eexpr = TCall( - mk_static_field_access_infer runtime_cl "isInt" e.epos [], - [ obj ] - ); - etype = basic.tbool; - epos = e.epos - } - | _ -> - mk_is obj md - ) - (* end Std.is() *) - - | TBinop( Ast.OpUShr, e1, e2 ) -> - mk_cast e.etype { e with eexpr = TBinop( Ast.OpShr, mk_cast uint (run e1), run e2 ) } - - | TBinop( Ast.OpAssignOp Ast.OpUShr, e1, e2 ) -> - let mk_ushr local = - { e with eexpr = TBinop(Ast.OpAssign, local, run { e with eexpr = TBinop(Ast.OpUShr, local, run e2) }) } - in - - let mk_local obj = - let var = mk_temp gen "opUshr" obj.etype in - let added = { obj with eexpr = TVars([var, Some(obj)]); etype = basic.tvoid } in - let local = mk_local var obj.epos in - local, added - in - - let e1 = run e1 in - - let ret = match e1.eexpr with - | TField({ eexpr = TLocal _ }, _) - | TField({ eexpr = TTypeExpr _ }, _) - | TArray({ eexpr = TLocal _ }, _) - | TLocal(_) -> - mk_ushr e1 - | TField(fexpr, field) -> - let local, added = mk_local fexpr in - { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TField(local, field) } ]); } - | TArray(ea1, ea2) -> - 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 - in - - ret - - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "csharp_specific_e" + + let priority = solve_deps name [DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter TryCatchWrapper.priority] + + let get_cl_from_t t = + match follow t with + | TInst(cl,_) -> cl + | _ -> assert false + + let get_ab_from_t t = + match follow t with + | TAbstract(ab,_) -> ab + | _ -> assert false + + let traverse 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 is_var = alloc_var "__is__" t_dynamic in + let name () = match gen.gcurrent_class with + | Some cl -> path_s cl.cl_path + | _ -> "" + in + + let rec run e = + match e.eexpr with + (* Std.is() *) + | TCall( + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, + [ 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"}) ) }, + [ obj; { eexpr = TTypeExpr(md) }] + ) -> + let md = change_md md in + let mk_is obj md = + { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [ + obj; + { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos } + ] ) } + in + + let mk_or a b = + { + eexpr = TBinop(Ast.OpBoolOr, a, b); + etype = basic.tbool; + epos = e.epos + } + in + + let wrap_if_needed obj f = + (* introduce temp variable for complex expressions *) + match obj.eexpr with + | TLocal(v) -> f obj + | _ -> + let var = mk_temp gen "is" obj.etype in + let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in + let local = mk_local var obj.epos in + { + eexpr = TBlock([ added; f local ]); + etype = basic.tbool; + epos = e.epos + } + in + + let obj = run obj in + (match follow_module follow md with + | TAbstractDecl{ a_path = ([], "Float") } when name() <> "haxe.lang.Runtime" -> + (* on the special case of seeing if it is a Float, we need to test if both it is a float and if it is an Int *) + let mk_is local = + (* we check if it float or int or uint *) + let eisint = mk_is local (TAbstractDecl (get_ab_from_t basic.tint)) in + let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in + let eisfloat = mk_is local md in + mk_paren (mk_or eisfloat (mk_or eisint eisuint)) + in + wrap_if_needed obj mk_is + + | TAbstractDecl{ a_path = ([], "Int") } when name() <> "haxe.lang.Runtime" -> + (* int can be stored in double variable because of anonymous functions, check that case *) + let mk_isint_call local = + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "isInt" e.epos [], + [ local ] + ); + etype = basic.tbool; + epos = e.epos + } + in + let mk_is local = + let eisint = mk_is local (TAbstractDecl (get_ab_from_t basic.tint)) in + let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in + mk_paren (mk_or (mk_or eisint eisuint) (mk_isint_call local)) + in + wrap_if_needed obj mk_is + + | TAbstractDecl{ a_path = ([], "UInt") } when name() <> "haxe.lang.Runtime" -> + (* uint can be stored in double variable because of anonymous functions, check that case *) + let mk_isuint_call local = + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "isUInt" e.epos [], + [ local ] + ); + etype = basic.tbool; + epos = e.epos + } + in + let mk_is local = + let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in + mk_paren (mk_or eisuint (mk_isuint_call local)) + in + wrap_if_needed obj mk_is + + | _ -> + mk_is obj md + ) + (* end Std.is() *) + + | TBinop( Ast.OpUShr, e1, e2 ) -> + mk_cast e.etype { e with eexpr = TBinop( Ast.OpShr, mk_cast uint (run e1), run e2 ) } + + | TBinop( Ast.OpAssignOp Ast.OpUShr, e1, e2 ) -> + let mk_ushr local = + { e with eexpr = TBinop(Ast.OpAssign, local, run { e with eexpr = TBinop(Ast.OpUShr, local, run e2) }) } + in + + let mk_local obj = + let var = mk_temp gen "opUshr" obj.etype in + let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in + let local = mk_local var obj.epos in + local, added + in + + let e1 = run e1 in + + let ret = match e1.eexpr with + | TField({ eexpr = TLocal _ }, _) + | TField({ eexpr = TTypeExpr _ }, _) + | TArray({ eexpr = TLocal _ }, _) + | TLocal(_) -> + mk_ushr e1 + | TField(fexpr, field) -> + let local, added = mk_local fexpr in + { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TField(local, field) } ]); } + | TArray(ea1, ea2) -> + 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 + in + + ret + + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; @@ -282,241 +375,304 @@ end;; (* - Some CSharp-specific syntax filters that can run after ExprUnwrap + Some CSharp-specific syntax filters that can run after ExprUnwrap - dependencies: - Runs after ExprUnwrap + dependencies: + Runs after ExprUnwrap *) module CSharpSpecificSynf = struct - let name = "csharp_specific" - - let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DAfter HardNullableSynf.priority ] - - let get_cl_from_t t = - match follow t with - | TInst(cl,_) -> cl - | _ -> assert false - - let is_tparam t = - match follow t with - | TInst( { cl_kind = KTypeParameter _ }, _ ) -> true - | _ -> false - - let traverse gen runtime_cl = - let basic = gen.gcon.basic in - let tchar = match ( get_type gen (["cs"], "Char16") ) with | TTypeDecl t -> t | _ -> assert false in - let tchar = TType(tchar,[]) in - let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in - - let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in - - let clstring = match basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in - - let is_struct t = (* not basic type *) - match follow t with - | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true - | _ -> false - in - - let is_cl t = match gen.greal_type t with | TInst ( { cl_path = (["System"], "Type") }, [] ) -> true | _ -> false in - - let rec run e = - match e.eexpr with - - (* Std.int() *) - | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" }) ) }, - [obj] - ) -> - run (mk_cast basic.tint obj) - (* end Std.int() *) - - (* TODO: change cf_name *) - | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "length" })) -> - { e with eexpr = TField(run ef, FDynamic "Length") } - | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "toLowerCase" })) -> - { e with eexpr = TField(run ef, FDynamic "ToLower") } - | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "toUpperCase" })) -> - { e with eexpr = TField(run ef, FDynamic "ToUpper") } - - | TCall( { eexpr = TField(_, FStatic({ cl_path = [], "String" }, { cf_name = "fromCharCode" })) }, [cc] ) -> - { e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); mk_int gen 1 cc.epos]) } - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("charAt" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("charCodeAt" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("indexOf" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("lastIndexOf" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("split" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("substring" as field) })) }, args ) - | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("substr" as field) })) }, args ) -> - { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) } - | TNew( { cl_path = ([], "String") }, [], [p] ) -> run p (* new String(myString) -> myString *) - - | TCast(expr, _) when is_int_float e.etype && not (is_int_float expr.etype) && not (is_null e.etype) -> - let needs_cast = match gen.gfollow#run_f e.etype with - | TInst _ -> false - | _ -> true - in - - let fun_name = if like_int e.etype then "toInt" else "toDouble" in - - let ret = { - eexpr = TCall( - mk_static_field_access_infer runtime_cl fun_name expr.epos [], - [ run expr ] - ); - etype = basic.tint; - epos = expr.epos - } in - - if needs_cast then mk_cast e.etype ret else ret - | TCast(expr, _) when is_string e.etype -> - { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) } - | TBinop( (Ast.OpNotEq as op), e1, e2) - | TBinop( (Ast.OpEq as op), e1, e2) when is_string e1.etype || is_string e2.etype -> - let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in - mk_ret { e with - eexpr = TCall({ - eexpr = TField(mk_classtype_access clstring e.epos, FDynamic "Equals"); - etype = TFun(["obj1",false,basic.tstring; "obj2",false,basic.tstring], basic.tbool); - epos = e1.epos - }, [ run e1; run e2 ]) - } - - | TCast(expr, _) when is_tparam e.etype -> - let static = mk_static_field_access_infer (runtime_cl) "genericCast" e.epos [e.etype] in - { e with eexpr = TCall(static, [mk_local (alloc_var "$type_param" e.etype) expr.epos; run expr]); } - - | TBinop( (Ast.OpNotEq as op), e1, e2) - | TBinop( (Ast.OpEq as op), e1, e2) when is_struct e1.etype || is_struct e2.etype -> - let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in - mk_ret { e with - eexpr = TCall({ - eexpr = TField(run e1, FDynamic "Equals"); - etype = TFun(["obj1",false,t_dynamic;], basic.tbool); - epos = e1.epos - }, [ run e2 ]) - } - - | TBinop ( (Ast.OpEq as op), e1, e2 ) - | TBinop ( (Ast.OpNotEq as op), e1, e2 ) when is_cl e1.etype -> - let static = mk_static_field_access_infer (runtime_cl) "typeEq" e.epos [] in - let ret = { e with eexpr = TCall(static, [run e1; run e2]); } in - if op = Ast.OpNotEq then - { ret with eexpr = TUnop(Ast.Not, Ast.Prefix, ret) } - else - ret - - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "csharp_specific" + + let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DAfter HardNullableSynf.priority ] + + let get_cl_from_t t = + match follow t with + | TInst(cl,_) -> cl + | _ -> assert false + + let is_tparam t = + match follow t with + | TInst( { cl_kind = KTypeParameter _ }, _ ) -> true + | _ -> false + + let traverse gen runtime_cl = + let basic = gen.gcon.basic in + let tchar = match ( get_type gen (["cs"], "Char16") ) with + | TTypeDecl t -> TType(t,[]) + | TAbstractDecl a -> TAbstract(a,[]) + | _ -> assert false + in + let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in + let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in + let clstring = match basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in + let ti64 = match ( get_type gen (["cs"], "Int64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in + let boxed_ptr = + if Common.defined gen.gcon Define.Unsafe then + get_cl (get_type gen (["haxe";"lang"], "BoxedPointer")) + (* get_abstract (get_type gen (["cs"],"Pointer")) *) + else + null_class + in + + let is_struct t = (* not basic type *) + match follow t with + | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true + | _ -> false + in + + let is_cl t = match gen.greal_type t with | TInst ( { cl_path = (["System"], "Type") }, [] ) -> true | _ -> false in + let name () = match gen.gcurrent_class with + | Some cl -> path_s cl.cl_path + | _ -> "" + in + + let rec run e = + match e.eexpr with + + (* Std.int() *) + | TCall( + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" }) ) }, + [obj] + ) -> + run (mk_cast basic.tint obj) + (* end Std.int() *) + + (* TODO: change cf_name *) + | TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = "length" })) -> + { e with eexpr = TField(run ef, FDynamic "Length") } + | TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = "toLowerCase" })) -> + { e with eexpr = TField(run ef, FDynamic "ToLowerInvariant") } + | TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = "toUpperCase" })) -> + { e with eexpr = TField(run ef, FDynamic "ToUpperInvariant") } + + | TCall( { eexpr = TField(_, FStatic({ cl_path = [], "String" }, { cf_name = "fromCharCode" })) }, [cc] ) -> + { e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); mk_int gen 1 cc.epos]) } + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charAt" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("charCodeAt" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("indexOf" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("lastIndexOf" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("split" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("substring" as field) })) }, args ) + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("substr" as field) })) }, args ) -> + { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) } + | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, { cf_name = ("toString") })) }, [] ) -> + run ef + | TNew( { cl_path = ([], "String") }, [], [p] ) -> run p (* new String(myString) -> myString *) + + | TCast(expr, _) when like_float expr.etype && is_pointer gen e.etype -> + let expr = run expr in + mk_cast e.etype (mk_cast ti64 expr) + | TCast(expr, _) when is_dynamic gen expr.etype && is_pointer gen e.etype -> + (match get_ptr expr with + | None -> + (* unboxing *) + let expr = run expr in + mk_cast e.etype (mk_field_access gen (mk_cast (TInst(boxed_ptr,[])) expr) "value" e.epos) + | Some e -> + run e) + | TCast(expr, _) when is_pointer gen expr.etype && is_dynamic gen e.etype -> + (match get_ptr expr with + | None -> + (* boxing *) + let expr = run expr in + { e with eexpr = TNew(boxed_ptr,[],[expr]) } + | Some e -> + run e) + | TCast(expr, _) when is_bool e.etype && not (is_exactly_bool gen expr.etype) -> + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "toBool" expr.epos [], + [ run expr ] + ); + etype = basic.tbool; + epos = e.epos + } + | TCast(expr, _) when is_int_float gen e.etype && not (is_cs_basic_type (gen.greal_type expr.etype)) && ( Common.defined gen.gcon Define.EraseGenerics || not (is_null e.etype) ) && name() <> "haxe.lang.Runtime" -> + let needs_cast = match gen.gfollow#run_f e.etype with + | TInst _ -> false + | _ -> true + in + + let fun_name = if like_int e.etype then "toInt" else "toDouble" in + + let ret = { + eexpr = TCall( + mk_static_field_access_infer runtime_cl fun_name expr.epos [], + [ run expr ] + ); + etype = basic.tint; + epos = expr.epos + } in + + if needs_cast then mk_cast e.etype ret else ret + | TCast(expr, _) when (is_string e.etype) && (not (is_string expr.etype)) && name() <> "haxe.lang.Runtime" -> + { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) } + | TBinop( (Ast.OpNotEq as op), e1, e2) + | TBinop( (Ast.OpEq as op), e1, e2) when is_string e1.etype || is_string e2.etype -> + let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in + mk_ret { e with + eexpr = TCall({ + eexpr = TField(mk_classtype_access clstring e.epos, FDynamic "Equals"); + etype = TFun(["obj1",false,basic.tstring; "obj2",false,basic.tstring], basic.tbool); + epos = e1.epos + }, [ run e1; run e2 ]) + } + + | TCast(expr, _) when is_tparam e.etype && name() <> "haxe.lang.Runtime" && not (Common.defined gen.gcon Define.EraseGenerics) -> + let static = mk_static_field_access_infer (runtime_cl) "genericCast" e.epos [e.etype] in + { e with eexpr = TCall(static, [mk_local (alloc_var "$type_param" e.etype) expr.epos; run expr]); } + + | TBinop( (Ast.OpNotEq as op), e1, e2) + | TBinop( (Ast.OpEq as op), e1, e2) when is_struct e1.etype || is_struct e2.etype -> + let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in + mk_ret { e with + eexpr = TCall({ + eexpr = TField(run e1, FDynamic "Equals"); + etype = TFun(["obj1",false,t_dynamic;], basic.tbool); + epos = e1.epos + }, [ run e2 ]) + } + + | TBinop ( (Ast.OpEq as op), e1, e2 ) + | TBinop ( (Ast.OpNotEq as op), e1, e2 ) when is_cl e1.etype && name() <> "haxe.lang.Runtime" -> + let static = mk_static_field_access_infer (runtime_cl) "typeEq" e.epos [] in + let ret = { e with eexpr = TCall(static, [run e1; run e2]); } in + if op = Ast.OpNotEq then + { ret with eexpr = TUnop(Ast.Not, Ast.Prefix, ret) } + else + ret + + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; +let add_cast_handler gen = + let basic = gen.gcon.basic in + (* + starting to set gtparam_cast. + *) + + (* NativeArray: the most important. *) + + (* + var new_arr = new NativeArray(old_arr.Length); + var i = -1; + while( i < old_arr.Length ) + { + new_arr[i] = (TO_T) old_arr[i]; + } + *) + + let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in + + let get_narr_param t = match follow t with + | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> param + | _ -> assert false + in + + let gtparam_cast_native_array e to_t = + let old_param = get_narr_param e.etype in + let new_param = get_narr_param to_t in + + let new_v = mk_temp gen "new_arr" to_t in + let i = mk_temp gen "i" basic.tint in + let old_len = mk_field_access gen e "Length" e.epos in + let obj_v = mk_temp gen "obj" t_dynamic in + let check_null = {eexpr = TBinop(Ast.OpNotEq, e, null e.etype e.epos); etype = basic.tbool; epos = e.epos} in + let block = [ + { + eexpr = TVar( + new_v, Some( { + eexpr = TNew(native_arr_cl, [new_param], [old_len] ); + etype = to_t; + epos = e.epos + } ) + ); + etype = basic.tvoid; + epos = e.epos + }; + { + eexpr = TVar(i, Some( mk_int gen (-1) e.epos )); + etype = basic.tvoid; + epos = e.epos + }; + { + eexpr = TWhile( + { + eexpr = TBinop( + Ast.OpLt, + { eexpr = TUnop(Ast.Increment, Ast.Prefix, mk_local i e.epos); etype = basic.tint; epos = e.epos }, + old_len + ); + etype = basic.tbool; + epos = e.epos + }, + { eexpr = TBlock [ + { + eexpr = TVar(obj_v, Some (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos })); + etype = basic.tvoid; + epos = e.epos + }; + { + eexpr = TIf({ + eexpr = TBinop(Ast.OpNotEq, mk_local obj_v e.epos, null e.etype e.epos); + etype = basic.tbool; + epos = e.epos + }, + { + eexpr = TBinop( + Ast.OpAssign, + { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos }, + mk_cast new_param (mk_local obj_v e.epos) + ); + etype = new_param; + epos = e.epos + }, + None); + etype = basic.tvoid; + epos = e.epos + } + ]; etype = basic.tvoid; epos = e.epos }, + Ast.NormalWhile + ); + etype = basic.tvoid; + epos = e.epos; + }; + mk_local new_v e.epos + ] in + { + eexpr = TIf( + check_null, + { + eexpr = TBlock(block); + etype = to_t; + epos = e.epos; + }, + Some(null new_v.v_type e.epos) + ); + etype = to_t; + epos = e.epos; + } + in + + Hashtbl.add gen.gtparam_cast (["cs"], "NativeArray") gtparam_cast_native_array + (* end set gtparam_cast *) + + (* Type Parameters Handling *) let handle_type_params gen ifaces base_generic = - let basic = gen.gcon.basic in - (* - starting to set gtparam_cast. - *) - - (* NativeArray: the most important. *) - - (* - var new_arr = new NativeArray(old_arr.Length); - var i = -1; - while( i < old_arr.Length ) - { - new_arr[i] = (TO_T) old_arr[i]; - } - *) - - let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in - - let get_narr_param t = match follow t with - | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> param - | _ -> assert false - in - - let gtparam_cast_native_array e to_t = - let old_param = get_narr_param e.etype in - let new_param = get_narr_param to_t in - - let new_v = mk_temp gen "new_arr" to_t in - let i = mk_temp gen "i" basic.tint in - let old_len = mk_field_access gen e "Length" e.epos in - let obj_v = mk_temp gen "obj" t_dynamic in - let block = [ - { - eexpr = TVars( - [ - new_v, Some( { - eexpr = TNew(native_arr_cl, [new_param], [old_len] ); - etype = to_t; - epos = e.epos - } ); - i, Some( mk_int gen (-1) e.epos ) - ]); - etype = basic.tvoid; - epos = e.epos }; - { - eexpr = TWhile( - { - eexpr = TBinop( - Ast.OpLt, - { eexpr = TUnop(Ast.Increment, Ast.Prefix, mk_local i e.epos); etype = basic.tint; epos = e.epos }, - old_len - ); - etype = basic.tbool; - epos = e.epos - }, - { eexpr = TBlock [ - { - eexpr = TVars([obj_v, Some (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos })]); - etype = basic.tvoid; - epos = e.epos - }; - { - eexpr = TIf({ - eexpr = TBinop(Ast.OpNotEq, mk_local obj_v e.epos, null e.etype e.epos); - etype = basic.tbool; - epos = e.epos - }, - { - eexpr = TBinop( - Ast.OpAssign, - { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos }, - mk_cast new_param (mk_local obj_v e.epos) - ); - etype = new_param; - epos = e.epos - }, - None); - etype = basic.tvoid; - epos = e.epos - } - ]; etype = basic.tvoid; epos = e.epos }, - Ast.NormalWhile - ); - etype = basic.tvoid; - epos = e.epos; - }; - mk_local new_v e.epos - ] in - { eexpr = TBlock(block); etype = to_t; epos = e.epos } - in - - Hashtbl.add gen.gtparam_cast (["cs"], "NativeArray") gtparam_cast_native_array; - (* end set gtparam_cast *) - - TypeParams.RealTypeParams.default_config gen (fun e t -> gen.gcon.warning ("Cannot cast to " ^ (debug_type t)) e.epos; mk_cast t e) ifaces base_generic + add_cast_handler gen; + TypeParams.RealTypeParams.default_config gen (fun e t -> gen.gcon.warning ("Cannot cast to " ^ (debug_type t)) e.epos; mk_cast t e) ifaces base_generic let connecting_string = "?" (* ? see list here http://www.fileformat.info/info/unicode/category/index.htm and here for C# http://msdn.microsoft.com/en-us/library/aa664670.aspx *) let default_package = "cs" (* I'm having this separated as I'm still not happy with having a cs package. Maybe dotnet would be better? *) @@ -524,1826 +680,3887 @@ let strict_mode = ref false (* strict mode is so we can check for unexpected inf (* reserved c# words *) let reserved = let res = Hashtbl.create 120 in - List.iter (fun lst -> Hashtbl.add res lst ("@" ^ lst)) ["abstract"; "as"; "base"; "bool"; "break"; "byte"; "case"; "catch"; "char"; "checked"; "class"; - "const"; "continue"; "decimal"; "default"; "delegate"; "do"; "double"; "else"; "enum"; "event"; "explicit"; - "extern"; "false"; "finally"; "fixed"; "float"; "for"; "foreach"; "goto"; "if"; "implicit"; "in"; "int"; - "interface"; "internal"; "is"; "lock"; "long"; "namespace"; "new"; "null"; "object"; "operator"; "out"; "override"; - "params"; "private"; "protected"; "public"; "readonly"; "ref"; "return"; "sbyte"; "sealed"; "short"; "sizeof"; - "stackalloc"; "static"; "string"; "struct"; "switch"; "this"; "throw"; "true"; "try"; "typeof"; "uint"; "ulong"; - "unchecked"; "unsafe"; "ushort"; "using"; "virtual"; "volatile"; "void"; "while"; "add"; "ascending"; "by"; "descending"; - "dynamic"; "equals"; "from"; "get"; "global"; "group"; "into"; "join"; "let"; "on"; "orderby"; "partial"; - "remove"; "select"; "set"; "value"; "var"; "where"; "yield"]; - res + List.iter (fun lst -> Hashtbl.add res lst ("@" ^ lst)) ["abstract"; "as"; "base"; "bool"; "break"; "byte"; "case"; "catch"; "char"; "checked"; "class"; + "const"; "continue"; "decimal"; "default"; "delegate"; "do"; "double"; "else"; "enum"; "event"; "explicit"; + "extern"; "false"; "finally"; "fixed"; "float"; "for"; "foreach"; "goto"; "if"; "implicit"; "in"; "int"; + "interface"; "internal"; "is"; "lock"; "long"; "namespace"; "new"; "null"; "object"; "operator"; "out"; "override"; + "params"; "private"; "protected"; "public"; "readonly"; "ref"; "return"; "sbyte"; "sealed"; "short"; "sizeof"; + "stackalloc"; "static"; "string"; "struct"; "switch"; "this"; "throw"; "true"; "try"; "typeof"; "uint"; "ulong"; + "unchecked"; "unsafe"; "ushort"; "using"; "virtual"; "volatile"; "void"; "while"; "add"; "ascending"; "by"; "descending"; + "dynamic"; "equals"; "from"; "get"; "global"; "group"; "into"; "join"; "let"; "on"; "orderby"; "partial"; + "remove"; "select"; "set"; "value"; "var"; "where"; "yield"]; + res let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } ) let rec get_class_modifiers meta cl_type cl_access cl_modifiers = - match meta with - | [] -> cl_type,cl_access,cl_modifiers - | (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers - | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers - | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "internal" cl_modifiers - (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) - | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *) - | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers) - | (Meta.Unsafe,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("unsafe" :: cl_modifiers) - | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers + match meta with + | [] -> cl_type,cl_access,cl_modifiers + | (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers + | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers + | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "internal" cl_modifiers + (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) + | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *) + | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers) + | (Meta.Unsafe,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("unsafe" :: cl_modifiers) + | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers let rec get_fun_modifiers meta access modifiers = - match meta with - | [] -> access,modifiers - | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers - | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "internal" modifiers - | (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers) - | (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers) - | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers) - | _ :: meta -> get_fun_modifiers meta access modifiers + match meta with + | [] -> access,modifiers + | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers + | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "internal" modifiers + | (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers) + | (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers) + | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers) + | (Meta.Custom ("?prop_impl" | "?event_impl"),[],_) :: meta -> get_fun_modifiers meta "private" modifiers + | _ :: meta -> get_fun_modifiers meta access modifiers (* this was the way I found to pass the generator context to be accessible across all functions here *) (* so 'configure' is almost 'top-level' and will have all functions needed to make this work *) let configure gen = - let basic = gen.gcon.basic in - - let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in - - let null_t = (get_cl (get_type gen (["haxe";"lang"],"Null")) ) in - - let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in - - let no_root = Common.defined gen.gcon Define.NoRoot in - - let change_clname n = n in - - let change_id name = try Hashtbl.find reserved name with | Not_found -> name in - - let change_ns md = if no_root then - function - | [] when is_hxgen md -> ["haxe";"root"] - | ns -> List.map change_id ns - else List.map change_id in - - let change_field = change_id in - - let write_id w name = write w (change_id name) in - - let write_field w name = write w (change_field name) in - - gen.gfollow#add ~name:"follow_basic" (fun t -> match t with - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) - | TEnum ({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) - | TType ({ t_path = [],"UInt" },[]) - | TAbstract ({ a_path = [],"UInt" },[]) - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeUInt64" },[]) - | TType ({ t_path = ["cs"],"UInt64" },[]) - | TAbstract ({ a_path = ["cs"],"UInt64" },[]) - | TType ({ t_path = ["cs"],"UInt8" },[]) - | TAbstract ({ a_path = ["cs"],"UInt8" },[]) - | TType ({ t_path = ["cs"],"Int8" },[]) - | TAbstract ({ a_path = ["cs"],"Int8" },[]) - | TType ({ t_path = ["cs"],"Int16" },[]) - | TAbstract ({ a_path = ["cs"],"Int16" },[]) - | TType ({ t_path = ["cs"],"UInt16" },[]) - | TAbstract ({ a_path = ["cs"],"UInt16" },[]) - | TType ({ t_path = ["cs"],"Char16" },[]) - | TAbstract ({ a_path = ["cs"],"Char16" },[]) - | TType ({ t_path = ["cs"],"Ref" },_) - | TAbstract ({ a_path = ["cs"],"Ref" },_) - | TType ({ t_path = ["cs"],"Out" },_) - | TAbstract ({ a_path = ["cs"],"Out" },_) - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) -> Some t - | TType ({ t_path = [],"Null" },[_]) -> Some t - | TAbstract ({ a_impl = Some _ } as a, pl) -> - Some (gen.gfollow#run_f ( Codegen.Abstract.get_underlying_type a pl) ) - | TAbstract( { a_path = ([], "EnumValue") }, _ ) - | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic - | _ -> None); - - let module_s md = - let path = (t_infos md).mt_path in - match path with - | ([], "String") -> "string" - | ([], "Null") -> path_s (change_ns md ["haxe"; "lang"], change_clname "Null") - | (ns,clname) -> path_s (change_ns md ns, change_clname clname) - in - - let ifaces = Hashtbl.create 1 in - - let ti64 = match ( get_type gen (["haxe";"_Int64"], "NativeInt64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in - - let ttype = get_cl ( get_type gen (["System"], "Type") ) in - - let has_tdyn tl = - List.exists (fun t -> match follow t with - | TDynamic _ | TMono _ -> true - | _ -> false - ) tl - in - - let rec real_type t = - let t = gen.gfollow#run_f t in - let ret = match t with - | TAbstract ({ a_impl = Some _ } as a, pl) -> - real_type (Codegen.Abstract.get_underlying_type a pl) - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64 - | TAbstract( { a_path = [],"Class" }, _ ) - | TAbstract( { a_path = [],"Enum" }, _ ) - | TInst( { cl_path = ([], "Class") }, _ ) - | TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[]) - | TEnum(_, []) - | TInst(_, []) -> t - | TInst(cl, params) when - has_tdyn params && - Hashtbl.mem ifaces cl.cl_path -> - TInst(Hashtbl.find ifaces cl.cl_path, []) - | TEnum(e, params) -> - TEnum(e, List.map (fun _ -> t_dynamic) params) - | TInst(cl, params) when Meta.has Meta.Enum cl.cl_meta -> - TInst(cl, List.map (fun _ -> t_dynamic) params) - | TInst(cl, params) -> TInst(cl, change_param_type (TClassDecl cl) params) - | TType({ t_path = ([], "Null") }, [t]) -> - (* - Null<> handling is a little tricky. - It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter - It works on cases such as Hash returning Null since cast_detect will invoke real_type at the original type, - Null, which will then return the type haxe.lang.Null<> - *) - (match real_type t with - | TInst( { cl_kind = KTypeParameter _ }, _ ) -> TInst(null_t, [t]) - | _ when is_cs_basic_type t -> TInst(null_t, [t]) - | _ -> real_type t) - | TAbstract _ - | TType _ -> t - | TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ | AbstractStatics _ -> true | _ -> false) -> t - | TFun _ -> TInst(fn_cl,[]) - | _ -> t_dynamic - in - ret - and - - (* - On hxcs, the only type parameters allowed to be declared are the basic c# types. - That's made like this to avoid casting problems when type parameters in this case - add nothing to performance, since the memory layout is always the same. - - To avoid confusion between Generic (which has a different meaning in hxcs AST), - all those references are using dynamic_anon, which means Generic<{}> - *) - change_param_type md tl = - let is_hxgeneric = (TypeParams.RealTypeParams.is_hxgeneric md) in - let ret t = match is_hxgeneric, real_type t with - | false, _ -> t - (* - Because Null<> types need a special compiler treatment for many operations (e.g. boxing/unboxing), - Null<> type parameters will be transformed into Dynamic. - *) - | true, TInst ( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> dynamic_anon - | true, TInst ( { cl_kind = KTypeParameter _ }, _ ) -> t - | true, TInst _ - | true, TEnum _ - | true, TAbstract _ when is_cs_basic_type t -> t - | true, TDynamic _ -> t - | true, _ -> dynamic_anon - in - if is_hxgeneric && List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) tl then - List.map (fun _ -> t_dynamic) tl - else - List.map ret tl - in - - let is_dynamic t = match real_type t with - | TMono _ | TDynamic _ -> true - | TAnon anon -> - (match !(anon.a_status) with - | EnumStatics _ | Statics _ -> false - | _ -> true - ) - | _ -> false - in - - let rec t_s t = - match real_type t with - (* basic types *) - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> "bool" - | TEnum ({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> "object" - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) -> "double" - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) -> "int" - | TType ({ t_path = [],"UInt" },[]) - | TAbstract ({ a_path = [],"UInt" },[]) -> "uint" - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long" - | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeUInt64" },[]) -> "ulong" - | TType ({ t_path = ["cs"],"UInt64" },[]) - | TAbstract ({ a_path = ["cs"],"UInt64" },[]) -> "ulong" - | TType ({ t_path = ["cs"],"UInt8" },[]) - | TAbstract ({ a_path = ["cs"],"UInt8" },[]) -> "byte" - | TType ({ t_path = ["cs"],"Int8" },[]) - | TAbstract ({ a_path = ["cs"],"Int8" },[]) -> "sbyte" - | TType ({ t_path = ["cs"],"Int16" },[]) - | TAbstract ({ a_path = ["cs"],"Int16" },[]) -> "short" - | TType ({ t_path = ["cs"],"UInt16" },[]) - | TAbstract ({ a_path = ["cs"],"UInt16" },[]) -> "ushort" - | TType ({ t_path = ["cs"],"Char16" },[]) - | TAbstract ({ a_path = ["cs"],"Char16" },[]) -> "char" - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) -> "float" - | TInst ({ cl_path = ["haxe"],"Int32" },[]) - | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int" - | TInst ({ cl_path = ["haxe"],"Int64" },[]) - | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long" - | TInst ({ cl_path = ([], "Dynamic") },_) - | TAbstract ({ a_path = ([], "Dynamic") },_) -> "object" - | TType ({ t_path = ["cs"],"Out" },[t]) - | TAbstract ({ a_path = ["cs"],"Out" },[t]) - | TType ({ t_path = ["cs"],"Ref" },[t]) - | TAbstract ({ a_path = ["cs"],"Ref" },[t]) -> t_s t - | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> - let rec check_t_s t = - match real_type t with - | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> - (check_t_s param) ^ "[]" - | _ -> t_s (run_follow gen t) - in - (check_t_s param) ^ "[]" - | TInst({ cl_path = (["cs"], "Pointer") },[t]) - | TAbstract({ a_path = (["cs"], "Pointer") },[t])-> - t_s t ^ "*" - (* 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)) - | TInst ({ cl_path = [], "String" }, []) -> "string" - | TEnum (e, params) -> ("global::" ^ (module_s (TEnumDecl e))) - | TInst (cl, _ :: _) when Meta.has Meta.Enum cl.cl_meta -> - "global::" ^ module_s (TClassDecl cl) - | TInst (({ cl_path = p } as cl), params) -> (path_param_s (TClassDecl cl) p params) - | TType (({ t_path = p } as t), params) -> (path_param_s (TTypeDecl t) p params) - | TAnon (anon) -> - (match !(anon.a_status) with - | Statics _ | EnumStatics _ -> "System.Type" - | _ -> "object") - | TDynamic _ -> "object" - | TAbstract(a,pl) when a.a_impl <> None -> - t_s (Codegen.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) ^ " ]" - - and path_param_s md path params = - match params with - | [] -> "global::" ^ module_s md - | _ -> sprintf "%s<%s>" ("global::" ^ module_s md) (String.concat ", " (List.map (fun t -> t_s t) (change_param_type md params))) - in - - let rett_s t = - match t with - | TEnum ({e_path = ([], "Void")}, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> "void" - | _ -> t_s t - in - - let argt_s t = - match t with - | TType ({ t_path = (["cs"], "Ref") }, [t]) - | TAbstract ({ a_path = (["cs"], "Ref") },[t]) -> "ref " ^ t_s t - | TType ({ t_path = (["cs"], "Out") }, [t]) - | TAbstract ({ a_path = (["cs"], "Out") },[t]) -> "out " ^ t_s t - | _ -> t_s t - in - - let escape ichar b = - match ichar with - | 92 (* \ *) -> Buffer.add_string b "\\\\" - | 39 (* ' *) -> Buffer.add_string b "\\\'" - | 34 -> Buffer.add_string b "\\\"" - | 13 (* \r *) -> Buffer.add_string b "\\r" - | 10 (* \n *) -> Buffer.add_string b "\\n" - | 9 (* \t *) -> Buffer.add_string b "\\t" - | c when c < 32 || c >= 127 -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c) - | c -> Buffer.add_char b (Char.chr c) - in - - let escape s = - let b = Buffer.create 0 in - (try - UTF8.validate s; - UTF8.iter (fun c -> escape (UChar.code c) b) s - with - UTF8.Malformed_code -> - String.iter (fun c -> escape (Char.code c) b) s - ); - Buffer.contents b - in - - let has_semicolon e = - match e.eexpr with - | TBlock _ | TFor _ | TSwitch _ | TMatch _ | TTry _ | TIf _ -> false - | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false - | _ -> true - in - - let in_value = ref false in - - let rec md_s md = - let md = follow_module (gen.gfollow#run_f) md in - match md with - | TClassDecl ({ cl_types = [] } as cl) -> - t_s (TInst(cl,[])) - | TClassDecl (cl) when not (is_hxgen md) -> - t_s (TInst(cl,List.map (fun t -> t_dynamic) cl.cl_types)) - | TEnumDecl ({ e_types = [] } as e) -> - t_s (TEnum(e,[])) - | TEnumDecl (e) when not (is_hxgen md) -> - t_s (TEnum(e,List.map (fun t -> t_dynamic) e.e_types)) - | TClassDecl cl -> - t_s (TInst(cl,[])) - | TEnumDecl e -> - t_s (TEnum(e,[])) - | TTypeDecl t -> - t_s (TType(t, List.map (fun t -> t_dynamic) t.t_types)) - | TAbstractDecl a -> - t_s (TAbstract(a, List.map(fun t -> t_dynamic) a.a_types)) - in - - let rec ensure_local e explain = - match e.eexpr with - | TLocal _ -> e - | TCast(e,_) - | TParenthesis e -> ensure_local e explain - | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e - in - - let is_pointer t = match follow t with - | TInst({ cl_path = (["cs"], "Pointer") }, _) - | TAbstract ({ a_path = (["cs"], "Pointer") },_) -> - true - | _ -> - false in - - let last_line = ref (-1) in - let line_directive = - if Common.defined gen.gcon Define.RealPosition then - fun w p -> () - else fun w p -> - let cur_line = Lexer.get_error_line p in - let is_relative_path = (String.sub p.pfile 0 1) = "." in - let file = if is_relative_path then Common.get_full_path p.pfile else p.pfile in - if cur_line <> ((!last_line)+1) then begin print w "#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end; - last_line := cur_line - in - - let rec extract_tparams params el = - match el with - | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl -> - extract_tparams (tp.etype :: params) tl - | _ -> (params, el) - in - - let expr_s w e = - last_line := -1; - in_value := false; - let rec expr_s w e = - let was_in_value = !in_value in - in_value := true; - (match e.eexpr with - | TConst c -> - (match c with - | TInt i32 -> - write w (Int32.to_string i32); - (*match real_type e.etype with - | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L"; - | _ -> () - *) - | TFloat s -> - write w s; - (if String.get s (String.length s - 1) = '.' then write w "0"); - (*match real_type e.etype with - | TType( { t_path = ([], "Single") }, [] ) -> write w "f" - | _ -> () - *) - | TString s -> - write w "\""; - write w (escape s); - write w "\"" - | TBool b -> write w (if b then "true" else "false") - | TNull -> - write w "default("; - write w (t_s e.etype); - write w ")" - | TThis -> write w "this" - | TSuper -> write w "base") - | TLocal { v_name = "__sbreak__" } -> write w "break" - | TLocal { v_name = "__undefined__" } -> - write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types))); - write w ".undefined"; - | TLocal { v_name = "__typeof__" } -> write w "typeof" - | TLocal { v_name = "__sizeof__" } -> write w "sizeof" - | TLocal var -> - write_id w var.v_name - | TField (_, FEnum(e, ef)) -> - let s = ef.ef_name in - print w "%s." ("global::" ^ module_s (TEnumDecl e)); write_field w s - | TArray (e1, e2) -> - expr_s w e1; write w "["; expr_s w e2; write w "]" - | TBinop ((Ast.OpAssign as op), e1, e2) - | TBinop ((Ast.OpAssignOp _ as op), e1, e2) -> - expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2 - | TBinop (op, e1, e2) -> - write w "( "; - expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2; - write w " )" - | TField ({ eexpr = TTypeExpr mt }, s) -> - (match mt with - | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt) - | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt) - | TClassDecl { cl_interface = true } -> - write w ("global::" ^ module_s mt); - write w "__Statics_"; - | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_empty) cl.cl_types))) - | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_empty) en.e_types))) - | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_empty) td.t_types)))) - | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_empty) a.a_types))) - ); - write w "."; - write_field w (field_name s) - | TField (e, s) -> - expr_s w e; write w "."; write_field w (field_name s) - | TTypeExpr mt -> - (match mt with - | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt) - | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt) - | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_types))) - | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_dynamic) en.e_types))) - | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_dynamic) td.t_types)))) - | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_dynamic) a.a_types))) - ) - | TParenthesis e -> - write w "("; expr_s w e; write w ")" - | TArrayDecl el -> - print w "new %s" (t_s e.etype); - write w "{"; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w "}" - | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> - write w "( "; - expr_s w expr; - write w " is "; - write w (md_s md); - write w " )" - | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> - write w "( "; - expr_s w expr; - write w " as "; - write w (md_s md); - write w " )" - | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, [ expr ] ) -> - write w "( "; - expr_s w expr; - write w " as "; - write w (t_s e.etype); - write w " )"; - | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) -> - write w s - | TCall ({ eexpr = TLocal( { v_name = "__unsafe__" } ) }, [ e ] ) -> - write w "unsafe"; - expr_s w (mk_block e) - | TCall ({ eexpr = TLocal( { v_name = "__checked__" } ) }, [ e ] ) -> - write w "checked"; - expr_s w (mk_block e) - | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) -> - write w "lock("; - expr_s w eobj; - write w ")"; - expr_s w (mk_block eblock) - | TCall ({ eexpr = TLocal( { v_name = "__fixed__" } ) }, [ e ] ) -> - let first = ref true in - let rec loop = function - | ({ eexpr = TVars([v, Some({ eexpr = TCast( { eexpr = TCast(e, _) }, _) }) ]) } as expr) :: tl when is_pointer v.v_type -> - (if !first then first := false); - write w "fixed("; - let vf = mk_temp gen "fixed" v.v_type in - expr_s w { expr with eexpr = TVars([vf, Some e]) }; - write w ")"; - begin_block w; - expr_s w { expr with eexpr = TVars([v, Some (mk_local vf expr.epos)]) }; - write w ";"; - loop tl; - end_block w - | el when not !first -> - expr_s w { e with eexpr = TBlock el } - | _ -> - trace (debug_expr e); - gen.gcon.error "Invalid 'fixed' keyword format" e.epos - in - (match e.eexpr with - | TBlock bl -> loop bl - | _ -> - trace "not block"; - trace (debug_expr e); - gen.gcon.error "Invalid 'fixed' keyword format" e.epos - ) - | TCall ({ eexpr = TLocal( { v_name = "__addressOf__" } ) }, [ e ] ) -> - let e = ensure_local e "for addressOf" in - write w "&"; - expr_s w e - | TCall ({ eexpr = TLocal( { v_name = "__valueOf__" } ) }, [ e ] ) -> - write w "*("; - expr_s w e; - write w ")" - | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> - print w "goto label%ld" v - | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> - print w "label%ld: {}" v - | TCall ({ eexpr = TLocal( { v_name = "__rethrow__" } ) }, _) -> - write w "throw" - (* operator overloading handling *) - | TCall({ eexpr = TField(ef, FInstance(cl,{ cf_name = "__get" })) }, [idx]) when not (is_hxgen (TClassDecl cl)) -> - expr_s w { e with eexpr = TArray(ef, idx) } - | TCall({ eexpr = TField(ef, FInstance(cl,{ cf_name = "__set" })) }, [idx; v]) when not (is_hxgen (TClassDecl cl)) -> - expr_s w { e with eexpr = TBinop(Ast.OpAssign, { e with eexpr = TArray(ef, idx) }, v) } - | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name binops_names -> - let _, elr = extract_tparams [] el in - (match elr with - | [e1;e2] -> - expr_s w { e with eexpr = TBinop(PMap.find cf.cf_name binops_names, e1, e2) } - | _ -> do_call w e el) - | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name unops_names -> - (match extract_tparams [] el with - | _, [e1] -> - expr_s w { e with eexpr = TUnop(PMap.find cf.cf_name unops_names, Ast.Prefix,e1) } - | _ -> do_call w e el) - | TCall (e, el) -> - do_call w e el - | TNew (({ cl_path = (["cs"], "NativeArray") } as cl), params, [ size ]) -> - let rec check_t_s t times = - match real_type t with - | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> - (check_t_s param (times+1)) - | _ -> - print w "new %s[" (t_s (run_follow gen t)); - expr_s w size; - print w "]"; - let rec loop i = - if i <= 0 then () else (write w "[]"; loop (i-1)) - in - loop (times - 1) - in - check_t_s (TInst(cl, params)) 0 - | TNew ({ cl_path = ([], "String") } as cl, [], el) -> - write w "new "; - write w (t_s (TInst(cl, []))); - write w "("; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w ")" - | TNew (cl, params, el) -> - write w "new "; - write w (path_param_s (TClassDecl cl) cl.cl_path params); - write w "("; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w ")" - | TUnop ((Ast.Increment as op), flag, e) - | TUnop ((Ast.Decrement as op), flag, e) -> - (match flag with - | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e - | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op)) - | TUnop (op, flag, e) -> - (match flag with - | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") " - | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op)) - | TVars (v_eop_l) -> - ignore (List.fold_left (fun acc (var, eopt) -> - (if acc <> 0 then write w ", "); - print w "%s " (t_s var.v_type); - write_id w var.v_name; - (match eopt with - | None -> - write w " = "; - expr_s w (null var.v_type e.epos) - | Some e -> - write w " = "; - expr_s w e - ); - acc + 1 - ) 0 v_eop_l); - | TBlock [e] when was_in_value -> - expr_s w e - | TBlock el -> - begin_block w; - List.iter (fun e -> - line_directive w e.epos; - in_value := false; - expr_s w e; - (if has_semicolon e then write w ";"); - newline w - ) el; - end_block w - | TIf (econd, e1, Some(eelse)) when was_in_value -> - write w "( "; - expr_s w (mk_paren econd); - write w " ? "; - expr_s w (mk_paren e1); - write w " : "; - expr_s w (mk_paren eelse); - write w " )"; - | TIf (econd, e1, eelse) -> - write w "if "; - expr_s w (mk_paren econd); - write w " "; - in_value := false; - expr_s w (mk_block e1); - (match eelse with - | None -> () - | Some e -> - write w " else "; - in_value := false; - expr_s w (mk_block e) - ) - | TWhile (econd, eblock, flag) -> - (match flag with - | Ast.NormalWhile -> - write w "while "; - expr_s w (mk_paren econd); - write w ""; - in_value := false; - expr_s w (mk_block eblock) - | Ast.DoWhile -> - write w "do "; - in_value := false; - expr_s w (mk_block eblock); - write w "while "; - in_value := true; - expr_s w (mk_paren econd); - ) - | TSwitch (econd, ele_l, default) -> - write w "switch "; - expr_s w (mk_paren econd); - begin_block w; - List.iter (fun (el, e) -> - List.iter (fun e -> - write w "case "; - in_value := true; - expr_s w e; - write w ":"; - ) el; - newline w; - in_value := false; - expr_s w (mk_block e); - newline w; - newline w - ) ele_l; - if is_some default then begin - write w "default:"; - newline w; - in_value := false; - expr_s w (get default); - newline w; - end; - end_block w - | TTry (tryexpr, ve_l) -> - write w "try "; - in_value := false; - expr_s w (mk_block tryexpr); - List.iter (fun (var, e) -> - print w "catch (%s %s)" (t_s var.v_type) (var.v_name); - in_value := false; - expr_s w (mk_block e); - newline w - ) ve_l - | TReturn eopt -> - write w "return "; - if is_some eopt then expr_s w (get eopt) - | TBreak -> write w "break" - | TContinue -> write w "continue" - | TThrow e -> - write w "throw "; - expr_s w e - | TCast (e1,md_t) -> - ((*match gen.gfollow#run_f e.etype with - | TType({ t_path = ([], "UInt") }, []) -> - write w "( unchecked ((uint) "; - expr_s w e1; - write w ") )" - | _ ->*) - (* FIXME I'm ignoring module type *) - print w "((%s) (" (t_s e.etype); - expr_s w e1; - write w ") )" - ) - | TFor (_,_,content) -> - 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 - | TMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false - ) - and do_call w e el = - let params, el = extract_tparams [] el in - let params = List.rev params in - - expr_s w e; - - (match params with - | [] -> () - | params -> - let md = match e.eexpr with - | TField(ef, _) -> t_to_md (run_follow gen ef.etype) - | _ -> assert false - in - write w "<"; - ignore (List.fold_left (fun acc t -> - (if acc <> 0 then write w ", "); - write w (t_s t); - acc + 1 - ) 0 (change_param_type md params)); - write w ">" - ); - - let rec loop acc elist tlist = - match elist, tlist with - | e :: etl, (_,_,t) :: ttl -> - (if acc <> 0 then write w ", "); - (match real_type t with - | TType({ t_path = (["cs"], "Ref") }, _) - | TAbstract ({ a_path = (["cs"], "Ref") },_) -> - let e = ensure_local e "of type cs.Ref" in - write w "ref "; - expr_s w e - | TType({ t_path = (["cs"], "Out") }, _) - | TAbstract ({ a_path = (["cs"], "Out") },_) -> - let e = ensure_local e "of type cs.Out" in - write w "out "; - expr_s w e - | _ -> - expr_s w e - ); - loop (acc + 1) etl ttl - | e :: etl, [] -> - (if acc <> 0 then write w ", "); - expr_s w e; - loop (acc + 1) etl [] - | _ -> () - in - write w "("; - let ft = match follow e.etype with - | TFun(args,_) -> args - | _ -> [] - in - - loop 0 el ft; - - write w ")" - in - expr_s w e - in - - let get_string_params cl_types = - match cl_types with - | [] -> - ("","") - | _ -> - let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_types)) in - let params_extends = List.fold_left (fun acc (name, t) -> - match run_follow gen t with - | TInst (cl, p) -> - (match cl.cl_implements with - | [] -> 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 t); assert false (* FIXME it seems that a cl_types will never be anything other than cl.cl_types. I'll take the risk and fail if not, just to see if that confirms *) - ) [] cl_types in - (params, String.concat " " params_extends) - in - - let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf = - let is_interface = cl.cl_interface in - let name, is_new, is_explicit_iface = match cf.cf_name with - | "new" -> snd cl.cl_path, true, false - | name when String.contains name '.' -> - let fn_name, path = parse_explicit_iface name in - (path_s path) ^ "." ^ fn_name, false, true - | name -> try - let binop = PMap.find name binops_names in - "operator " ^ s_binop binop, false, false - with | Not_found -> try - let unop = PMap.find name unops_names in - "operator " ^ s_unop unop, false, false - with | Not_found -> - name, false, false - in - let rec loop_static cl = - match is_static, cl.cl_super with - | false, _ -> [] - | true, None -> [] - | true, Some(cl,_) -> - (try - let cf2 = PMap.find cf.cf_name cl.cl_statics in - Gencommon.CastDetect.type_eq gen EqStrict cf.cf_type cf2.cf_type; - ["new"] - with - | Not_found | Unify_error _ -> - loop_static cl - ) - in - let modf = loop_static cl in - - (match cf.cf_kind with - | Var _ - | Method (MethDynamic) when not (Type.is_extern_field cf) -> - (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then - gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos); - if not is_interface then begin - let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in - let modifiers = modifiers @ modf in - (match cf.cf_expr with - | Some e -> - print w "%s %s%s %s %s = " access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name); - expr_s w e; - write w ";" - | None -> - print w "%s %s%s %s %s;" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name) - ) - end (* TODO see how (get,set) variable handle when they are interfaces *) - | Method _ when Type.is_extern_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 - gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf - ) cf.cf_overloads - | Var _ | Method MethDynamic -> () - | Method mkind -> - List.iter (fun cf -> - if cl.cl_interface || cf.cf_expr <> None then - gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf - ) cf.cf_overloads; - let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in - let is_virtual = if not is_virtual || Meta.has Meta.Final cf.cf_meta then false else is_virtual in - let is_override = List.memq cf cl.cl_overrides in - let is_override = is_override || match cf.cf_name, follow cf.cf_type with - | "Equals", TFun([_,_,targ], tret) -> - (match follow targ, follow tret with - | TDynamic _, TEnum({ e_path = ([], "Bool") }, []) - | TDynamic _, TAbstract({ a_path = ([], "Bool") }, []) -> true - | _ -> false) - | "GetHashCode", TFun([],_) -> true - | _ -> false - in - - let is_virtual = is_virtual && not (Meta.has Meta.Final cl.cl_meta) && not (is_interface) in - let visibility = if is_interface then "" else "public" in - - let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in - let modifiers = modifiers @ modf 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 "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_types)) 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 - - (* public static void funcName *) - print w "%s %s %s %s %s" (visibility) v_n (String.concat " " modifiers) (if is_new then "" else rett_s (run_follow gen ret_type)) (change_field name); - let params, params_ext = get_string_params cf.cf_params in - (* (string arg1, object arg2) with T : object *) - (match cf.cf_expr with - | Some { eexpr = TFunction tf } -> - print w "%s(%s)%s" (params) (String.concat ", " (List.map2 (fun (var, _) (_,_,t) -> sprintf "%s %s" (argt_s (run_follow gen t)) (change_id var.v_name)) tf.tf_args args)) (params_ext) - | _ -> - print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s (run_follow gen t)) (change_id name)) args)) (params_ext) - ); - if is_interface then - write w ";" - else begin - let rec loop meta = - match meta with - | [] -> - let expr = match cf.cf_expr with - | None -> mk (TBlock([])) t_dynamic Ast.null_pos - | Some s -> - match s.eexpr with - | TFunction tf -> - mk_block (tf.tf_expr) - | _ -> assert false (* FIXME *) - in - (if is_new then begin - let rec get_super_call el = - match el with - | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest -> - Some call, rest - | ( { eexpr = TBlock(bl) } as block ) :: rest -> - let ret, mapped = get_super_call bl in - ret, ( { block with eexpr = TBlock(mapped) } :: rest ) - | _ -> - None, el - in - match expr.eexpr with - | TBlock(bl) -> - let super_call, rest = get_super_call bl in - (match super_call with - | None -> () - | Some sc -> - write w " : "; - let t = Common.timer "expression to string" in - expr_s w sc; - t() - ); - begin_block w; - write w "unchecked "; - let t = Common.timer "expression to string" in - expr_s w { expr with eexpr = TBlock(rest) }; - t(); - write w "#line default"; - end_block w; - | _ -> assert false - end else begin - begin_block w; - write w "unchecked "; - let t = Common.timer "expression to string" in - expr_s w expr; - t(); - write w "#line default"; - end_block w; - end) - | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> - begin_block w; - write w contents; - end_block w - | _ :: tl -> loop tl - in - loop cf.cf_meta - - end); - newline w; - newline w; - in - - let check_special_behaviors w cl = match cl.cl_kind with - | KAbstractImpl _ -> () - | _ -> - (* get/set pairs *) - let pairs = ref PMap.empty in - (try - let get = PMap.find "__get" cl.cl_fields in - List.iter (fun cf -> - let args,ret = get_fun cf.cf_type in - match args with - | [_,_,idx] -> pairs := PMap.add (t_s idx) ( t_s ret, Some cf, None ) !pairs - | _ -> gen.gcon.warning "The __get function must have exactly one argument (the index)" cf.cf_pos - ) (get :: get.cf_overloads) - with | Not_found -> ()); - (try - let set = PMap.find "__set" cl.cl_fields in - List.iter (fun cf -> - let args, ret = get_fun cf.cf_type in - match args with - | [_,_,idx; _,_,v] -> (try - let vt, g, _ = PMap.find (t_s idx) !pairs in - let tvt = t_s v in - if vt <> tvt then gen.gcon.warning "The __get function of same index has a different type from this __set function" cf.cf_pos; - pairs := PMap.add (t_s idx) (vt, g, Some cf) !pairs - with | Not_found -> - pairs := PMap.add (t_s idx) (t_s v, None, Some cf) !pairs) - | _ -> - gen.gcon.warning "The __set function must have exactly two arguments (index, value)" cf.cf_pos - ) (set :: set.cf_overloads) - with | Not_found -> ()); - PMap.iter (fun idx (v, get, set) -> - print w "public %s this[%s index]" v idx; - begin_block w; - (match get with - | None -> () - | Some _ -> - write w "get"; - begin_block w; - write w "return this.__get(index);"; - end_block w); - (match set with - | None -> () - | Some _ -> - write w "set"; - begin_block w; - write w "this.__set(index,value);"; - end_block w); - end_block w) !pairs; - (if not (PMap.is_empty !pairs) then try - let get = PMap.find "__get" cl.cl_fields in - 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 - in - List.iter (fun (cl,args) -> - match cl.cl_array_access with - | None -> () - | Some t -> - let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) t in - let t_as_s = t_s (run_follow gen changed_t) in - print w "%s %s.this[int key]" t_as_s (t_s (TInst(cl, args))); - begin_block w; - write w "get"; - begin_block w; - print w "return ((%s) this.__get(key));" t_as_s; - end_block w; - write w "set"; - begin_block w; - print w "this.__set(key, (%s) value);" v_t; - end_block w; - end_block w; - newline w; - newline w - ) cl.cl_implements - with | Not_found -> ()); - if cl.cl_interface && is_hxgen (TClassDecl cl) && is_some cl.cl_array_access then begin - let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) (get cl.cl_array_access) in - print w "%s this[int key]" (t_s (run_follow gen changed_t)); - begin_block w; - write w "get;"; - newline w; - write w "set;"; - newline w; - end_block w; - newline w; - newline w - end; - (try - if cl.cl_interface then raise Not_found; - let cf = PMap.find "toString" cl.cl_fields in - (if List.exists (fun c -> c.cf_name = "toString") cl.cl_overrides then raise Not_found); - (match cf.cf_type with - | TFun([], ret) -> - (match real_type ret with - | TInst( { cl_path = ([], "String") }, []) -> - write w "public override string ToString()"; - begin_block w; - write w "return this.toString();"; - end_block w; - newline w; - newline w - | _ -> - gen.gcon.error "A toString() function should return a String!" cf.cf_pos - ) - | _ -> () - ) - with | Not_found -> ()); - (* properties * - let handle_prop static f = - match f.cf_kind with - | Method _ -> () - | Var v when not (Type.is_extern_field f) -> () - | Var v -> - let prop acc = match acc with - | AccNo | AccNever | AccCall -> true - | _ -> false - in - if prop v.v_read && prop v.v_write && (v.v_read = AccCall || v.v_write = AccCall) then begin - let this = if static then - mk_classtype_access cl f.cf_pos - else - { eexpr = TConst TThis; etype = TInst(cl,List.map snd cl.cl_types); epos = f.cf_pos } - in - print w "public %s%s %s" (if static then "static " else "") (t_s f.cf_type) f.cf_name; - begin_block w; - (match v.v_read with - | AccCall -> - write w "get"; - begin_block w; - write w "return "; - expr_s w this; - print w ".get_%s();" f.cf_name; - end_block w - | _ -> ()); - (match v.v_write with - | AccCall -> - write w "set"; - begin_block w; - expr_s w this; - print w ".set_%s(value);" f.cf_name; - end_block w - | _ -> ()); - end_block w; - end - in - List.iter (handle_prop true) cl.cl_ordered_statics; - List.iter (handle_prop false) cl.cl_ordered_fields *) - in - - let gen_class w cl = - 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 - | ns -> - print w "namespace %s" (String.concat "." ns); - begin_block w; - true - in - - 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 "cs.Boot.init();"; newline w); - expr_s w { eexpr = TTypeExpr(TClassDecl cl); etype = t_dynamic; epos = Ast.null_pos }; - write w ".main();"; - end_block w; - end_block w; - false - | Some path when path = cl.cl_path && not cl.cl_interface -> true - | _ -> false - in - - let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in - let is_final = clt = "struct" || Meta.has Meta.Final cl.cl_meta in - - print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path)); - (* type parameters *) - let params, params_ext = get_string_params cl.cl_types in - let extends_implements = (match cl.cl_super with | None -> [] | Some (cl,p) -> [path_param_s (TClassDecl cl) cl.cl_path p]) @ (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements) in - (match extends_implements with - | [] -> print w "%s %s" params params_ext - | _ -> print w "%s : %s %s" params (String.concat ", " extends_implements) params_ext); - (* class head ok: *) - (* 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;*) - - let rec loop meta = - match meta with - | [] -> () - | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> - write w contents - | _ :: tl -> loop tl - in - loop cl.cl_meta; - - if is_main then begin - write w "public static void Main()"; - begin_block w; - (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "cs.Boot.init();"; newline w); - write w "main();"; - end_block w - end; - - (match cl.cl_init with - | None -> () - | Some init -> - print w "static %s() " (snd cl.cl_path); - expr_s w (mk_block init)); - (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor)); - if not cl.cl_interface then List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics; - List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields; - check_special_behaviors w cl; - end_block w; - if cl.cl_interface && cl.cl_ordered_statics <> [] then begin - print w "public class %s__Statics_" (snd cl.cl_path); - begin_block w; - List.iter (gen_class_field w true { cl with cl_interface = false } is_final) cl.cl_ordered_statics; - end_block w - end; - if should_close then end_block w - in - - - let gen_enum w e = - let should_close = match change_ns (TEnumDecl e) (fst e.e_path) with - | [] -> false - | ns -> - print w "namespace %s" (String.concat "." ns); - begin_block w; - true - in - - print w "public enum %s" (change_clname (snd e.e_path)); - begin_block w; - write w (String.concat ", " (List.map (change_id) e.e_names)); - end_block w; - - if should_close then end_block w - in - - let module_type_gen w md_tp = - match md_tp with - | TClassDecl cl -> - if not cl.cl_extern then begin - (if no_root && len w = 0 then write w "using haxe.root;"; newline w;); - gen_class w cl; - newline w; - newline w - end; - (not cl.cl_extern) - | TEnumDecl e -> - if not e.e_extern then begin - (if no_root && len w = 0 then write w "using haxe.root;"; newline w;); - gen_enum w e; - newline w; - newline w - end; - (not e.e_extern) - | TAbstractDecl _ - | TTypeDecl _ -> - false - in - - let module_gen w md_def = - List.fold_left (fun should md -> module_type_gen w md or should) false md_def.m_types - in - - (* generate source code *) - init_ctx gen; - - Hashtbl.add gen.gspecial_vars "__rethrow__" true; - Hashtbl.add gen.gspecial_vars "__typeof__" true; - Hashtbl.add gen.gspecial_vars "__label__" true; - Hashtbl.add gen.gspecial_vars "__goto__" true; - Hashtbl.add gen.gspecial_vars "__is__" true; - Hashtbl.add gen.gspecial_vars "__as__" true; - Hashtbl.add gen.gspecial_vars "__cs__" true; - - Hashtbl.add gen.gspecial_vars "__checked__" true; - Hashtbl.add gen.gspecial_vars "__lock__" true; - Hashtbl.add gen.gspecial_vars "__fixed__" true; - Hashtbl.add gen.gspecial_vars "__unsafe__" true; - Hashtbl.add gen.gspecial_vars "__addressOf__" true; - Hashtbl.add gen.gspecial_vars "__valueOf__" true; - Hashtbl.add gen.gspecial_vars "__sizeof__" true; - - Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true); - let last_needs_box = gen.gneeds_box in - gen.gneeds_box <- (fun t -> match t with | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true | _ -> last_needs_box t); - - gen.greal_type <- real_type; - gen.greal_type_param <- change_param_type; - - SetHXGen.run_filter gen SetHXGen.default_hxgen_func; - - (* before running the filters, follow all possible types *) - (* this is needed so our module transformations don't break some core features *) - (* like multitype selection *) - let run_follow_gen = run_follow gen in - let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen) (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in - let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in - List.iter (function - | TClassDecl cl -> - let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in - List.iter (fun cf -> - cf.cf_type <- run_follow_gen cf.cf_type; - cf.cf_expr <- Option.map type_map cf.cf_expr - ) all_fields; - cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic; - cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access; - cl.cl_init <- Option.map type_map cl.cl_init; - cl.cl_super <- Option.map super_map cl.cl_super; - cl.cl_implements <- List.map super_map cl.cl_implements - | _ -> () - ) gen.gcon.types; - - let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in - - (*let closure_t = ClosuresToClass.create gen 10 float_cl - (fun l -> l) - (fun l -> l) - (fun args -> args) - (fun args -> []) - in - ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e)); - - StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*) - - let tp_v = alloc_var "$type_param" t_dynamic in - let mk_tp t pos = { eexpr = TLocal(tp_v); etype = t; epos = pos } in - TypeParams.configure gen (fun ecall efield params elist -> - match efield.eexpr with - | TField(_, FEnum _) -> - { ecall with eexpr = TCall(efield, elist) } - | _ -> - { ecall with eexpr = TCall(efield, (List.map (fun t -> mk_tp t ecall.epos ) params) @ elist) } - ); - - HardNullableSynf.configure gen (HardNullableSynf.traverse gen - (fun e -> - match real_type e.etype with - | TInst({ cl_path = (["haxe";"lang"], "Null") }, [t]) -> - { (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 - ) - (fun v t has_value -> - match has_value, real_type v.etype with - | true, TDynamic _ | true, TAnon _ | true, TMono _ -> - { - eexpr = TCall(mk_static_field_access_infer null_t "ofDynamic" v.epos [t], [mk_tp t v.epos; v]); - etype = TInst(null_t, [t]); - epos = v.epos - } - | _ -> - { eexpr = TNew(null_t, [t], [gen.ghandle_cast t v.etype v; { eexpr = TConst(TBool has_value); etype = gen.gcon.basic.tbool; epos = v.epos } ]); etype = TInst(null_t, [t]); epos = v.epos } - ) - (fun e -> - { - eexpr = TCall( - { (mk_field_access gen { (mk_paren e) with etype = real_type e.etype } "toDynamic" e.epos) with etype = TFun([], t_dynamic) }, - []); - etype = t_dynamic; - epos = e.epos - } - ) - (fun e -> - mk_field_access gen { e with etype = real_type e.etype } "hasValue" e.epos - ) - (fun e1 e2 -> - { - eexpr = TCall( - mk_field_access gen e1 "Equals" e1.epos, - [e2]); - etype = basic.tbool; - epos = e1.epos; - } - ) - true - false - ); - - - let explicit_fn_name c tl fname = - path_param_s (TClassDecl c) c.cl_path tl ^ "." ^ fname - in - FixOverrides.configure ~explicit_fn_name:explicit_fn_name gen; - NormalizeType.configure gen; - - AbstractImplementationFix.configure gen; - - IteratorsInterface.configure gen (fun e -> e); - - OverrideFix.configure gen; - - ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) )); - - EnumToClass.configure gen (Some (fun e -> mk_cast gen.gcon.basic.tint e)) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) true false; - - InterfaceVarsDeleteModf.configure gen; - - let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in - - let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in - - (*fixme: THIS IS A HACK. take this off *) - let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in - (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*) - - let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in - let empty_ef = - try - PMap.find "EMPTY" empty_e.e_constrs - with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false - in - OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen; - - let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in - let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in - - let can_be_float = like_float in - - let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe = - let is_float = can_be_float (real_type main_expr.etype) in - let fn_name = if is_some may_set then "setField" else "getField" in - let fn_name = if is_float then fn_name ^ "_f" else fn_name in - let pos = field_expr.epos in - - let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in - - let should_cast = match main_expr.etype with | TInst({ cl_path = ([], "Float") }, []) -> false | _ -> true in - let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in - let first_args = - [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ] - @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else [] - in - let args = first_args @ match is_float, may_set with - | true, Some(set) -> - [ if should_cast then mk_cast basic.tfloat set else set ] - | false, Some(set) -> - [ set ] - | _ -> - [ is_unsafe ] - in - - let call = { main_expr with eexpr = TCall(infer,args) } in - let call = if is_float && should_cast then mk_cast main_expr.etype call else call in - call - in - - let rcf_on_call_field ecall field_expr field may_hash args = - let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in - - let hash_arg = match may_hash with - | None -> [] - | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ] - in - - let arr_call = if args <> [] then - { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos } - else - null (basic.tarray t_dynamic) ecall.epos - in - - let call_args = - [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ] - @ hash_arg - @ [ arr_call ] - in - - mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args) } - in - - handle_type_params gen ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject"))); - - let rcf_ctx = ReflectionCFs.new_ctx gen closure_t object_iface true rcf_on_getset_field rcf_on_call_field (fun hash hash_array -> - { hash with eexpr = TCall(rcf_static_find, [hash; hash_array]); etype=basic.tint } - ) (fun hash -> { hash with eexpr = TCall(rcf_static_lookup, [hash]); etype = gen.gcon.basic.tstring } ) false in - - ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object; - - ReflectionCFs.configure_dynamic_field_access rcf_ctx false; - - (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *) - let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in - let varargs_cl = get_cl (get_type gen (["haxe";"lang"],"VarArgsFunction")) in - let dynamic_name = gen.gmk_internal_name "hx" "invokeDynamic" in - - List.iter (fun cl -> - List.iter (fun cf -> - if cf.cf_name = dynamic_name then cl.cl_overrides <- cf :: cl.cl_overrides - ) cl.cl_ordered_fields - ) [closure_cl; varargs_cl]; - - let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in - - ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) ); - - let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in - ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> { - eexpr = TCall(slow_invoke, [ethis; efield; eargs]); - etype = t_dynamic; - epos = ethis.epos; - } ) object_iface; - - let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in - - ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn); - - InitFunction.configure gen true; - TArrayTransform.configure gen (TArrayTransform.default_implementation gen ( - fun e -> - match e.eexpr with - | TArray(e1, e2) -> - ( match follow e1.etype with - | TDynamic _ | TAnon _ | TMono _ -> true - | TInst({ cl_kind = KTypeParameter _ }, _) -> true - | _ -> false ) - | _ -> assert false - ) "__get" "__set" ); - - let field_is_dynamic t field = - match field_access gen (gen.greal_type t) field with - | FEnumField _ - | FClassField _ -> false - | _ -> true - in - - let is_type_param e = match follow e with - | TInst( { cl_kind = KTypeParameter _ },[]) -> true - | _ -> false - in - - let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with - | TField(tf, f) -> field_is_dynamic tf.etype (field_name f) - | _ -> false - in - - let may_nullable t = match gen.gfollow#run_f t with - | TType({ t_path = ([], "Null") }, [t]) -> - (match follow t with - | TInst({ cl_path = ([], "String") }, []) - | TInst({ cl_path = ([], "Float") }, []) - | TAbstract ({ a_path = ([], "Float") },[]) - | TInst({ cl_path = (["haxe"], "Int32")}, [] ) - | TInst({ cl_path = (["haxe"], "Int64")}, [] ) - | TInst({ cl_path = ([], "Int") }, []) - | TAbstract ({ a_path = ([], "Int") },[]) - | TEnum({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t - | TAbstract _ when like_float t -> Some t - | _ -> None ) - | _ -> None - in - - let is_double t = like_float t && not (like_int t) in - let is_int t = like_int t in - - let is_null t = match real_type t with - | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true - | _ -> false - in - - let is_null_expr e = is_null e.etype || match e.eexpr with - | TField(tf, f) -> (match field_access gen (real_type tf.etype) (field_name f) with - | FClassField(_,_,_,_,_,actual_t,_) -> is_null actual_t - | _ -> false) - | _ -> false - in - - let should_handle_opeq t = - match real_type t with - | TDynamic _ | TAnon _ | TMono _ - | TInst( { cl_kind = KTypeParameter _ }, _ ) - | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true - | _ -> false - in - - let string_cl = match gen.gcon.basic.tstring with - | TInst(c,[]) -> c - | _ -> assert false - in - - DynamicOperators.configure gen - (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with - | TBinop (Ast.OpEq, e1, e2) - | TBinop (Ast.OpNotEq, e1, e2) -> should_handle_opeq e1.etype or should_handle_opeq e2.etype - | TBinop (Ast.OpAssignOp Ast.OpAdd, e1, e2) -> - is_dynamic_expr e1 || is_null_expr e1 || is_string e.etype - | TBinop (Ast.OpAdd, e1, e2) -> is_dynamic e1.etype or is_dynamic e2.etype or is_type_param e1.etype or is_type_param e2.etype or is_string e1.etype or is_string e2.etype or is_string e.etype - | TBinop (Ast.OpLt, e1, e2) - | TBinop (Ast.OpLte, e1, e2) - | TBinop (Ast.OpGte, e1, e2) - | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2 or is_string e1.etype or is_string e2.etype - | TBinop (_, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2 - | TUnop (_, _, e1) -> is_dynamic_expr e1 || is_null_expr e1 (* we will see if the expression is Null also, as the unwrap from Unop will be the same *) - | _ -> false) - (fun e1 e2 -> - let is_basic = is_cs_basic_type (follow e1.etype) || is_cs_basic_type (follow e2.etype) in - let is_ref = if is_basic then false else match follow e1.etype, follow e2.etype with - | TDynamic _, _ - | _, TDynamic _ - | TInst( { cl_path = ([], "String") }, [] ), _ - | _, TInst( { cl_path = ([], "String") }, [] ) - | TInst( { cl_kind = KTypeParameter _ }, [] ), _ - | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false - | _, _ -> true - in - - let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in - { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos } - ) - (fun e e1 e2 -> - match may_nullable e1.etype, may_nullable e2.etype with - | Some t1, Some t2 -> - let t1, t2 = if is_string t1 || is_string t2 then - basic.tstring, basic.tstring - else if is_double t1 || is_double t2 then - basic.tfloat, basic.tfloat - else if is_int t1 || is_int t2 then - basic.tint, basic.tint - else t1, t2 in - { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos } - | _ when is_string e.etype || is_string e1.etype || is_string e2.etype -> - { - eexpr = TCall( - mk_static_field_access_infer runtime_cl "concat" e.epos [], - [ e1; e2 ] - ); - etype = basic.tstring; - epos = e.epos - } - | _ -> - let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in - mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos }) - (fun e1 e2 -> - if is_string e1.etype then begin - { e1 with eexpr = TCall(mk_static_field_access_infer string_cl "Compare" e1.epos [], [ e1; e2 ]); etype = gen.gcon.basic.tint } - end else begin - let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in - { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos } - end) ~handle_strings:false); - - FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func); - - let base_exception = get_cl (get_type gen (["System"], "Exception")) in - let base_exception_t = TInst(base_exception, []) in - - let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in - let hx_exception_t = TInst(hx_exception, []) in - - let rec is_exception t = - match follow t with - | TInst(cl,_) -> - if cl == base_exception then - true - else - (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg))) - | _ -> false - in - - TryCatchWrapper.configure gen - ( - TryCatchWrapper.traverse gen - (fun t -> not (is_exception (real_type t))) - (fun throwexpr expr -> - let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in - { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid } - ) - (fun v_to_unwrap pos -> - let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in - mk_field_access gen local "obj" pos - ) - (fun rethrow -> - { rethrow with eexpr = TCall(mk_local (alloc_var "__rethrow__" t_dynamic) rethrow.epos, [rethrow]); etype = gen.gcon.basic.tvoid } - ) - (base_exception_t) - (hx_exception_t) - (fun v e -> e) - ); - - let get_typeof e = - { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) } - in - - ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> - get_typeof e - )); - - CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) true ~native_string_cast:false ~overloads_cast_to_base:true); - - (*FollowAll.configure gen;*) - - SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e -> - match e.eexpr with - | TSwitch(cond, cases, def) -> - (match gen.gfollow#run_f cond.etype with - | TInst({ cl_path = ([], "Int") },[]) - | TAbstract ({ a_path = ([], "Int") },[]) - | TInst({ cl_path = ([], "String") },[]) -> - (List.exists (fun (c,_) -> - List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c - ) cases) - | _ -> true - ) - | _ -> assert false - ) true ) ; - - ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVars([mk_temp gen "expr" e.etype, Some e]); etype = gen.gcon.basic.tvoid; epos = e.epos })); - - UnnecessaryCastsRemoval.configure gen; - - IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true); - - UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true false); - - let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in - ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl); - - let goto_special = alloc_var "__goto__" t_dynamic in - let label_special = alloc_var "__label__" t_dynamic in - SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen - (fun e_loop n api -> - api ({ eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos }) false; - e_loop - ) - (fun e_break n api -> - { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos } - ) - ); - - DefaultArguments.configure gen (DefaultArguments.traverse gen); - - CSharpSpecificSynf.configure gen (CSharpSpecificSynf.traverse gen runtime_cl); - CSharpSpecificESynf.configure gen (CSharpSpecificESynf.traverse gen runtime_cl); - - let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in - mkdir gen.gcon.file; - mkdir (gen.gcon.file ^ "/src"); - - (* add resources array *) - (try - let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in - mkdir (gen.gcon.file ^ "/src/Resources"); - let cf = PMap.find "content" res.cl_statics in - let res = ref [] in - Hashtbl.iter (fun name v -> - res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res; - - let f = open_out (gen.gcon.file ^ "/src/Resources/" ^ name) in - output_string f v; - close_out f - ) gen.gcon.resources; - cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos }) - with | Not_found -> ()); - - run_filters gen; - (* after the filters have been run, add all hashed fields to FieldLookup *) - - let normalize_i i = - let i = Int32.of_int (i) in - if i < Int32.zero then - Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30) - else i - in - - let hashes = Hashtbl.fold (fun i s acc -> (normalize_i i,s) :: acc) rcf_ctx.rcf_hash_fields [] in - let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in - - let flookup_cl = get_cl (get_type gen (["haxe";"lang"], "FieldLookup")) in - (try - let basic = gen.gcon.basic in - let change_array = ArrayDeclSynf.default_implementation gen native_arr_cl in - let cl = flookup_cl in - let field_ids = PMap.find "fieldIds" cl.cl_statics in - let fields = PMap.find "fields" cl.cl_statics in - - field_ids.cf_expr <- Some (change_array { - eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TInt (i)); etype = basic.tint; epos = field_ids.cf_pos }) hashes); - etype = basic.tarray basic.tint; - epos = field_ids.cf_pos - }); - - fields.cf_expr <- Some (change_array { - eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TString s); etype = basic.tstring; epos = fields.cf_pos }) hashes); - etype = basic.tarray basic.tstring; - epos = fields.cf_pos - }) - - with | Not_found -> - gen.gcon.error "Fields 'fieldIds' and 'fields' were not found in class haxe.lang.FieldLookup" flookup_cl.cl_pos - ); - - TypeParams.RenameTypeParameters.run gen; - - let t = Common.timer "code generation" in - - generate_modules gen "cs" "src" module_gen; - - dump_descriptor gen ("hxcs_build.txt") path_s module_s; + 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_len <- (fun e p -> mk_field_access gen e "Length" p); + + let basic = gen.gcon.basic in + + let erase_generics = Common.defined gen.gcon Define.EraseGenerics in + let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in + let null_t = if erase_generics then null_class else (get_cl (get_type gen (["haxe";"lang"],"Null")) ) in + let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in + let no_root = Common.defined gen.gcon Define.NoRoot in + let change_id name = try + Hashtbl.find reserved name + with | Not_found -> + let ret = String.concat "." (String.nsplit name "#") in + List.hd (String.nsplit ret "`") + in + + let change_clname n = change_id n in + + let change_ns_params_root md ns params = + let ns,params = List.fold_left (fun (ns,params) nspart -> try + let part, nparams = String.split nspart "`" in + let nparams = int_of_string nparams in + let rec loop i needed params = + if i = nparams then + (List.rev needed,params) + else + loop (i+1) (List.hd params :: needed) (List.tl params) + in + let needed,params = loop 0 [] params in + let part = change_id part in + (part ^ "<" ^ (String.concat ", " needed) ^ ">")::ns, params + with _ -> (* Invalid_string / int_of_string *) + (change_id nspart)::ns, params + ) ([],params) ns + in + List.rev ns,params + in + + let change_ns_params md params ns = if no_root then match ns with + | [] when is_hxgen md -> ["haxe";"root"], params + | [] -> (match md with + | TClassDecl { cl_path = ([],"Std" | [],"Math") } -> ["haxe";"root"], params + | TClassDecl { cl_meta = m } when Meta.has Meta.Enum m -> ["haxe";"root"], params + | _ -> [], params) + | ns when params = [] -> List.map change_id ns, params + | ns -> + change_ns_params_root md ns params + else if params = [] then + List.map change_id ns, params + else + change_ns_params_root md ns params + in + + let change_ns md ns = + let ns, _ = change_ns_params md [] ns in + ns + in + + let change_field = change_id in + let write_id w name = write w (change_id name) in + let write_field w name = write w (change_field name) in + + let ptr = + if Common.defined gen.gcon Define.Unsafe then + get_abstract (get_type gen (["cs"],"Pointer")) + else + null_abstract + in + + let is_hxgeneric md = + TypeParams.RealTypeParams.is_hxgeneric md + in + + let rec field_is_hxgeneric e = match e.eexpr with + | TParenthesis e | TMeta(_,e) -> field_is_hxgeneric e + | TField(_, (FStatic(cl,_) | FInstance(cl,_,_)) ) -> + (* print_endline ("is_hxgeneric " ^ path_s cl.cl_path ^ " : " ^ string_of_bool (is_hxgeneric (TClassDecl cl))); *) + is_hxgeneric (TClassDecl cl) + | _ -> true + in + + gen.gfollow#add ~name:"follow_basic" (fun t -> match t with + | TAbstract ({ a_path = ([], "Bool") },[]) + | TAbstract ({ a_path = ([], "Void") },[]) + | TAbstract ({ a_path = ([],"Float") },[]) + | TAbstract ({ a_path = ([],"Int") },[]) + | TAbstract ({ a_path = [],"UInt" },[]) + | TType ({ t_path = ["cs"], "Int64" },[]) + | TAbstract ({ a_path = ["cs"], "Int64" },[]) + | TType ({ t_path = ["cs"],"UInt64" },[]) + | TAbstract ({ a_path = ["cs"],"UInt64" },[]) + | TType ({ t_path = ["cs"],"UInt8" },[]) + | TAbstract ({ a_path = ["cs"],"UInt8" },[]) + | TType ({ t_path = ["cs"],"Int8" },[]) + | TAbstract ({ a_path = ["cs"],"Int8" },[]) + | TType ({ t_path = ["cs"],"Int16" },[]) + | TAbstract ({ a_path = ["cs"],"Int16" },[]) + | TType ({ t_path = ["cs"],"UInt16" },[]) + | TAbstract ({ a_path = ["cs"],"UInt16" },[]) + | TType ({ t_path = ["cs"],"Char16" },[]) + | TAbstract ({ a_path = ["cs"],"Char16" },[]) + | TType ({ t_path = ["cs"],"Ref" },_) + | TAbstract ({ a_path = ["cs"],"Ref" },_) + | TType ({ t_path = ["cs"],"Out" },_) + | TAbstract ({ a_path = ["cs"],"Out" },_) + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> Some t + | TType (({ t_path = [],"Null" } as tdef),[t2]) -> + Some (TType(tdef,[follow (gen.gfollow#run_f t2)])) + | TAbstract({ a_path = ["cs"],"PointerAccess" },[t]) -> + Some (TAbstract(ptr,[t])) + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + Some (gen.gfollow#run_f ( Abstract.get_underlying_type a pl) ) + | TAbstract( { a_path = ([], "EnumValue") }, _ ) + | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic + | _ -> None); + + let module_s_params md params = + let md = change_md md in + let path = (t_infos md).mt_path in + match path with + | ([], "String") -> "string", params + | ([], "Null") -> path_s (change_ns md ["haxe"; "lang"], change_clname "Null"), params + | (ns,clname) -> + let ns, params = change_ns_params md params ns in + path_s (ns, change_clname clname), params + in + + let module_s md = + fst (module_s_params md []) + in + + 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 ttype = get_cl ( get_type gen (["System"], "Type") ) in + + let has_tdyn tl = + List.exists (fun t -> match follow t with + | TDynamic _ | TMono _ -> true + | _ -> false + ) tl + in + + let rec real_type t = + let t = gen.gfollow#run_f t in + let ret = match t with + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + real_type (Abstract.get_underlying_type a pl) + | TAbstract ({ a_path = (["cs";"_Flags"], "EnumUnderlying") }, [t]) -> + real_type t + | TInst( { cl_path = (["cs";"system"], "String") }, [] ) -> + gen.gcon.basic.tstring; + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64 + | TAbstract( { a_path = [],"Class" }, _ ) + | TAbstract( { a_path = [],"Enum" }, _ ) + | TAbstract( { a_path = ["haxe";"extern"],"Rest" }, _ ) + | TInst( { cl_path = ([], "Class") }, _ ) + | TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[]) + | TInst( ({ cl_kind = KTypeParameter _ } as cl), _ ) when erase_generics && not (Meta.has Meta.NativeGeneric cl.cl_meta) -> + t_dynamic + | TEnum(_, []) + | TInst(_, []) -> t + | TInst(cl, params) when + has_tdyn params && + Hashtbl.mem ifaces cl.cl_path -> + TInst(Hashtbl.find ifaces cl.cl_path, []) + | TEnum(e, params) -> + TEnum(e, List.map (fun _ -> t_dynamic) params) + | TInst(cl, params) when Meta.has Meta.Enum cl.cl_meta -> + TInst(cl, List.map (fun _ -> t_dynamic) params) + | TInst(cl, params) -> TInst(cl, change_param_type (TClassDecl cl) params) + | TType({ t_path = ([], "Null") }, [t]) -> + (* + Null<> handling is a little tricky. + It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter + It works on cases such as Hash returning Null since cast_detect will invoke real_type at the original type, + Null, which will then return the type haxe.lang.Null<> + *) + if erase_generics then + if is_cs_basic_type t then + t_dynamic + else + real_type t + else + (match real_type t with + | TInst( { cl_kind = KTypeParameter _ }, _ ) -> TInst(null_t, [t]) + | _ when is_cs_basic_type t -> TInst(null_t, [t]) + | _ -> real_type t) + | TAbstract _ + | TType _ -> t + | TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ | AbstractStatics _ -> true | _ -> false) -> t + | TFun _ -> TInst(fn_cl,[]) + | _ -> t_dynamic + in + ret + and + + (* + On hxcs, the only type parameters allowed to be declared are the basic c# types. + That's made like this to avoid casting problems when type parameters in this case + add nothing to performance, since the memory layout is always the same. + + To avoid confusion between Generic (which has a different meaning in hxcs AST), + all those references are using dynamic_anon, which means Generic<{}> + *) + change_param_type md tl = + let types = match md with + | TClassDecl c -> c.cl_params + | TEnumDecl e -> [] + | TAbstractDecl a -> a.a_params + | TTypeDecl t -> t.t_params + in + let is_hxgeneric = if types = [] then is_hxgen md else (TypeParams.RealTypeParams.is_hxgeneric md) in + let ret t = + let t_changed = real_type t in + match is_hxgeneric, t_changed with + | false, _ -> t + (* + Because Null<> types need a special compiler treatment for many operations (e.g. boxing/unboxing), + Null<> type parameters will be transformed into Dynamic. + *) + | true, TInst ( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> dynamic_anon + | true, TInst ( { cl_kind = KTypeParameter _ }, _ ) -> t + | true, TInst _ + | true, TEnum _ + | true, TAbstract _ when is_cs_basic_type t_changed -> t + | true, TDynamic _ -> t + | true, x -> + dynamic_anon + in + if is_hxgeneric && (erase_generics || List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) tl) then + List.map (fun _ -> t_dynamic) tl + else + List.map ret tl + in + + let is_dynamic t = match real_type t with + | TMono _ | TDynamic _ + | TInst({ cl_kind = KTypeParameter _ }, _) -> true + | TAnon anon -> + (match !(anon.a_status) with + | EnumStatics _ | Statics _ -> false + | _ -> true + ) + | _ -> false + in + + let rec t_s t = + match real_type t with + (* basic types *) + | TAbstract ({ a_path = ([], "Bool") },[]) -> "bool" + | TAbstract ({ a_path = ([], "Void") },[]) -> "object" + | TAbstract ({ a_path = ([],"Float") },[]) -> "double" + | TAbstract ({ a_path = ([],"Int") },[]) -> "int" + | TAbstract ({ a_path = [],"UInt" },[]) -> "uint" + | TType ({ t_path = ["cs"], "Int64" },[]) + | TAbstract ({ a_path = ["cs"], "Int64" },[]) -> "long" + | TType ({ t_path = ["cs"],"UInt64" },[]) + | TAbstract ({ a_path = ["cs"],"UInt64" },[]) -> "ulong" + | TType ({ t_path = ["cs"],"UInt8" },[]) + | TAbstract ({ a_path = ["cs"],"UInt8" },[]) -> "byte" + | TType ({ t_path = ["cs"],"Int8" },[]) + | TAbstract ({ a_path = ["cs"],"Int8" },[]) -> "sbyte" + | TType ({ t_path = ["cs"],"Int16" },[]) + | TAbstract ({ a_path = ["cs"],"Int16" },[]) -> "short" + | TType ({ t_path = ["cs"],"UInt16" },[]) + | TAbstract ({ a_path = ["cs"],"UInt16" },[]) -> "ushort" + | TType ({ t_path = ["cs"],"Char16" },[]) + | TAbstract ({ a_path = ["cs"],"Char16" },[]) -> "char" + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> "float" + | TInst ({ cl_path = ["haxe"],"Int32" },[]) + | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int" + | TInst ({ cl_path = ["haxe"],"Int64" },[]) + | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long" + | TInst ({ cl_path = ([], "Dynamic") },_) + | TAbstract ({ a_path = ([], "Dynamic") },_) -> "object" + | TType ({ t_path = ["cs"],"Out" },[t]) + | TAbstract ({ a_path = ["cs"],"Out" },[t]) + | TType ({ t_path = ["cs"],"Ref" },[t]) + | TAbstract ({ a_path = ["cs"],"Ref" },[t]) -> t_s t + | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> + let rec check_t_s t = + match real_type t with + | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> + (check_t_s param) ^ "[]" + | _ -> t_s (run_follow gen t) + in + (check_t_s param) ^ "[]" + | TInst({ cl_path = (["cs"], "Pointer") },[t]) + | TAbstract({ a_path = (["cs"], "Pointer") },[t])-> + let ret = t_s t in + (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)) + | TInst ({ cl_path = [], "String" }, []) -> "string" + | TEnum (e, params) -> ("global::" ^ (module_s (TEnumDecl e))) + | TInst (cl, _ :: _) when Meta.has Meta.Enum cl.cl_meta -> + "global::" ^ module_s (TClassDecl cl) + | TInst (({ cl_path = p } as cl), params) -> (path_param_s (TClassDecl cl) p params) + | TType (({ t_path = p } as t), params) -> (path_param_s (TTypeDecl t) p params) + | TAnon (anon) -> + (match !(anon.a_status) with + | Statics _ | EnumStatics _ -> "System.Type" + | _ -> "object") + | TDynamic _ -> "object" + | 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) ^ " ]" + + and path_param_s md path params = + match params with + | [] -> "global::" ^ module_s md + | _ when erase_generics && is_hxgeneric md -> + "global::" ^ module_s md + | _ -> + let params = (List.map (fun t -> t_s t) (change_param_type md params)) in + let str,params = module_s_params md params in + if params = [] then + "global::" ^ str + else + sprintf "global::%s<%s>" str (String.concat ", " params) + in + + let rett_s t = + match t with + | TAbstract ({ a_path = ([], "Void") },[]) -> "void" + | _ -> t_s t + in + + let escape ichar b = + match ichar with + | 92 (* \ *) -> Buffer.add_string b "\\\\" + | 39 (* ' *) -> Buffer.add_string b "\\\'" + | 34 -> Buffer.add_string b "\\\"" + | 13 (* \r *) -> Buffer.add_string b "\\r" + | 10 (* \n *) -> Buffer.add_string b "\\n" + | 9 (* \t *) -> Buffer.add_string b "\\t" + | c when c < 32 || (c >= 127 && c <= 0xFFFF) -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c) + | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\U%.8x" c) + | c -> Buffer.add_char b (Char.chr c) + in + + let escape s = + let b = Buffer.create 0 in + (try + UTF8.validate s; + UTF8.iter (fun c -> escape (UChar.code c) b) s + with + UTF8.Malformed_code -> + String.iter (fun c -> escape (Char.code c) b) s + ); + Buffer.contents b + in + + let has_semicolon e = + match e.eexpr with + | TBlock _ | TFor _ | TSwitch _ | TTry _ | TIf _ -> false + | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false + | _ -> true + in + + let in_value = ref false in + + let rec md_s md = + let md = follow_module (gen.gfollow#run_f) md in + match md with + | TClassDecl ({ cl_params = [] } as cl) -> + t_s (TInst(cl,[])) + | TClassDecl (cl) when not (is_hxgen md) -> + t_s (TInst(cl,List.map (fun t -> t_dynamic) cl.cl_params)) + | TEnumDecl ({ e_params = [] } as e) -> + t_s (TEnum(e,[])) + | TEnumDecl (e) when not (is_hxgen md) -> + t_s (TEnum(e,List.map (fun t -> t_dynamic) e.e_params)) + | TClassDecl cl -> + t_s (TInst(cl,[])) + | TEnumDecl e -> + t_s (TEnum(e,[])) + | TTypeDecl t -> + t_s (TType(t, List.map (fun t -> t_dynamic) t.t_params)) + | TAbstractDecl a -> + t_s (TAbstract(a, List.map(fun t -> t_dynamic) a.a_params)) + in + + let rec ensure_local e explain = + match e.eexpr with + | TLocal _ -> e + | TCast(e,_) + | TParenthesis e | TMeta(_,e) -> ensure_local e explain + | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e + in + + let rec ensure_refout e explain = + match e.eexpr with + | TField _ | TLocal _ -> e + | TCast(e,_) + | TParenthesis e | TMeta(_,e) -> ensure_refout e explain + | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e + in + + let last_line = ref (-1) in + let begin_block w = write w "{"; push_indent w; newline w; last_line := -1 in + let end_block w = pop_indent w; (if w.sw_has_content then newline w); write w "}"; newline w; last_line := -1 in + let skip_line_directives = (not gen.gcon.debug && not (Common.defined gen.gcon Define.NoCompilation)) || Common.defined gen.gcon Define.RealPosition in + let line_directive = + if skip_line_directives then + fun w p -> () + else fun w p -> + let cur_line = Lexer.get_error_line p in + let file = Common.get_full_path p.pfile in + if cur_line <> ((!last_line)+1) then begin print w "#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end; + last_line := cur_line + in + let line_reset_directive = + if skip_line_directives then + fun w -> () + else fun w -> + print w "#line default" + in + + let rec extract_tparams params el = + match el with + | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl -> + extract_tparams (tp.etype :: params) tl + | _ -> (params, el) + in + + let is_extern_prop t name = match follow (run_follow gen t), field_access gen t name with + | TInst({ cl_interface = true; cl_extern = true } as cl, _), FNotFound -> + not (is_hxgen (TClassDecl cl)) + | _, FClassField(_,_,decl,v,_,t,_) -> + Type.is_extern_field v && (Meta.has Meta.Property v.cf_meta || (decl.cl_extern && not (is_hxgen (TClassDecl decl)))) + | _ -> false + in + + let is_event t name = match follow (run_follow gen t), field_access gen t name with + | TInst({ cl_interface = true; cl_extern = true } as cl, _), FNotFound -> + not (is_hxgen (TClassDecl cl)) + | _, FClassField(_,_,decl,v,_,_,_) -> + Meta.has Meta.Event v.cf_meta + | _ -> false + in + + let extract_statements expr = + let ret = ref [] in + let rec loop expr = match expr.eexpr with + | TCall ({ eexpr = TLocal { + v_name = "__is__" | "__typeof__" | "__array__" | "__sizeof__" | "__delegate__" + } }, el) -> + List.iter loop el + | TNew ({ cl_path = (["cs"], "NativeArray") }, params, [ size ]) -> + () + | TUnop (Ast.Increment, _, _) + | TUnop (Ast.Decrement, _, _) + | TBinop (Ast.OpAssign, _, _) + | TBinop (Ast.OpAssignOp _, _, _) + | TLocal { v_name = "__fallback__" } + | TLocal { v_name = "__sbreak__" } -> + ret := expr :: !ret + | TConst _ + | TLocal _ + | TArray _ + | TBinop _ + | TField _ + | TEnumParameter _ + | TTypeExpr _ + | TObjectDecl _ + | TArrayDecl _ + | TCast _ + | TMeta _ + | TParenthesis _ + | TUnop _ -> + Type.iter loop expr + | TFunction _ -> () (* do not extract parameters from inside of it *) + | _ -> + ret := expr :: !ret + in + loop expr; + (* [expr] *) + List.rev !ret + in + + let expr_s w e = + last_line := -1; + in_value := false; + let rec expr_s w e = + let was_in_value = !in_value in + in_value := true; + (match e.eexpr with + | TCall({ eexpr = TField(ef,f) }, (_ :: _ as args) ) when (field_name f) = "get_Item" -> + expr_s w ef; + write w "["; + let first = ref true in + List.iter (fun f -> + if !first then first := false else write w ", "; + expr_s w f + ) args; + write w "]" + | TCall({ eexpr = TField(ef,f) }, (_ :: _ :: _ as args) ) when (field_name f) = "set_Item" -> + expr_s w ef; + write w "["; + let args, value = match List.rev args with + | v :: args -> List.rev args, v + | _ -> assert false + in + let first = ref true in + List.iter (fun f -> + if !first then first := false else write w ", "; + expr_s w f + ) args; + write w "] = "; + expr_s w value + | TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "add_" -> + let name = field_name f in + let propname = String.sub name 4 (String.length name - 4) in + if is_event (gen.greal_type ef.etype) propname then begin + expr_s w ef; + write w "."; + write_field w propname; + write w " += "; + expr_s w ev + end else + do_call w e [ev] + | TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "remove_" -> + let name = field_name f in + let propname = String.sub name 7 (String.length name - 7) in + if is_event (gen.greal_type ef.etype) propname then begin + expr_s w ef; + write w "."; + write_field w propname; + write w " -= "; + expr_s w ev + end else + do_call w e [ev] + | TCall( ({ eexpr = TField(ef,f) } as e), [] ) when String.starts_with (field_name f) "get_" -> + let name = field_name f in + let propname = String.sub name 4 (String.length name - 4) in + if is_extern_prop (gen.greal_type ef.etype) propname then begin + expr_s w ef; + write w "."; + write_field w propname + end else + do_call w e [] + | TCall( ({ eexpr = TField(ef,f) } as e), [v] ) when String.starts_with (field_name f) "set_" -> + let name = field_name f in + let propname = String.sub name 4 (String.length name - 4) in + if is_extern_prop (gen.greal_type ef.etype) propname then begin + expr_s w ef; + write w "."; + write_field w propname; + write w " = "; + expr_s w v + end else + do_call w e [v] + | TField (e, (FStatic(_, cf) | FInstance(_, _, cf))) when Meta.has Meta.Native cf.cf_meta -> + let rec loop meta = match meta with + | (Meta.Native, [EConst (String s), _],_) :: _ -> + expr_s w e; write w "."; write_field w s + | _ :: tl -> loop tl + | [] -> expr_s w e; write w "."; write_field w (cf.cf_name) + in + loop cf.cf_meta + | TConst c -> + (match c with + | TInt i32 -> + write w (Int32.to_string i32); + (*match real_type e.etype with + | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L"; + | _ -> () + *) + | TFloat s -> + write w s; + (if String.get s (String.length s - 1) = '.' then write w "0"); + (*match real_type e.etype with + | TType( { t_path = ([], "Single") }, [] ) -> write w "f" + | _ -> () + *) + | TString s -> + write w "\""; + write w (escape s); + write w "\"" + | TBool b -> write w (if b then "true" else "false") + | TNull when is_cs_basic_type e.etype || is_tparam e.etype -> + write w "default("; + write w (t_s e.etype); + write w ")" + | TNull -> write w "null" + | TThis -> write w "this" + | TSuper -> write w "base") + | TLocal { v_name = "__sbreak__" } -> write w "break" + | TLocal { v_name = "__undefined__" } -> + write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_params))); + write w ".undefined"; + | TLocal { v_name = "__typeof__" } -> write w "typeof" + | TLocal { v_name = "__sizeof__" } -> write w "sizeof" + | TLocal var -> + write_id w var.v_name + | TField (_, FEnum(e, ef)) -> + let s = ef.ef_name in + print w "%s." ("global::" ^ module_s (TEnumDecl e)); write_field w s + | TArray (e1, e2) -> + expr_s w e1; write w "["; expr_s w e2; write w "]" + | TBinop ((Ast.OpAssign as op), e1, e2) + | TBinop ((Ast.OpAssignOp _ as op), e1, e2) -> + expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2 + | TBinop (op, e1, e2) -> + write w "( "; + expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2; + write w " )" + | TField ({ eexpr = TTypeExpr mt }, s) -> + (match mt with + | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt) + | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt) + | TClassDecl { cl_interface = true } -> + write w ("global::" ^ module_s mt); + write w "__Statics_"; + | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_empty) cl.cl_params))) + | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_empty) en.e_params))) + | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_empty) td.t_params)))) + | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_empty) a.a_params))) + ); + write w "."; + write_field w (field_name s) + | TField (e, s) when is_pointer gen e.etype -> + (* take off the extra cast if possible *) + let e = match e.eexpr with + | TCast(e1,_) when Gencommon.CastDetect.type_iseq gen e.etype e1.etype -> + e1 + | _ -> e + in + expr_s w e; write w "->"; write_field w (field_name s) + | TField (e, s) -> + expr_s w e; write w "."; write_field w (field_name s) + | TTypeExpr mt -> + (match mt with + | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt) + | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt) + | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_empty) cl.cl_params))); + | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_empty) en.e_params))) + | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_empty) td.t_params)))) + | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_empty) a.a_params))) + ) + | TParenthesis e -> + write w "("; expr_s w e; write w ")" + | TMeta (_,e) -> + expr_s w e + | TArrayDecl el + | TCall ({ eexpr = TLocal { v_name = "__array__" } }, el) + | TCall ({ eexpr = TField(_, FStatic({ cl_path = (["cs"],"NativeArray") }, { cf_name = "make" })) }, el) -> + let _, el = extract_tparams [] el in + print w "new %s" (t_s e.etype); + write w "{"; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w "}" + | TCall ({ eexpr = TLocal { v_name = "__delegate__" } }, [del]) -> + expr_s w del + | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> + write w "( "; + expr_s w expr; + write w " is "; + write w (md_s md); + write w " )" + | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> + write w "( "; + expr_s w expr; + write w " as "; + write w (md_s md); + write w " )" + | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, expr :: _ ) -> + write w "( "; + expr_s w expr; + write w " as "; + write w (t_s e.etype); + write w " )"; + | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) -> + write w s + | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, { eexpr = TConst(TString(s)) } :: tl ) -> + Codegen.interpolate_code gen.gcon s tl (write w) (expr_s w) e.epos + | TCall ({ eexpr = TLocal( { v_name = "__stackalloc__" } ) }, [ e ] ) -> + write w "stackalloc byte["; + expr_s w e; + write w "]" + | TCall ({ eexpr = TLocal( { v_name = "__unsafe__" } ) }, [ e ] ) -> + write w "unsafe"; + expr_s w (mk_block e) + | TCall ({ eexpr = TLocal( { v_name = "__checked__" } ) }, [ e ] ) -> + write w "checked"; + expr_s w (mk_block e) + | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) -> + write w "lock("; + expr_s w eobj; + write w ")"; + expr_s w (mk_block eblock) + | TCall ({ eexpr = TLocal( { v_name = "__fixed__" } ) }, [ e ] ) -> + let fixeds = ref [] in + let rec loop = function + | ({ eexpr = TVar(v, Some(e) ) } as expr) :: tl when is_pointer gen v.v_type -> + let e = match get_ptr e with + | None -> e + | Some e -> e + in + fixeds := (v,e,expr) :: !fixeds; + loop tl; + | el when !fixeds <> [] -> + let rec loop fx acc = match fx with + | (v,e,expr) :: tl -> + write w "fixed("; + let vf = mk_temp gen "fixed" v.v_type in + expr_s w { expr with eexpr = TVar(vf, Some e) }; + write w ") "; + begin_block w; + expr_s w { expr with eexpr = TVar(v, Some (mk_local vf expr.epos)) }; + write w ";"; + newline w; + loop tl (acc + 1) + | [] -> acc + in + let nblocks = loop (List.rev !fixeds) 0 in + in_value := false; + expr_s w { e with eexpr = TBlock el }; + for i = 1 to nblocks do + end_block w + done + | _ -> + trace (debug_expr e); + gen.gcon.error "Invalid 'fixed' keyword format" e.epos + in + (match e.eexpr with + | TBlock bl -> loop bl + | _ -> + trace "not block"; + trace (debug_expr e); + gen.gcon.error "Invalid 'fixed' keyword format" e.epos + ) + | TCall ({ eexpr = TLocal( { v_name = "__addressOf__" } ) }, [ e ] ) -> + let e = ensure_local e "for addressOf" in + write w "&"; + expr_s w e + | TCall ({ eexpr = TLocal( { v_name = "__valueOf__" } ) }, [ e ] ) -> + write w "*("; + expr_s w e; + write w ")" + | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> + print w "goto label%ld" v + | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> + print w "label%ld: {}" v + | TCall ({ eexpr = TLocal( { v_name = "__rethrow__" } ) }, _) -> + write w "throw" + (* operator overloading handling *) + | TCall({ eexpr = TField(ef, FInstance(cl,_,{ cf_name = "__get" })) }, [idx]) when not (is_hxgen (TClassDecl cl)) -> + expr_s w { e with eexpr = TArray(ef, idx) } + | TCall({ eexpr = TField(ef, FInstance(cl,_,{ cf_name = "__set" })) }, [idx; v]) when not (is_hxgen (TClassDecl cl)) -> + expr_s w { e with eexpr = TBinop(Ast.OpAssign, { e with eexpr = TArray(ef, idx) }, v) } + | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name binops_names -> + let _, elr = extract_tparams [] el in + (match elr with + | [e1;e2] -> + expr_s w { e with eexpr = TBinop(PMap.find cf.cf_name binops_names, e1, e2) } + | _ -> do_call w e el) + | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name unops_names -> + (match extract_tparams [] el with + | _, [e1] -> + expr_s w { e with eexpr = TUnop(PMap.find cf.cf_name unops_names, Ast.Prefix,e1) } + | _ -> do_call w e el) + | TCall (e, el) -> + do_call w e el + | TNew (({ cl_path = (["cs"], "NativeArray") } as cl), params, [ size ]) -> + let rec check_t_s t times = + match real_type t with + | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> + (check_t_s param (times+1)) + | _ -> + print w "new %s[" (t_s (run_follow gen t)); + expr_s w size; + print w "]"; + let rec loop i = + if i <= 0 then () else (write w "[]"; loop (i-1)) + in + loop (times - 1) + in + check_t_s (TInst(cl, params)) 0 + | TNew ({ cl_path = ([], "String") } as cl, [], el) -> + write w "new "; + write w (t_s (TInst(cl, []))); + write w "("; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w ")" + | TNew ({ cl_kind = KTypeParameter _ } as cl, params, el) -> + print w "default(%s) /* This code should never be reached. It was produced by the use of @:generic on a new type parameter instance: %s */" (t_s (TInst(cl,params))) (path_param_s (TClassDecl cl) cl.cl_path params) + | TNew (cl, params, el) -> + write w "new "; + write w (path_param_s (TClassDecl cl) cl.cl_path params); + write w "("; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w ")" + | TUnop ((Ast.Increment as op), flag, e) + | TUnop ((Ast.Decrement as op), flag, e) -> + (match flag with + | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e + | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op)) + | TUnop (op, flag, e) -> + (match flag with + | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") " + | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op)) + | TVar (var, eopt) -> + print w "%s " (t_s var.v_type); + write_id w var.v_name; + (match eopt with + | None -> + write w " = "; + expr_s w (null var.v_type e.epos) + | Some e -> + write w " = "; + expr_s w e + ) + | TBlock [e] when was_in_value -> + expr_s w e + | TBlock el -> + begin_block w; + List.iter (fun e -> + List.iter (fun e -> + line_directive w e.epos; + in_value := false; + expr_s w e; + (if has_semicolon e then write w ";"); + newline w + ) (extract_statements e) + ) el; + end_block w + | TIf (econd, e1, Some(eelse)) when was_in_value -> + write w "( "; + expr_s w (mk_paren econd); + write w " ? "; + expr_s w (mk_paren e1); + write w " : "; + expr_s w (mk_paren eelse); + write w " )"; + | TIf (econd, e1, eelse) -> + write w "if "; + expr_s w (mk_paren econd); + write w " "; + in_value := false; + expr_s w (mk_block e1); + (match eelse with + | None -> () + | Some e -> + write w "else "; + in_value := false; + let e = match e.eexpr with + | TIf _ -> e + | TBlock [{eexpr = TIf _} as e] -> e + | _ -> mk_block e + in + expr_s w e + ) + | TWhile (econd, eblock, flag) -> + (match flag with + | Ast.NormalWhile -> + write w "while "; + expr_s w (mk_paren econd); + write w " "; + in_value := false; + expr_s w (mk_block eblock) + | Ast.DoWhile -> + write w "do "; + in_value := false; + expr_s w (mk_block eblock); + write w "while "; + in_value := true; + expr_s w (mk_paren econd); + ) + | TSwitch (econd, ele_l, default) -> + write w "switch "; + expr_s w (mk_paren econd); + write w " "; + begin_block w; + List.iter (fun (el, e) -> + List.iter (fun e -> + write w "case "; + in_value := true; + expr_s w e; + write w ":"; + newline w; + ) el; + in_value := false; + expr_s w (mk_block e); + newline w; + newline w + ) ele_l; + if is_some default then begin + write w "default:"; + newline w; + in_value := false; + expr_s w (get default); + newline w; + end; + end_block w + | TTry (tryexpr, ve_l) -> + write w "try "; + in_value := false; + expr_s w (mk_block tryexpr); + List.iter (fun (var, e) -> + print w "catch (%s %s)" (t_s var.v_type) (var.v_name); + in_value := false; + expr_s w (mk_block e); + newline w + ) ve_l + | TReturn eopt -> + write w "return"; + if is_some eopt then (write w " "; expr_s w (get eopt)) + | TBreak -> write w "break" + | TContinue -> write w "continue" + | TThrow e -> + write w "throw "; + expr_s w e + | TCast (e1,md_t) -> + ((*match gen.gfollow#run_f e.etype with + | TType({ t_path = ([], "UInt") }, []) -> + write w "( unchecked ((uint) "; + expr_s w e1; + write w ") )" + | _ ->*) + (* FIXME I'm ignoring module type *) + print w "((%s) (" (t_s e.etype); + expr_s w e1; + write w ") )" + ) + | TFor (_,_,content) -> + 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 + ) + and do_call w e el = + let params, el = extract_tparams [] el in + let params = List.rev params in + + expr_s w e; + + (match params with + | _ :: _ when not (erase_generics && field_is_hxgeneric e) -> + let md = match e.eexpr with + | TField(ef, _) -> + t_to_md (run_follow gen ef.etype) + | _ -> assert false + in + write w "<"; + ignore (List.fold_left (fun acc t -> + (if acc <> 0 then write w ", "); + write w (t_s t); + acc + 1 + ) 0 (change_param_type md params)); + write w ">" + | _ -> () + ); + + let rec loop acc elist tlist = + match elist, tlist with + | e :: etl, (_,_,t) :: ttl -> + (if acc <> 0 then write w ", "); + (match real_type t with + | TType({ t_path = (["cs"], "Ref") }, _) + | TAbstract ({ a_path = (["cs"], "Ref") },_) -> + let e = ensure_refout e "of type cs.Ref" in + write w "ref "; + expr_s w e + | TType({ t_path = (["cs"], "Out") }, _) + | TAbstract ({ a_path = (["cs"], "Out") },_) -> + let e = ensure_refout e "of type cs.Out" in + write w "out "; + expr_s w e + | _ -> + expr_s w e + ); + loop (acc + 1) etl ttl + | e :: etl, [] -> + (if acc <> 0 then write w ", "); + expr_s w e; + loop (acc + 1) etl [] + | _ -> () + in + write w "("; + let ft = match follow e.etype with + | TFun(args,_) -> args + | _ -> [] + in + + loop 0 el ft; + + write w ")" + in + expr_s w e + in + + let rec gen_fpart_attrib w = function + | EConst( Ident i ), _ -> + write w i + | EField( ef, f ), _ -> + gen_fpart_attrib w ef; + write w "."; + write w f + | _, p -> + gen.gcon.error "Invalid expression inside @:meta metadata" p + in + + let rec gen_spart w = function + | EConst c, p -> (match c with + | Int s | Float s | Ident s -> + write w s + | String s -> + write w "\""; + write w (escape s); + write w "\"" + | _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p) + | EField( ef, f ), _ -> + gen_spart w ef; + write w "."; + write w f + | EBinop( Ast.OpAssign, (EConst (Ident s), _), e2 ), _ -> + write w s; + write w " = "; + gen_spart w e2 + | EArrayDecl( el ), _ -> + write w "new[] {"; + let fst = ref true in + List.iter (fun e -> + if !fst then fst := false else write w ", "; + gen_spart w e + ) el; + write w "}" + | ECall(fpart,args), _ -> + gen_fpart_attrib w fpart; + write w "("; + let fst = ref true in + List.iter (fun e -> + if !fst then fst := false else write w ", "; + gen_spart w e + ) args; + write w ")" + | _, p -> + gen.gcon.error "Invalid expression inside @:meta metadata" p + in + + let gen_attributes w metadata = + List.iter (function + | Meta.Meta, [EConst(String s), _], _ -> + write w "["; + write w s; + write w "]"; + newline w + | Meta.Meta, [meta], _ -> + write w "["; + gen_spart w meta; + write w "]"; + newline w + | _ -> () + ) metadata + in + + let gen_nocompletion w metadata = + if Meta.has Meta.NoCompletion metadata then begin + write w "[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]"; + newline w + end; + in + + let argt_s t = + let w = new_source_writer () in + let rec run t = + match t with + | TType (tdef,p) -> + gen_attributes w tdef.t_meta; + run (follow_once t) + | TMono r -> + (match !r with + | Some t -> run t + | _ -> () (* avoid infinite loop / should be the same in this context *)) + | TLazy f -> + run (!f()) + | _ -> () + in + run t; + let ret = match run_follow gen t with + | TType ({ t_path = (["cs"], "Ref") }, [t]) + | TAbstract ({ a_path = (["cs"], "Ref") },[t]) -> "ref " ^ t_s t + | TType ({ t_path = (["cs"], "Out") }, [t]) + | TAbstract ({ a_path = (["cs"], "Out") },[t]) -> "out " ^ t_s t + | t -> t_s t + in + let c = contents w in + if c <> "" then + c ^ " " ^ ret + else + ret + in + + let get_string_params cl cl_params = + 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 params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> get_param_name tcl) cl_params)) in + let params_extends = + if hxgen + (* this is temprorary, see https://github.com/HaxeFoundation/haxe/issues/3526 *) + || not (Meta.has (Meta.Custom ":nativeTypeConstraints") cl.cl_meta) + then + [""] + else + List.fold_left (fun acc (name, t) -> + match run_follow gen t with + | TInst({cl_kind = KTypeParameter constraints}, _) when constraints <> [] -> + (* base class should come before interface constraints *) + let base_class_constraints = ref [] in + let other_constraints = List.fold_left (fun acc t -> + match follow t with + (* string is implicitly sealed, maybe haxe should have it final as well *) + | TInst ({ cl_path=[],"String" }, []) -> + acc + + (* non-sealed class *) + | TInst ({ cl_interface = false; cl_meta = meta},_) when not (Meta.has Meta.Final meta) -> + base_class_constraints := (t_s t) :: !base_class_constraints; + acc; + + (* interface *) + | TInst ({ cl_interface = true}, _) -> + (t_s t) :: acc + + (* skip anything other *) + | _ -> + acc + ) [] constraints in + + let s_constraints = (!base_class_constraints @ other_constraints) in + if s_constraints <> [] then + (sprintf " where %s : %s" (get_param_name t) (String.concat ", " s_constraints) :: acc) + else + acc; + | _ -> acc + ) [] cl_params in + (params, String.concat " " params_extends) + | _ -> ("","") + in + + let gen_field_decl w visibility v_n modifiers t n = + let parts = ref [] in + if visibility <> "" then parts := visibility :: !parts; + if v_n <> "" then parts := v_n :: !parts; + if modifiers <> [] then parts := modifiers @ !parts; + if t <> "" then parts := t :: !parts; + parts := n :: !parts; + write w (String.concat " " (List.rev !parts)); + in + + let rec gen_event w is_static cl (event,t,custom,add,remove) = + let is_interface = cl.cl_interface in + let visibility = if is_interface then "" else "public" in + let visibility, modifiers = get_fun_modifiers event.cf_meta visibility ["event"] in + let v_n = if is_static then "static" else "" in + gen_field_decl w visibility v_n modifiers (t_s (run_follow gen t)) (change_field event.cf_name); + if custom && not is_interface then begin + write w " "; + begin_block w; + print w "add { _add_%s(value); }" event.cf_name; + newline w; + print w "remove { _remove_%s(value); }" event.cf_name; + newline w; + end_block w; + newline w; + end else + write w ";\n"; + newline w; + in + + let rec gen_prop w is_static cl is_final (prop,t,get,set) = + gen_attributes w prop.cf_meta; + let is_interface = cl.cl_interface in + let fn_is_final = function + | None -> true + | Some ({ cf_kind = Method mkind } as m) -> + (match mkind with | MethInline -> true | _ -> false) || Meta.has Meta.Final m.cf_meta + | _ -> assert false + in + let is_virtual = not (is_interface || is_final || Meta.has Meta.Final prop.cf_meta || fn_is_final get || fn_is_final set) in + + let fn_is_override = function + | Some cf -> List.memq cf cl.cl_overrides + | None -> false + in + let is_override = fn_is_override get || fn_is_override set in + let visibility = if is_interface then "" else "public" in + let visibility, modifiers = get_fun_modifiers prop.cf_meta visibility [] 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 + gen_nocompletion w prop.cf_meta; + + gen_field_decl w visibility v_n modifiers (t_s (run_follow gen t)) (change_field prop.cf_name); + + let check cf = match cf with + | Some ({ cf_overloads = o :: _ } as cf) -> + gen.gcon.error "Property functions with more than one overload is currently unsupported" cf.cf_pos; + gen.gcon.error "Property functions with more than one overload is currently unsupported" o.cf_pos + | _ -> () + in + check get; + check set; + + write w " "; + if is_interface then begin + write w "{ "; + let s = ref "" in + (match prop.cf_kind with Var { v_read = AccCall } -> write w "get;"; s := " "; | _ -> ()); + (match prop.cf_kind with Var { v_write = AccCall } -> print w "%sset;" !s | _ -> ()); + write w " }"; + newline w; + end else begin + begin_block w; + (match get with + | Some cf -> + print w "get { return _get_%s(); }" prop.cf_name; + newline w; + cf.cf_meta <- (Meta.Custom "?prop_impl", [], null_pos) :: cf.cf_meta; + | None -> ()); + (match set with + | Some cf -> + print w "set { _set_%s(value); }" prop.cf_name; + newline w; + cf.cf_meta <- (Meta.Custom "?prop_impl", [], null_pos) :: cf.cf_meta; + | None -> ()); + end_block w; + newline w; + newline w; + end; + in + + let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf = + gen_attributes w cf.cf_meta; + let is_interface = cl.cl_interface in + let name, is_new, is_explicit_iface = match cf.cf_name with + | "new" -> snd cl.cl_path, true, false + | name when String.contains name '.' -> + let fn_name, path = parse_explicit_iface name in + (path_s path) ^ "." ^ fn_name, false, true + | name -> try + let binop = PMap.find name binops_names in + "operator " ^ s_binop binop, false, false + with | Not_found -> try + let unop = PMap.find name unops_names in + "operator " ^ s_unop unop, false, false + with | Not_found -> + if Meta.has (Meta.Custom "?prop_impl") cf.cf_meta || Meta.has (Meta.Custom "?event_impl") cf.cf_meta then + "_" ^ name, false, false + else + name, false, false + in + let rec loop_static cl = + match is_static, cl.cl_super with + | false, _ -> [] + | true, None -> [] + | true, Some(cl,_) -> + (try + let cf2 = PMap.find cf.cf_name cl.cl_statics in + Gencommon.CastDetect.type_eq gen EqStrict cf.cf_type cf2.cf_type; + ["new"] + with + | Not_found | Unify_error _ -> + loop_static cl + ) + in + let modf = loop_static cl in + + (match cf.cf_kind with + | Var _ + | Method (MethDynamic) when not (Type.is_extern_field cf) -> + (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then + gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos); + if not is_interface then begin + let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in + let modifiers = modifiers @ modf in + gen_nocompletion w cf.cf_meta; + gen_field_decl w access (if is_static then "static" else "") modifiers (t_s (run_follow gen cf.cf_type)) (change_field name); + (match cf.cf_expr with + | Some e -> + write w " = "; + expr_s w e; + | None -> () + ); + write w ";" + end (* TODO see how (get,set) variable handle when they are interfaces *) + | Method _ when Type.is_extern_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 + gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf + ) cf.cf_overloads + | Var _ | Method MethDynamic -> () + | Method mkind -> + List.iter (fun cf -> + if cl.cl_interface || cf.cf_expr <> None then + gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf + ) cf.cf_overloads; + let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in + let is_virtual = if not is_virtual || Meta.has Meta.Final cf.cf_meta then false else is_virtual in + let is_override = List.memq cf cl.cl_overrides in + let is_override = is_override || match cf.cf_name, follow cf.cf_type with + | "Equals", TFun([_,_,targ], tret) -> + (match follow targ, follow tret with + | TDynamic _, TAbstract({ a_path = ([], "Bool") }, []) -> true + | _ -> false) + | "GetHashCode", TFun([],_) -> true + | _ -> false + in + let is_override = if Meta.has (Meta.Custom "?prop_impl") cf.cf_meta then false else is_override in + + let is_virtual = is_virtual && not (Meta.has Meta.Final cl.cl_meta) && not (is_interface) in + let visibility = if is_interface then "" else "public" in + + let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in + 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 + gen_nocompletion w cf.cf_meta; + + (* public static void funcName *) + gen_field_decl w visibility v_n modifiers (if not is_new then (rett_s (run_follow gen ret_type)) else "") (change_field name); + + let params, params_ext = get_string_params cl cf.cf_params in + (* (string arg1, object arg2) with T : object *) + (match cf.cf_expr with + | Some { eexpr = TFunction tf } -> + print w "%s(%s)%s" (params) (String.concat ", " (List.map2 (fun (var, _) (_,_,t) -> sprintf "%s %s" (argt_s t) (change_id var.v_name)) tf.tf_args args)) (params_ext) + | _ -> + print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s t) (change_id name)) args)) (params_ext) + ); + if is_interface then + write w ";" + else begin + write w " "; + let rec loop meta = + match meta with + | [] -> + let expr = match cf.cf_expr with + | None -> mk (TBlock([])) t_dynamic Ast.null_pos + | Some s -> + match s.eexpr with + | TFunction tf -> + mk_block (tf.tf_expr) + | _ -> assert false (* FIXME *) + in + + let needs_unchecked e = + let rec loop e = match e.eexpr with + (* a non-zero integer constant means that we want unchecked context *) + | TConst (TInt i) when i <> Int32.zero -> + raise Exit + + (* don't recurse into explicit checked blocks *) + | TCall ({ eexpr = TLocal({ v_name = "__checked__" }) }, _) -> + () + + (* skip reflection field hashes as they are safe *) + | TNew ({ cl_path = (["haxe"; "lang"],"DynamicObject") }, [], [_; e1; _; e2]) -> + loop e1; + loop e2 + | TNew ({ cl_path = (["haxe"; "lang"],"Closure") }, [], [eo; _; _]) -> + loop eo + | TCall ({ eexpr = TField (_, FStatic ({ cl_path = ["haxe"; "lang"],"Runtime" }, + { cf_name = "getField" | "setField" | "getField_f" | "setField_f" | "callField" })) }, + eo :: _ :: _ :: rest) -> + loop eo; + List.iter loop rest + + | _ -> + Type.iter loop e + in + try (loop e; false) with Exit -> true + in + let write_method_expr e = + match e.eexpr with + | TBlock [] -> + begin_block w; + end_block w + | TBlock _ -> + let unchecked = needs_unchecked e in + if unchecked then (begin_block w; write w "unchecked "); + let t = Common.timer "expression to string" in + expr_s w e; + t(); + line_reset_directive w; + if unchecked then end_block w + | _ -> + assert false + in + + (if is_new then begin + let rec get_super_call el = + match el with + | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest -> + Some call, rest + | ( { eexpr = TBlock(bl) } as block ) :: rest -> + let ret, mapped = get_super_call bl in + ret, ( { block with eexpr = TBlock(mapped) } :: rest ) + | _ -> + None, el + in + match expr.eexpr with + | TBlock(bl) -> + let super_call, rest = get_super_call bl in + (match super_call with + | None -> () + | Some sc -> + write w ": "; + let t = Common.timer "expression to string" in + expr_s w sc; + write w " "; + t() + ); + write_method_expr { expr with eexpr = TBlock(rest) } + | _ -> assert false + end else + write_method_expr expr + ) + | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> + begin_block w; + write w contents; + end_block w + | _ :: tl -> loop tl + in + loop cf.cf_meta + + end); + newline w; + newline w; + in + + let check_special_behaviors w cl = match cl.cl_kind with + | KAbstractImpl _ -> () + | _ -> + (* get/set pairs *) + let pairs = ref PMap.empty in + (try + let get = PMap.find "__get" cl.cl_fields in + List.iter (fun cf -> + let args,ret = get_fun cf.cf_type in + match args with + | [_,_,idx] -> pairs := PMap.add (t_s idx) ( t_s ret, Some cf, None ) !pairs + | _ -> gen.gcon.warning "The __get function must have exactly one argument (the index)" cf.cf_pos + ) (get :: get.cf_overloads) + with | Not_found -> ()); + (try + let set = PMap.find "__set" cl.cl_fields in + List.iter (fun cf -> + let args, ret = get_fun cf.cf_type in + match args with + | [_,_,idx; _,_,v] -> (try + let vt, g, _ = PMap.find (t_s idx) !pairs in + let tvt = t_s v in + if vt <> tvt then gen.gcon.warning "The __get function of same index has a different type from this __set function" cf.cf_pos; + pairs := PMap.add (t_s idx) (vt, g, Some cf) !pairs + with | Not_found -> + pairs := PMap.add (t_s idx) (t_s v, None, Some cf) !pairs) + | _ -> + gen.gcon.warning "The __set function must have exactly two arguments (index, value)" cf.cf_pos + ) (set :: set.cf_overloads) + with | Not_found -> ()); + PMap.iter (fun idx (v, get, set) -> + print w "public %s this[%s index]" v idx; + begin_block w; + (match get with + | None -> () + | Some _ -> + write w "get"; + begin_block w; + write w "return this.__get(index);"; + end_block w); + (match set with + | None -> () + | Some _ -> + write w "set"; + begin_block w; + write w "this.__set(index,value);"; + end_block w); + end_block w) !pairs; + (if not (PMap.is_empty !pairs) then try + let get = PMap.find "__get" cl.cl_fields in + 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 + in + List.iter (fun (cl,args) -> + match cl.cl_array_access with + | None -> () + | Some t -> + let changed_t = apply_params cl.cl_params (List.map (fun _ -> t_dynamic) cl.cl_params) t in + let t_as_s = t_s (run_follow gen changed_t) in + print w "%s %s.this[int key]" t_as_s (t_s (TInst(cl, args))); + begin_block w; + write w "get"; + begin_block w; + print w "return ((%s) this.__get(key));" t_as_s; + end_block w; + write w "set"; + begin_block w; + print w "this.__set(key, (%s) value);" v_t; + end_block w; + end_block w; + newline w; + newline w + ) cl.cl_implements + with | Not_found -> ()); + if cl.cl_interface && is_hxgen (TClassDecl cl) && is_some cl.cl_array_access then begin + let changed_t = apply_params cl.cl_params (List.map (fun _ -> t_dynamic) cl.cl_params) (get cl.cl_array_access) in + print w "%s this[int key]" (t_s (run_follow gen changed_t)); + begin_block w; + write w "get;"; + newline w; + write w "set;"; + newline w; + end_block w; + newline w; + newline w + end; + (try + if cl.cl_interface then raise Not_found; + let cf = PMap.find "toString" cl.cl_fields in + (if List.exists (fun c -> c.cf_name = "toString") cl.cl_overrides then raise Not_found); + (match cf.cf_type with + | TFun([], ret) -> + (match real_type ret with + | TInst( { cl_path = ([], "String") }, []) -> + write w "public override string ToString()"; + begin_block w; + write w "return this.toString();"; + end_block w; + newline w; + newline w + | _ -> + gen.gcon.error "A toString() function should return a String!" cf.cf_pos + ) + | _ -> () + ) + with | Not_found -> ()); + (try + if cl.cl_interface then raise Not_found; + let cf = PMap.find "finalize" cl.cl_fields in + (if List.exists (fun c -> c.cf_name = "finalize") cl.cl_overrides then raise Not_found); + (match cf.cf_type with + | TFun([], ret) -> + (match real_type ret with + | TAbstract( { a_path = ([], "Void") }, []) -> + write w "~"; + write w (snd cl.cl_path); + write w "()"; + begin_block w; + write w "this.finalize();"; + end_block w; + newline w; + newline w + | _ -> + gen.gcon.error "A finalize() function should be Void->Void!" cf.cf_pos + ) + | _ -> () + ) + with | Not_found -> ()); + (* properties *) + let handle_prop static f = + match f.cf_kind with + | Method _ -> () + | Var v when not (Type.is_extern_field f) -> () + | Var v -> + let prop acc = match acc with + | AccNo | AccNever | AccCall -> true + | _ -> false + in + if prop v.v_read && prop v.v_write && (v.v_read = AccCall || v.v_write = AccCall) then begin + let this = if static then + mk_classtype_access cl f.cf_pos + else + { eexpr = TConst TThis; etype = TInst(cl,List.map snd cl.cl_params); epos = f.cf_pos } + in + print w "public %s%s %s" (if static then "static " else "") (t_s f.cf_type) (netname_to_hx f.cf_name); + begin_block w; + (match v.v_read with + | AccCall -> + write w "get"; + begin_block w; + write w "return "; + expr_s w this; + print w ".get_%s();" f.cf_name; + end_block w + | _ -> ()); + (match v.v_write with + | AccCall -> + write w "set"; + begin_block w; + expr_s w this; + print w ".set_%s(value);" f.cf_name; + end_block w + | _ -> ()); + end_block w; + end + in + if Meta.has Meta.BridgeProperties cl.cl_meta then begin + List.iter (handle_prop true) cl.cl_ordered_statics; + List.iter (handle_prop false) cl.cl_ordered_fields; + end + in + + let gen_class w cl = + 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 + | ns -> + print w "namespace %s " (String.concat "." ns); + begin_block w; + true + in + + (try + let _,m,_ = Meta.get (Meta.Custom "generic_iface") cl.cl_meta in + let rec loop i acc = + if i == 0 then + acc + else + "object" :: (loop (pred i) acc) + in + let tparams = loop (match m with [(EConst(Int s),_)] -> int_of_string s | _ -> assert false) [] in + cl.cl_meta <- (Meta.Meta, [ + EConst(String("global::haxe.lang.GenericInterface(typeof(global::" ^ module_s (TClassDecl cl) ^ "<" ^ String.concat ", " tparams ^ ">))") ), cl.cl_pos + ], cl.cl_pos) :: cl.cl_meta + with Not_found -> + ()); + + 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); + expr_s w { eexpr = TTypeExpr(TClassDecl cl); etype = t_dynamic; epos = Ast.null_pos }; + write w ".main();"; + end_block w; + end_block w; + newline w; + false + | Some path when path = cl.cl_path && not cl.cl_interface -> true + | _ -> false + in + + let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in + let is_final = clt = "struct" || Meta.has Meta.Final cl.cl_meta in + + let modifiers = [access] @ modifiers in + print w "%s %s %s" (String.concat " " modifiers) clt (change_clname (snd cl.cl_path)); + (* type parameters *) + let params, params_ext = get_string_params cl cl.cl_params in + let extends_implements = (match cl.cl_super with | None -> [] | Some (cl,p) -> [path_param_s (TClassDecl cl) cl.cl_path p]) @ (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements) in + (match extends_implements with + | [] -> print w "%s%s " params params_ext + | _ -> print w "%s : %s%s " params (String.concat ", " extends_implements) params_ext); + (* class head ok: *) + (* public class Test : X, Y, Z where A : Y *) + 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;*) + + let rec loop meta = + match meta with + | [] -> () + | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> + write w contents + | _ :: tl -> loop tl + in + loop cl.cl_meta; + + if is_main then begin + 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); + write w "main();"; + end_block w + end; + + (match cl.cl_init with + | None -> () + | Some init -> + print w "static %s() " (snd cl.cl_path); + expr_s w (mk_block init); + line_reset_directive w; + newline w; + newline w + ); + + (* collect properties and events *) + let partition cf cflist = + let events, props, nonprops = ref [], ref [], ref [] in + + List.iter (fun v -> match v.cf_kind with + | Var { v_read = AccCall } | Var { v_write = AccCall } when Type.is_extern_field v && Meta.has Meta.Property v.cf_meta -> + props := (v.cf_name, ref (v, v.cf_type, None, None)) :: !props; + | Var { v_read = AccNormal; v_write = AccNormal } when Meta.has Meta.Event v.cf_meta -> + if v.cf_public then gen.gcon.error "@:event fields must be private" v.cf_pos; + v.cf_meta <- (Meta.SkipReflection, [], null_pos) :: v.cf_meta; + events := (v.cf_name, ref (v, v.cf_type, false, None, None)) :: !events; + | _ -> + nonprops := v :: !nonprops; + ) cflist; + + let events, nonprops = !events, !nonprops in + + let t = TInst(cl, List.map snd cl.cl_params) in + let find_prop name = try + List.assoc name !props + with | Not_found -> match field_access gen t name with + | FClassField (_,_,decl,v,_,t,_) when is_extern_prop (TInst(cl,List.map snd cl.cl_params)) name -> + let ret = ref (v,t,None,None) in + props := (name, ret) :: !props; + ret + | _ -> raise Not_found + in + + let find_event name = List.assoc name events in + + let is_empty_function cf = match cf.cf_expr with + | Some {eexpr = TFunction { tf_expr = {eexpr = TBlock []}}} -> true + | _ -> false + in + + let interf = cl.cl_interface in + (* get all functions that are getters/setters *) + let nonprops = List.filter (function + | cf when String.starts_with cf.cf_name "get_" -> (try + (* find the property *) + let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in + let v, t, get, set = !prop in + assert (get = None); + prop := (v,t,Some cf,set); + not interf + with | Not_found -> true) + | cf when String.starts_with cf.cf_name "set_" -> (try + (* find the property *) + let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in + let v, t, get, set = !prop in + assert (set = None); + prop := (v,t,get,Some cf); + not interf + with | Not_found -> true) + | cf when String.starts_with cf.cf_name "add_" -> (try + let event = find_event (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in + let v, t, _, add, remove = !event in + assert (add = None); + cf.cf_meta <- (Meta.Custom "?event_impl", [], null_pos) :: cf.cf_meta; + let custom = not (is_empty_function cf) in + event := (v, t, custom, Some cf, remove); + false + with | Not_found -> true) + | cf when String.starts_with cf.cf_name "remove_" -> (try + let event = find_event (String.sub cf.cf_name 7 (String.length cf.cf_name - 7)) in + let v, t, _, add, remove = !event in + assert (remove = None); + cf.cf_meta <- (Meta.Custom "?event_impl", [], null_pos) :: cf.cf_meta; + let custom = not (is_empty_function cf) in + event := (v, t, custom, add, Some cf); + false + with | Not_found -> true) + | _ -> true + ) nonprops in + + let nonprops = ref nonprops in + List.iter (fun (n,r) -> + let ev, t, custom, add, remove = !r in + let tmeth = (tfun [t] basic.tvoid) in + match add, remove with + | None, _ -> + gen.gcon.error ("Missing event method add_" ^ n) ev.cf_pos; + failwith "Build failed" + | _, None -> + gen.gcon.error ("Missing event method remove_" ^ n) ev.cf_pos; + failwith "Build failed" + | Some add, Some remove -> + let check cf = try + type_eq EqStrict cf.cf_type tmeth + with Unify_error el -> + List.iter (fun e -> gen.gcon.error (Typecore.unify_error_msg (print_context()) e) cf.cf_pos) el; + failwith "Build failed"; + in + check add; + check remove; + if custom && not cl.cl_interface then + nonprops := add :: remove :: !nonprops + ) events; + + let evts = List.map (fun(_,v) -> !v) events in + let ret = List.map (fun (_,v) -> !v) !props in + let ret = List.filter (function | (_,_,None,None) -> false | _ -> true) ret in + evts, ret, List.rev !nonprops + in + + let fevents, fprops, fnonprops = partition cl cl.cl_ordered_fields in + let sevents, sprops, snonprops = partition cl cl.cl_ordered_statics in + (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor)); + if not cl.cl_interface then begin + (* we don't want to generate properties for abstract implementation classes, because they don't have object to work with *) + List.iter (gen_event w true cl) sevents; + if (match cl.cl_kind with KAbstractImpl _ -> false | _ -> true) then List.iter (gen_prop w true cl is_final) sprops; + List.iter (gen_class_field w true cl is_final) snonprops + end; + List.iter (gen_event w false cl) fevents; + List.iter (gen_prop w false cl is_final) fprops; + List.iter (gen_class_field w false cl is_final) fnonprops; + check_special_behaviors w cl; + end_block w; + if cl.cl_interface && cl.cl_ordered_statics <> [] then begin + print w "public class %s__Statics_" (snd cl.cl_path); + begin_block w; + List.iter (gen_class_field w true { cl with cl_interface = false } is_final) cl.cl_ordered_statics; + end_block w + end; + if should_close then end_block w + in + + + let gen_enum w e = + let should_close = match change_ns (TEnumDecl e) (fst e.e_path) with + | [] -> false + | ns -> + print w "namespace %s" (String.concat "." ns); + begin_block w; + true + in + gen_attributes w e.e_meta; + + print w "public enum %s" (change_clname (snd e.e_path)); + begin_block w; + write w (String.concat ", " (List.map (change_id) e.e_names)); + end_block w; + + if should_close then end_block w + in + + let module_type_gen w md_tp = + reset_temps(); + match md_tp with + | TClassDecl cl -> + if not cl.cl_extern then begin + (if no_root && len w = 0 then write w "using haxe.root;\n"; newline w;); + gen_class w cl; + newline w; + newline w + end; + (not cl.cl_extern) + | TEnumDecl e -> + if not e.e_extern && not (Meta.has Meta.Class e.e_meta) then begin + (if no_root && len w = 0 then write w "using haxe.root;\n"; newline w;); + gen_enum w e; + newline w; + newline w + end; + (not e.e_extern) + | TAbstractDecl _ + | TTypeDecl _ -> + false + in + + let module_gen w md_def = + List.fold_left (fun should md -> module_type_gen w md || should) false md_def.m_types + in + + (* generate source code *) + init_ctx gen; + + Hashtbl.add gen.gspecial_vars "__rethrow__" true; + Hashtbl.add gen.gspecial_vars "__typeof__" true; + Hashtbl.add gen.gspecial_vars "__label__" true; + Hashtbl.add gen.gspecial_vars "__goto__" true; + Hashtbl.add gen.gspecial_vars "__is__" true; + Hashtbl.add gen.gspecial_vars "__as__" true; + Hashtbl.add gen.gspecial_vars "__cs__" true; + + Hashtbl.add gen.gspecial_vars "__checked__" true; + Hashtbl.add gen.gspecial_vars "__lock__" true; + Hashtbl.add gen.gspecial_vars "__fixed__" true; + Hashtbl.add gen.gspecial_vars "__unsafe__" true; + Hashtbl.add gen.gspecial_vars "__addressOf__" true; + Hashtbl.add gen.gspecial_vars "__valueOf__" true; + Hashtbl.add gen.gspecial_vars "__sizeof__" true; + Hashtbl.add gen.gspecial_vars "__stackalloc__" true; + + Hashtbl.add gen.gspecial_vars "__delegate__" true; + Hashtbl.add gen.gspecial_vars "__array__" true; + Hashtbl.add gen.gspecial_vars "__ptr__" true; + + Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true); + let last_needs_box = gen.gneeds_box in + gen.gneeds_box <- (fun t -> match (gen.greal_type t) with + | TAbstract( ( { a_path = ["cs"], "Pointer" }, _ ) ) + | TInst( { cl_path = ["cs"], "Pointer" }, _ ) + | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true + | _ -> last_needs_box t); + + gen.greal_type <- real_type; + gen.greal_type_param <- change_param_type; + + SetHXGen.run_filter gen SetHXGen.default_hxgen_func; + + (* before running the filters, follow all possible types *) + (* this is needed so our module transformations don't break some core features *) + (* like multitype selection *) + let run_follow_gen = run_follow gen in + let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen) (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in + let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in + List.iter (function + | TClassDecl cl -> + let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in + List.iter (fun cf -> + cf.cf_type <- run_follow_gen cf.cf_type; + cf.cf_expr <- Option.map type_map cf.cf_expr; + + (* add @:skipReflection to @:event vars *) + match cf.cf_kind with + | Var _ when (Meta.has Meta.Event cf.cf_meta) && not (Meta.has Meta.SkipReflection cf.cf_meta) -> + cf.cf_meta <- (Meta.SkipReflection, [], null_pos) :: cf.cf_meta; + | _ -> () + + ) all_fields; + cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic; + cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access; + cl.cl_init <- Option.map type_map cl.cl_init; + cl.cl_super <- Option.map super_map cl.cl_super; + cl.cl_implements <- List.map super_map cl.cl_implements + | _ -> () + ) gen.gtypes_list; + + let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in + + (*let closure_t = ClosuresToClass.create gen 10 float_cl + (fun l -> l) + (fun l -> l) + (fun args -> args) + (fun args -> []) + in + ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e)); + + StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*) + + let tp_v = alloc_var "$type_param" t_dynamic in + let mk_tp t pos = { eexpr = TLocal(tp_v); etype = t; epos = pos } in + TypeParams.configure gen (fun ecall efield params elist -> + match efield.eexpr with + | TField(_, FEnum _) -> + { ecall with eexpr = TCall(efield, elist) } + | _ -> + { ecall with eexpr = TCall(efield, (List.map (fun t -> mk_tp t ecall.epos ) params) @ elist) } + ); + + if not erase_generics then HardNullableSynf.configure gen (HardNullableSynf.traverse gen + (fun e -> + match real_type e.etype with + | TInst({ cl_path = (["haxe";"lang"], "Null") }, [t]) -> + 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 + ) + (fun v t has_value -> + match has_value, real_type v.etype with + | true, TDynamic _ | true, TAnon _ | true, TMono _ -> + { + eexpr = TCall(mk_static_field_access_infer null_t "ofDynamic" v.epos [t], [mk_tp t v.epos; v]); + etype = TInst(null_t, [t]); + epos = v.epos + } + | _ -> + { eexpr = TNew(null_t, [t], [gen.ghandle_cast t v.etype v; { eexpr = TConst(TBool has_value); etype = gen.gcon.basic.tbool; epos = v.epos } ]); etype = TInst(null_t, [t]); epos = v.epos } + ) + (fun e -> + { + eexpr = TCall( + { (mk_field_access gen { (mk_paren e) with etype = real_type e.etype } "toDynamic" e.epos) with etype = TFun([], t_dynamic) }, + []); + etype = t_dynamic; + epos = e.epos + } + ) + (fun e -> + mk_field_access gen { e with etype = real_type e.etype } "hasValue" e.epos + ) + (fun e1 e2 -> + { + eexpr = TCall( + mk_field_access gen e1 "Equals" e1.epos, + [e2]); + etype = basic.tbool; + epos = e1.epos; + } + ) + true + false + ); + + + let explicit_fn_name c tl fname = + path_param_s (TClassDecl c) c.cl_path tl ^ "." ^ fname + in + + FixOverrides.configure ~explicit_fn_name:explicit_fn_name ~get_vmtype:real_type gen; + Normalize.configure gen ~metas:(Hashtbl.create 0); + + AbstractImplementationFix.configure gen; + + IteratorsInterface.configure gen (fun e -> e); + + OverrideFix.configure gen; + + ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) )); + + let enum_base = (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) in + let param_enum_base = (get_cl (get_type gen (["haxe";"lang"],"ParamEnum")) ) in + EnumToClass.configure gen (Some (fun e -> mk_cast gen.gcon.basic.tint e)) true true enum_base param_enum_base false false; + + InterfaceVarsDeleteModf.configure gen; + InterfaceProps.configure gen; + + let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in + + let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in + + (*fixme: THIS IS A HACK. take this off *) + let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in + (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*) + + let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in + let empty_ef = + try + PMap.find "EMPTY" empty_e.e_constrs + with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false + in + OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen; + + let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in + let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in + + let rcf_static_insert, rcf_static_remove = + if erase_generics then begin + 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 + in + (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("insert" ^ get_specialized_postfix t) Ast.null_pos []), + (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("remove" ^ get_specialized_postfix t) Ast.null_pos []) + end else + (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "insert" Ast.null_pos [t]), + (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "remove" Ast.null_pos [t]) + in + + let can_be_float = like_float in + + let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe = + let is_float = can_be_float (real_type main_expr.etype) in + let fn_name = if is_some may_set then "setField" else "getField" in + let fn_name = if is_float then fn_name ^ "_f" else fn_name in + let pos = field_expr.epos in + + let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in + + let should_cast = match main_expr.etype with | TAbstract({ a_path = ([], "Float") }, []) -> false | _ -> true in + let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in + let first_args = + [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ] + @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else [] + in + let args = first_args @ match is_float, may_set with + | true, Some(set) -> + [ if should_cast then mk_cast basic.tfloat set else set ] + | false, Some(set) -> + [ set ] + | _ -> + [ is_unsafe ] + in + + let call = { main_expr with eexpr = TCall(infer,args) } in + let call = if is_float && should_cast then mk_cast main_expr.etype call else call in + call + in + + let rcf_on_call_field ecall field_expr field may_hash args = + let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in + + let hash_arg = match may_hash with + | None -> [] + | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ] + in + + let arr_call = if args <> [] then + { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos } + else + null (basic.tarray t_dynamic) ecall.epos + in + + let call_args = + [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ] + @ hash_arg + @ [ arr_call ] + in + + mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args) } + in + + if not erase_generics then + handle_type_params gen ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject"))) + else begin + add_cast_handler gen; + TypeParams.RealTypeParams.RealTypeParamsModf.configure gen (TypeParams.RealTypeParams.RealTypeParamsModf.set_only_hxgeneric gen) + end; + + let rcf_ctx = + ReflectionCFs.new_ctx + gen + closure_t + object_iface + true + rcf_on_getset_field + rcf_on_call_field + (fun hash hash_array length -> { hash with eexpr = TCall(rcf_static_find, [hash; hash_array; length]); etype=basic.tint }) + (fun hash -> { hash with eexpr = TCall(rcf_static_lookup, [hash]); etype = gen.gcon.basic.tstring }) + (fun hash_array length pos value -> + let ecall = mk (TCall(rcf_static_insert value.etype, [hash_array; length; pos; value])) (if erase_generics then hash_array.etype else basic.tvoid) hash_array.epos in + if erase_generics then { ecall with eexpr = TBinop(OpAssign, hash_array, ecall) } else ecall + ) + (fun hash_array length pos -> + let t = gen.gclasses.nativearray_type hash_array.etype in + { hash_array with eexpr = TCall(rcf_static_remove t, [hash_array; length; pos]); etype = gen.gcon.basic.tvoid } + ) + false + in + + ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object; + + ReflectionCFs.configure_dynamic_field_access rcf_ctx false; + + (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *) + let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in + let varargs_cl = get_cl (get_type gen (["haxe";"lang"],"VarArgsFunction")) in + let dynamic_name = gen.gmk_internal_name "hx" "invokeDynamic" in + + List.iter (fun cl -> + List.iter (fun cf -> + if cf.cf_name = dynamic_name then cl.cl_overrides <- cf :: cl.cl_overrides + ) cl.cl_ordered_fields + ) [closure_cl; varargs_cl]; + + let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in + + ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) ); + + let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in + ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> { + eexpr = TCall(slow_invoke, [ethis; efield; eargs]); + etype = t_dynamic; + epos = ethis.epos; + } ) object_iface; + + let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in + + ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn); + + InitFunction.configure gen true true; + TArrayTransform.configure gen (TArrayTransform.default_implementation gen ( + fun e binop -> + match e.eexpr with + | TArray(e1, e2) -> + (match follow e1.etype with + | TDynamic _ | TAnon _ | TMono _ -> true + | TInst({ cl_kind = KTypeParameter _ }, _) -> true + | TInst(c,p) when erase_generics && is_hxgeneric (TClassDecl c) && is_hxgen (TClassDecl c) -> (match c.cl_path with + | [],"String" + | ["cs"],"NativeArray" -> false + | _ -> + true) + | _ -> match binop, change_param_type (t_to_md e1.etype) [e.etype] with + | Some(Ast.OpAssignOp _), ([TDynamic _] | [TAnon _]) -> + true + | _ -> false) + | _ -> assert false + ) "__get" "__set" ); + + let field_is_dynamic t field = + match field_access_esp gen (gen.greal_type t) field with + | FEnumField _ -> false + | FClassField (cl,p,_,_,_,t,_) -> + if not erase_generics then + false + else + let p = change_param_type (TClassDecl cl) p in + is_dynamic (apply_params cl.cl_params p t) + | _ -> true + in + + let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with + | TField(tf, f) -> field_is_dynamic tf.etype (f) + | _ -> false + in + + let may_nullable t = match gen.gfollow#run_f t with + | TType({ t_path = ([], "Null") }, [t]) -> + (match follow t with + | TInst({ cl_path = ([], "String") }, []) + | TAbstract ({ a_path = ([], "Float") },[]) + | TInst({ cl_path = (["haxe"], "Int32")}, [] ) + | TInst({ cl_path = (["haxe"], "Int64")}, [] ) + | TAbstract ({ a_path = ([], "Int") },[]) + | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t + | TAbstract _ when like_float t -> Some t + | t when is_cs_basic_type t -> Some t + | _ -> None ) + | _ -> None + in + + let is_double t = like_float t && not (like_int t) in + let is_int t = like_int t in + + let is_null t = match real_type t with + | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true + | _ -> false + in + + let is_null_expr e = is_null e.etype || match e.eexpr with + | TField(tf, f) -> (match field_access_esp gen (real_type tf.etype) (f) with + | FClassField(_,_,_,_,_,actual_t,_) -> is_null actual_t + | _ -> false) + | _ -> false + in + + let should_handle_opeq t = + match real_type t with + | TDynamic _ | TAnon _ | TMono _ + | TInst( { cl_kind = KTypeParameter _ }, _ ) + | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true + | _ -> false + in + + let string_cl = match gen.gcon.basic.tstring with + | TInst(c,[]) -> c + | _ -> assert false + in + + let is_undefined e = match e.eexpr with + | TLocal { v_name = "__undefined__" } | TField(_,FStatic({cl_path=["haxe";"lang"],"Runtime"},{cf_name="undefined"})) -> true + | _ -> false + in + + DynamicOperators.configure gen + (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with + | TBinop (Ast.OpEq, e1, e2) + | TBinop (Ast.OpNotEq, e1, e2) -> + ( + (* dont touch (v == null) and (null == v) comparisons because they are handled by HardNullableSynf later *) + match e1.eexpr, e2.eexpr with + | TConst(TNull), _ when (not (is_tparam e2.etype) && is_dynamic e2.etype) || is_null_expr e2 -> + false + | _, TConst(TNull) when (not (is_tparam e1.etype) && is_dynamic e1.etype) || is_null_expr e1 -> + false + | _ when is_undefined e1 || is_undefined e2 -> + false + | _ -> + should_handle_opeq e1.etype || should_handle_opeq e2.etype + ) + | TBinop (Ast.OpAssignOp Ast.OpAdd, e1, e2) -> + is_dynamic_expr e1 || is_null_expr e1 || is_string e.etype + | TBinop (Ast.OpAdd, e1, e2) -> is_dynamic e1.etype || is_dynamic e2.etype || is_tparam e1.etype || is_tparam e2.etype || is_string e1.etype || is_string e2.etype || is_string e.etype + | TBinop (Ast.OpLt, e1, e2) + | TBinop (Ast.OpLte, e1, e2) + | TBinop (Ast.OpGte, e1, e2) + | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 || is_string e1.etype || is_string e2.etype + | TBinop (_, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 + | TUnop (_, _, e1) -> is_dynamic_expr e1 || is_null_expr e1 (* we will see if the expression is Null also, as the unwrap from Unop will be the same *) + | _ -> false) + (fun e1 e2 -> + let is_basic = is_cs_basic_type (follow e1.etype) || is_cs_basic_type (follow e2.etype) in + let is_ref = if is_basic then false else match follow e1.etype, follow e2.etype with + | TDynamic _, _ + | _, TDynamic _ + | TInst( { cl_path = ([], "String") }, [] ), _ + | _, TInst( { cl_path = ([], "String") }, [] ) + | TInst( { cl_kind = KTypeParameter _ }, [] ), _ + | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false + | _, _ -> true + in + + let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in + { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos } + ) + (fun e e1 e2 -> + match may_nullable e1.etype, may_nullable e2.etype with + | Some t1, Some t2 -> + let t1, t2 = if is_string t1 || is_string t2 then + basic.tstring, basic.tstring + else if is_double t1 || is_double t2 then + basic.tfloat, basic.tfloat + else if is_int t1 || is_int t2 then + basic.tint, basic.tint + else t1, t2 in + { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos } + | _ when is_string e.etype || is_string e1.etype || is_string e2.etype -> + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "concat" e.epos [], + [ e1; e2 ] + ); + etype = basic.tstring; + epos = e.epos + } + | _ -> + let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in + mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos }) + (fun e1 e2 -> + if is_string e1.etype then begin + { e1 with eexpr = TCall(mk_static_field_access_infer string_cl "Compare" e1.epos [], [ e1; e2 ]); etype = gen.gcon.basic.tint } + end else begin + let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in + { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos } + end) ~handle_strings:false); + + FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func); + + let base_exception = get_cl (get_type gen (["System"], "Exception")) in + let base_exception_t = TInst(base_exception, []) in + + let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in + let hx_exception_t = TInst(hx_exception, []) in + + let rec is_exception t = + match follow t with + | TInst(cl,_) -> + if cl == base_exception then + true + else + (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg))) + | _ -> false + in + + TryCatchWrapper.configure gen + ( + TryCatchWrapper.traverse gen + (fun t -> not (is_exception (real_type t))) + (fun throwexpr expr -> + let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in + { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid } + ) + (fun v_to_unwrap pos -> + let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in + mk_field_access gen local "obj" pos + ) + (fun rethrow -> + { rethrow with eexpr = TCall(mk_local (alloc_var "__rethrow__" t_dynamic) rethrow.epos, [rethrow]); etype = gen.gcon.basic.tvoid } + ) + (base_exception_t) + (hx_exception_t) + (fun v e -> + + let exc_cl = get_cl (get_type gen (["haxe";"lang"],"Exceptions")) in + let exc_field = mk_static_field_access_infer exc_cl "exception" e.epos [] in + let esetstack = mk (TBinop(Ast.OpAssign, exc_field, mk_local v e.epos)) v.v_type e.epos in + + Type.concat esetstack e; + ) + ); + + let get_typeof e = + { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) } + in + + ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> + get_typeof e + )); + + CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) (not erase_generics) ~native_string_cast:false ~overloads_cast_to_base:true); + + (*FollowAll.configure gen;*) + + SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e -> + match e.eexpr with + | TSwitch(cond, cases, def) -> + (match gen.gfollow#run_f cond.etype with + | TAbstract ({ a_path = ([], "Int") },[]) + | TInst({ cl_path = ([], "String") },[]) -> + (List.exists (fun (c,_) -> + List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c + ) cases) + | _ -> true + ) + | _ -> assert false + ) true ) ; + + ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVar(mk_temp gen "expr" e.etype, Some e); etype = gen.gcon.basic.tvoid; epos = e.epos })); + + UnnecessaryCastsRemoval.configure gen; + + IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true); + + UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true false); + + ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl); + + let goto_special = alloc_var "__goto__" t_dynamic in + let label_special = alloc_var "__label__" t_dynamic in + SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen + (fun e_loop n api -> + api ({ eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos }) false; + e_loop + ) + (fun e_break n api -> + { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos } + ) + ); + + DefaultArguments.configure gen (DefaultArguments.traverse gen); + InterfaceMetas.configure gen; + + CSharpSpecificSynf.configure gen (CSharpSpecificSynf.traverse gen runtime_cl); + CSharpSpecificESynf.configure gen (CSharpSpecificESynf.traverse gen runtime_cl); + + let out_files = ref [] in + + (* copy resource files *) + if Hashtbl.length gen.gcon.resources > 0 then begin + let src = + gen.gcon.file ^ "/src/Resources" + in + Hashtbl.iter (fun name v -> + let name = Codegen.escape_res_name name true in + let full_path = src ^ "/" ^ name in + mkdir_from_path full_path; + + let f = open_out_bin full_path in + output_string f v; + close_out f; + + out_files := (unique_full_path full_path) :: !out_files + ) gen.gcon.resources; + end; + (* add resources array *) + (try + let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in + let cf = PMap.find "content" res.cl_statics in + let res = ref [] in + Hashtbl.iter (fun name v -> + res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res; + ) gen.gcon.resources; + cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos }) + with | Not_found -> ()); + + run_filters gen; + (* after the filters have been run, add all hashed fields to FieldLookup *) + + let normalize_i i = + let i = Int32.of_int (i) in + if i < Int32.zero then + Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30) + else i + in + + let nhash = ref 0 in + let hashes = Hashtbl.fold (fun i s acc -> incr nhash; (normalize_i i,s) :: acc) rcf_ctx.rcf_hash_fields [] in + let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in + + let flookup_cl = get_cl (get_type gen (["haxe";"lang"], "FieldLookup")) in + let haxe_libs = List.filter (function (_,_,_,lookup) -> is_some (lookup (["haxe";"lang"], "DceNo"))) gen.gcon.net_libs in + (try + (* first let's see if we're adding a -net-lib that has already a haxe.lang.FieldLookup *) + let name,_,_,_ = List.find (function (_,_,_,lookup) -> is_some (lookup (["haxe";"lang"], "FieldLookup"))) gen.gcon.net_libs in + if not (Common.defined gen.gcon Define.DllImport) then begin + gen.gcon.warning ("The -net-lib with path " ^ name ^ " contains a Haxe-generated assembly. Please define `-D dll_import` to handle Haxe-generated dll import correctly") null_pos; + raise Not_found + end; + if not (List.exists (function (n,_,_,_) -> n = name) haxe_libs) then + gen.gcon.warning ("The -net-lib with path " ^ name ^ " contains a Haxe-generated assembly, however it wasn't compiled with `-dce no`. Recompilation with `-dce no` is recommended") null_pos; + (* it has; in this case, we need to add the used fields on each __init__ *) + flookup_cl.cl_extern <- true; + let hashs_by_path = Hashtbl.create !nhash in + Hashtbl.iter (fun (path,i) s -> Hashtbl.add hashs_by_path path (i,s)) rcf_ctx.rcf_hash_paths; + Hashtbl.iter (fun _ md -> match md with + | TClassDecl ({ cl_extern = false; cl_interface = false } as c) -> (try + let all = Hashtbl.find_all hashs_by_path c.cl_path in + let all = List.map (fun (i,s) -> normalize_i i, s) all in + let all = List.sort (fun (i,s) (i2,s2) -> compare i i2) all in + + if all <> [] then begin + let add = mk_static_field_access_infer flookup_cl "addFields" c.cl_pos [] in + let expr = { eexpr = TCall(add, [ + mk_nativearray_decl gen basic.tint (List.map (fun (i,s) -> { eexpr = TConst(TInt (i)); etype = basic.tint; epos = c.cl_pos }) all) c.cl_pos; + mk_nativearray_decl gen basic.tstring (List.map (fun (i,s) -> { eexpr = TConst(TString (s)); etype = basic.tstring; epos = c.cl_pos }) all) c.cl_pos; + ]); etype = basic.tvoid; epos = c.cl_pos } in + match c.cl_init with + | None -> c.cl_init <- Some expr + | Some e -> + c.cl_init <- Some { eexpr = TBlock([expr;e]); etype = basic.tvoid; epos = e.epos } + end + with | Not_found -> ()) + | _ -> ()) gen.gtypes; + + with | Not_found -> try + let basic = gen.gcon.basic in + let cl = flookup_cl in + let field_ids = PMap.find "fieldIds" cl.cl_statics in + let fields = PMap.find "fields" cl.cl_statics in + + field_ids.cf_expr <- Some (mk_nativearray_decl gen basic.tint (List.map (fun (i,s) -> { eexpr = TConst(TInt (i)); etype = basic.tint; epos = field_ids.cf_pos }) hashes) field_ids.cf_pos); + fields.cf_expr <- Some (mk_nativearray_decl gen basic.tstring (List.map (fun (i,s) -> { eexpr = TConst(TString s); etype = basic.tstring; epos = fields.cf_pos }) hashes) fields.cf_pos); + + with | Not_found -> + gen.gcon.error "Fields 'fieldIds' and 'fields' were not found in class haxe.lang.FieldLookup" flookup_cl.cl_pos + ); + + if Common.defined gen.gcon Define.DllImport then begin + Hashtbl.iter (fun _ md -> match md with + | TClassDecl ({ cl_extern = false } as c) -> (try + let extra = match c.cl_params with + | _ :: _ when not erase_generics -> "_" ^ string_of_int (List.length c.cl_params) + | _ -> "" + in + let pack = match c.cl_path with + | ([], _) when no_root && is_hxgen (TClassDecl c) -> + ["haxe";"root"] + | (p,_) -> p + in + let path = (pack, snd c.cl_path ^ extra) in + ignore (List.find (function (_,_,_,lookup) -> + is_some (lookup path)) haxe_libs); + c.cl_extern <- true; + with | Not_found -> ()) + | _ -> ()) gen.gtypes + end; + + TypeParams.RenameTypeParameters.run gen; + + let t = Common.timer "code generation" in + + let parts = Str.split_delim (Str.regexp "[\\/]+") gen.gcon.file in + mkdir_recursive "" parts; + generate_modules gen "cs" "src" module_gen out_files; + + if not (Common.defined gen.gcon Define.KeepOldOutput) then + clean_files (gen.gcon.file ^ "/src") !out_files gen.gcon.verbose; + + dump_descriptor gen ("hxcs_build.txt") path_s module_s; if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin let old_dir = Sys.getcwd() in Sys.chdir gen.gcon.file; - let cmd = "haxelib run hxcs hxcs_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) in + let cmd = "haxelib run hxcs hxcs_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) ^ " --feature-level 1" in print_endline cmd; if gen.gcon.run_command cmd <> 0 then failwith "Build failed"; Sys.chdir old_dir; end; - t() + t() (* end of configure function *) -let before_generate con = - () - let generate con = - (try - let gen = new_ctx con in - let basic = con.basic in - - (* make the basic functions in C# *) - let type_cl = get_cl ( get_type gen (["System"], "Type")) in - let basic_fns = - [ - mk_class_field "Equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) []; - mk_class_field "ToString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) []; - mk_class_field "GetHashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) []; - mk_class_field "GetType" (TFun([], TInst(type_cl, []))) true Ast.null_pos (Method MethNormal) []; - ] in - List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns; - configure gen - with | TypeNotFound path -> - con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos); - debug_mode := false - + (try + + let gen = new_ctx con in + let basic = con.basic in + + if Common.defined_value con Define.Dce = "no" then begin + let m = { null_module with m_id = alloc_mid(); m_path = ["haxe";"lang"],"DceNo" } in + let cl = mk_class m (["haxe";"lang"],"DceNo") null_pos in + gen.gtypes_list <- (TClassDecl cl) :: gen.gtypes_list; + Hashtbl.add gen.gtypes cl.cl_path (TClassDecl cl) + end; + + (* make the basic functions in C# *) + let type_cl = get_cl ( get_type gen (["System"], "Type")) in + let basic_fns = + [ + mk_class_field "Equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "ToString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "GetHashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "GetType" (TFun([], TInst(type_cl, []))) true Ast.null_pos (Method MethNormal) []; + ] in + List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns; + configure gen + with | TypeNotFound path -> + con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos); + debug_mode := false + +(* -net-lib implementation *) +open IlData +open IlMeta + +type net_lib_ctx = { + nstd : bool; + ncom : Common.context; + nil : IlData.ilctx; +} + +let is_haxe_keyword = function + | "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true + | _ -> false + +let hxpath_to_net ctx path = + try + Hashtbl.find ctx.ncom.net_path_map path + with + | Not_found -> + [],[],"Not_found" + +let add_cs = function + | "haxe" :: ns -> "haxe" :: ns + | "std" :: ns -> "std" :: ns + | "cs" :: ns -> "cs" :: ns + | "system" :: ns -> "cs" :: "system" :: ns + | ns -> ns + +let escape_chars = + String.replace_chars (fun chr -> + if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' then + Char.escaped chr + else + "_x" ^ (string_of_int (Char.code chr)) ^ "_") + +let netcl_to_hx cl = + let cl = if String.length cl > 0 && String.get cl 0 >= 'a' && String.get cl 0 <= 'z' then + Char.escaped (Char.uppercase (String.get cl 0)) ^ (String.sub cl 1 (String.length cl - 1)) + else + cl + in + try + let cl, nargs = String.split cl "`" in + (escape_chars cl) ^ "_" ^ nargs + with | Invalid_string -> + escape_chars cl + +let netpath_to_hx std = function + | [],[], cl -> [], netcl_to_hx cl + | ns,[], cl -> + let ns = (List.map (fun s -> String.lowercase (escape_chars s)) ns) in + add_cs ns, netcl_to_hx cl + | ns,(nhd :: ntl as nested), cl -> + let nested = List.map (netcl_to_hx) nested in + let ns = (List.map (fun s -> String.lowercase (escape_chars s)) ns) @ [nhd] in + add_cs ns, String.concat "_" nested ^ "_" ^ netcl_to_hx cl + +let lookup_ilclass std com ilpath = + let path = netpath_to_hx std ilpath in + List.fold_right (fun (_,_,_,get_raw_class) acc -> + match acc with + | None -> get_raw_class path + | Some p -> acc + ) com.net_libs None + +let discard_nested = function + | (ns,_),cl -> (ns,[]),cl + +let mk_type_path ctx path params = + let pack, sub, name = match path with + | ns,[], cl -> + ns, None, netcl_to_hx cl + | ns, (nhd :: ntl as nested), cl -> + let nhd = netcl_to_hx nhd in + let nested = List.map (netcl_to_hx) nested in + ns, Some (String.concat "_" nested ^ "_" ^ netcl_to_hx cl), nhd + in + CTPath { + tpackage = fst (netpath_to_hx ctx.nstd (pack,[],"")); + Ast.tname = name; + tparams = params; + tsub = sub; + } + +let raw_type_path ctx path params = + { + tpackage = fst path; + Ast.tname = snd path; + tparams = params; + tsub = None; + } + +let rec convert_signature ctx p = function + | LVoid -> + mk_type_path ctx ([],[],"Void") [] + | LBool -> + mk_type_path ctx ([],[],"Bool") [] + | LChar -> + mk_type_path ctx (["cs";"types"],[],"Char16") [] + | LInt8 -> + mk_type_path ctx (["cs";"types"],[],"Int8") [] + | LUInt8 -> + mk_type_path ctx (["cs";"types"],[],"UInt8") [] + | LInt16 -> + mk_type_path ctx (["cs";"types"],[],"Int16") [] + | LUInt16 -> + mk_type_path ctx (["cs";"types"],[],"UInt16") [] + | LInt32 -> + mk_type_path ctx ([],[],"Int") [] + | LUInt32 -> + mk_type_path ctx ([],[],"UInt") [] + | LInt64 -> + mk_type_path ctx (["haxe"],[],"Int64") [] + | LUInt64 -> + mk_type_path ctx (["cs";"types"],[],"UInt64") [] + | LFloat32 -> + mk_type_path ctx ([],[],"Single") [] + | LFloat64 -> + mk_type_path ctx ([],[],"Float") [] + | LString -> + mk_type_path ctx (["std"],[],"String") [] + | LObject -> + mk_type_path ctx ([],[],"Dynamic") [] + | LPointer s | LManagedPointer s -> + mk_type_path ctx (["cs"],[],"Pointer") [ TPType (convert_signature ctx p s) ] + | LTypedReference -> + mk_type_path ctx (["cs";"system"],[],"TypedReference") [] + | LIntPtr -> + mk_type_path ctx (["cs";"system"],[],"IntPtr") [] + | LUIntPtr -> + mk_type_path ctx (["cs";"system"],[],"UIntPtr") [] + | LValueType (s,args) | LClass (s,args) -> + mk_type_path ctx s (List.map (fun s -> TPType (convert_signature ctx p s)) args) + | LTypeParam i -> + mk_type_path ctx ([],[],"T" ^ string_of_int i) [] + | LMethodTypeParam i -> + mk_type_path ctx ([],[],"M" ^ string_of_int i) [] + | LVector s -> + mk_type_path ctx (["cs"],[],"NativeArray") [TPType (convert_signature ctx p s)] + (* | LArray of ilsig_norm * (int option * int option) array *) + | LMethod (_,ret,args) -> + CTFunction (List.map (convert_signature ctx p) args, convert_signature ctx p ret) + | _ -> mk_type_path ctx ([],[], "Dynamic") [] + +let ilpath_s = function + | ns,[], name -> path_s (ns,name) + | [],nested,name -> String.concat "." nested ^ "." ^ name + | ns, nested, name -> String.concat "." ns ^ "." ^ String.concat "." nested ^ "." ^ name + +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 + List.exists (fun a -> + match a.ca_type with + | TypeRef r -> + check_flag r.tr_name r.tr_namespace + | TypeDef d -> + check_flag d.td_name d.td_namespace + | Method m -> + (match m.m_declaring with + | Some d -> + check_flag d.td_name d.td_namespace + | _ -> false) + | MemberRef r -> + (match r.memr_class with + | TypeRef r -> + check_flag r.tr_name r.tr_namespace + | TypeDef d -> + check_flag d.td_name d.td_namespace + | _ -> false) + | _ -> + false + ) ilcls.cattrs + +let convert_ilenum ctx p ?(is_flag=false) ilcls = + let meta = ref [ + Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p; + Meta.CsNative, [], p; + ] in + + let data = ref [] in + List.iter (fun f -> match f.fname with + | "value__" -> () + | _ when not (List.mem CStatic f.fflags.ff_contract) -> () + | _ -> + let meta, const = match f.fconstant with + | Some IChar i + | Some IByte i + | Some IShort i -> + [Meta.CsNative, [EConst (Int (string_of_int i) ), p], p ], Int64.of_int i + | Some IInt i -> + [Meta.CsNative, [EConst (Int (Int32.to_string i) ), p], p ], Int64.of_int32 i + | Some IFloat32 f | Some IFloat64 f -> + [], Int64.of_float f + | Some IInt64 i -> + [], i + | _ -> + [], Int64.zero + in + data := ( { ec_name = f.fname; ec_doc = None; ec_meta = meta; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; }, const) :: !data; + ) ilcls.cfields; + let data = List.stable_sort (fun (_,i1) (_,i2) -> Int64.compare i1 i2) (List.rev !data) in + + let _, c = netpath_to_hx ctx.nstd ilcls.cpath in + let name = netname_to_hx c in + EEnum { + d_name = if is_flag then name ^ "_FlagsEnum" else name; + d_doc = None; + d_params = []; (* enums never have type parameters *) + d_meta = !meta; + d_flags = [EExtern]; + d_data = List.map fst data; + } + +let rec has_unmanaged = function + | LPointer _ -> true + | LManagedPointer s -> has_unmanaged s + | LValueType (p,pl) -> List.exists (has_unmanaged) pl + | LClass (p,pl) -> List.exists (has_unmanaged) pl + | LVector s -> has_unmanaged s + | LArray (s,a) -> has_unmanaged s + | LMethod (c,r,args) -> has_unmanaged r || List.exists (has_unmanaged) args + | _ -> false + +let convert_ilfield ctx p field = + if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged field.fsig.snorm then raise Exit; + let p = { p with pfile = p.pfile ^" (" ^field.fname ^")" } in + let cff_doc = None in + let cff_pos = p in + let cff_meta = ref [] in + let cff_name = match field.fname with + | name when String.length name > 5 -> + (match String.sub name 0 5 with + | "__hx_" -> raise Exit + | _ -> name) + | name -> name + in + let cff_access = match field.fflags.ff_access with + | FAFamily | FAFamOrAssem -> APrivate + | FAPublic -> APublic + | _ -> raise Exit (* private instances aren't useful on externs *) + in + let readonly, acc = List.fold_left (fun (readonly,acc) -> function + | CStatic -> readonly, AStatic :: acc + | CInitOnly | CLiteral -> true, acc + | _ -> readonly,acc + ) (false,[cff_access]) field.fflags.ff_contract in + if PMap.mem "net_loader_debug" ctx.ncom.defines then + Printf.printf "\t%sfield %s : %s\n" (if List.mem AStatic acc then "static " else "") cff_name (IlMetaDebug.ilsig_s field.fsig.ssig); + let kind = match readonly with + | true -> + FProp ("default", "never", Some (convert_signature ctx p field.fsig.snorm), None) + | false -> + FVar (Some (convert_signature ctx p field.fsig.snorm), None) + in + let cff_name, cff_meta = + if String.get cff_name 0 = '%' then + let name = (String.sub cff_name 1 (String.length cff_name - 1)) in + "_" ^ name, + (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta + else + cff_name, !cff_meta + in + { + cff_name = cff_name; + cff_doc = cff_doc; + cff_pos = cff_pos; + cff_meta = cff_meta; + cff_access = acc; + cff_kind = kind; + } + +let convert_ilevent ctx p ev = + let p = { p with pfile = p.pfile ^" (" ^ev.ename ^")" } in + let name = ev.ename in + let kind = FVar (Some (convert_signature ctx p ev.esig.snorm), None) in + let meta = [Meta.Event, [], p; Meta.Keep,[],p; Meta.SkipReflection,[],p] in + let acc = [APrivate] in + let add_m acc m = match m with + | None -> acc + | Some (name,flags) -> + if List.mem (CMStatic) flags.mf_contract then + AStatic :: acc + else + acc + in + if PMap.mem "net_loader_debug" ctx.ncom.defines then + Printf.printf "\tevent %s : %s\n" name (IlMetaDebug.ilsig_s ev.esig.ssig); + let acc = add_m acc ev.eadd in + let acc = add_m acc ev.eremove in + let acc = add_m acc ev.eraise in + { + cff_name = name; + cff_doc = None; + cff_pos = p; + cff_meta = meta; + cff_access = acc; + cff_kind = kind; + } + +let convert_ilmethod ctx p m is_explicit_impl = + if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged m.msig.snorm then raise Exit; + let force_check = Common.defined ctx.ncom Define.ForceLibCheck in + let p = { p with pfile = p.pfile ^" (" ^m.mname ^")" } in + let cff_doc = None in + let cff_pos = p in + let cff_name = match m.mname with + | ".ctor" -> "new" + | ".cctor"-> raise Exit (* __init__ field *) + | "Equals" | "GetHashCode" -> raise Exit + | name when String.length name > 5 -> + (match String.sub name 0 5 with + | "__hx_" -> raise Exit + | _ -> name) + | name -> name + in + let acc = match m.mflags.mf_access with + | FAFamily | FAFamOrAssem -> APrivate + (* | FAPrivate -> APrivate *) + | FAPublic when List.mem SGetter m.msemantics || List.mem SSetter m.msemantics -> + APrivate + | FAPublic -> APublic + | _ -> + if PMap.mem "net_loader_debug" ctx.ncom.defines then + Printf.printf "\tmethod %s (skipped) : %s\n" cff_name (IlMetaDebug.ilsig_s m.msig.ssig); + raise Exit + in + let is_static = ref false in + let acc, is_final = List.fold_left (fun (acc,is_final) -> function + | CMStatic when cff_name <> "new" -> is_static := true; AStatic :: acc, is_final + | CMVirtual when is_final = None -> acc, Some false + | CMFinal -> acc, Some true + | _ -> acc, is_final + ) ([acc],None) m.mflags.mf_contract in + if PMap.mem "net_loader_debug" ctx.ncom.defines then + Printf.printf "\t%smethod %s : %s\n" (if !is_static then "static " else "") cff_name (IlMetaDebug.ilsig_s m.msig.ssig); + + let meta = [Meta.Overload, [], p] in + let meta = match is_final with + | None | Some true when not force_check -> + (Meta.Final,[],p) :: meta + | _ -> + meta + in + let meta = if is_explicit_impl then + (Meta.NoCompletion,[],p) :: (Meta.SkipReflection,[],p) :: meta + else + meta + in + (* let meta = if List.mem OSynchronized m.mflags.mf_interop then *) + (* (Meta.Synchronized,[],p) :: meta *) + (* else *) + (* meta *) + (* in *) + + let rec change_sig = function + | LManagedPointer s -> LManagedPointer (change_sig s) + | LPointer s -> LPointer (change_sig s) + | LValueType (p,pl) -> LValueType(p, List.map change_sig pl) + | LClass (p,pl) -> LClass(p, List.map change_sig pl) + | LTypeParam i -> LObject + | LVector s -> LVector (change_sig s) + | LArray (s,a) -> LArray (change_sig s, a) + | LMethod (c,r,args) -> LMethod (c, change_sig r, List.map change_sig args) + | p -> p + in + let change_sig = if !is_static then change_sig else (fun s -> s) in + + let ret = + if String.length cff_name > 4 && String.sub cff_name 0 4 = "set_" then + match m.mret.snorm, m.margs with + | LVoid, [_,_,s] -> + s.snorm + | _ -> m.mret.snorm + else + m.mret.snorm + in + + let kind = + let args = List.map (fun (name,flag,s) -> + let t = match s.snorm with + | LManagedPointer s -> + let is_out = List.mem POut flag.pf_io && not (List.mem PIn flag.pf_io) in + let name = if is_out then "Out" else "Ref" in + mk_type_path ctx (["cs"],[],name) [ TPType (convert_signature ctx p s) ] + | _ -> + convert_signature ctx p (change_sig s.snorm) + in + name,false,Some t,None) m.margs + in + let ret = convert_signature ctx p (change_sig ret) in + let types = List.map (fun t -> + { + tp_name = "M" ^ string_of_int t.tnumber; + tp_params = []; + tp_constraints = []; + } + ) m.mtypes in + FFun { + f_params = types; + f_args = args; + f_type = Some ret; + f_expr = None; + } + in + let cff_name, cff_meta = + if String.get cff_name 0 = '%' then + let name = (String.sub cff_name 1 (String.length cff_name - 1)) in + "_" ^ name, + (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: meta + else + cff_name, meta + in + let acc = match m.moverride with + | None -> acc + | _ when cff_name = "new" -> acc + | Some (path,s) -> match lookup_ilclass ctx.nstd ctx.ncom path with + | Some ilcls when not (List.mem SInterface ilcls.cflags.tdf_semantics) -> + AOverride :: acc + | None when ctx.ncom.verbose -> + prerr_endline ("(net-lib) A referenced assembly for path " ^ ilpath_s path ^ " was not found"); + acc + | _ -> acc + in + { + cff_name = cff_name; + cff_doc = cff_doc; + cff_pos = cff_pos; + cff_meta = cff_meta; + cff_access = acc; + cff_kind = kind; + } + +let convert_ilprop ctx p prop is_explicit_impl = + if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged prop.psig.snorm then raise Exit; + let p = { p with pfile = p.pfile ^" (" ^prop.pname ^")" } in + let pmflags = match prop.pget, prop.pset with + | Some(_,fl1), _ -> Some fl1 + | _, Some(_,fl2) -> Some fl2 + | _ -> None + in + let cff_access = match pmflags with + | Some { mf_access = FAFamily | FAFamOrAssem } -> APrivate + | Some { mf_access = FAPublic } -> APublic + | _ -> raise Exit (* non-public / protected fields don't interest us *) + in + let access acc = acc.mf_access in + let cff_access = match pmflags with + | Some m when List.mem CMStatic m.mf_contract -> + [AStatic;cff_access] + | _ -> [cff_access] + in + let get = match prop.pget with + | None -> "never" + | Some(s,_) when String.length s <= 4 || String.sub s 0 4 <> "get_" -> + raise Exit (* special (?) getter; not used *) + | Some(_,m) when access m <> FAPublic -> (match access m with + | FAFamily + | FAFamOrAssem -> "null" + | _ -> "never") + | Some _ -> "get" + in + let set = match prop.pset with + | None -> "never" + | Some(s,_) when String.length s <= 4 || String.sub s 0 4 <> "set_" -> + raise Exit (* special (?) getter; not used *) + | Some(_,m) when access m <> FAPublic -> (match access m with + | FAFamily + | FAFamOrAssem -> "null" + | _ -> "never"); + | Some _ -> "set" + in + if PMap.mem "net_loader_debug" ctx.ncom.defines then + Printf.printf "\tproperty %s (%s,%s) : %s\n" prop.pname get set (IlMetaDebug.ilsig_s prop.psig.ssig); + let ilsig = match prop.psig.snorm with + | LMethod (_,ret,[]) -> ret + | s -> raise Exit + in + + let meta = if is_explicit_impl then + [ Meta.NoCompletion,[],p; Meta.SkipReflection,[],p ] + else + [] + in + + let kind = + FProp (get, set, Some(convert_signature ctx p ilsig), None) + in + { + cff_name = prop.pname; + cff_doc = None; + cff_pos = p; + cff_meta = meta; + cff_access = cff_access; + cff_kind = kind; + } + +let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false + +let is_explicit ctx ilcls i = + let s = match i with + | LClass(path,_) | LValueType(path,_) -> ilpath_s path + | _ -> assert false + in + let len = String.length s in + List.exists (fun m -> + String.length m.mname > len && String.sub m.mname 0 len = s + ) ilcls.cmethods + +let mke e p = (e,p) + +let mk_special_call name p args = + mke (ECast( mke (EUntyped( mke (ECall( mke (EConst(Ident name)) p, args )) p )) p , None)) p + +let mk_this_call name p args = + mke (ECall( mke (EField(mke (EConst(Ident "this")) p ,name)) p, args )) p + +let mk_metas metas p = + List.map (fun m -> m,[],p) metas + +let mk_abstract_fun name p kind metas acc = + let metas = mk_metas metas p in + { + cff_name = name; + cff_doc = None; + cff_pos = p; + cff_meta = metas; + cff_access = acc; + cff_kind = kind; + } + +let convert_fun_arg ctx p = function + | LManagedPointer s -> + mk_type_path ctx (["cs"],[],"Ref") [ TPType (convert_signature ctx p s) ] + | s -> + convert_signature ctx p s + +let convert_fun ctx p ret args = + let args = List.map (convert_fun_arg ctx p) args in + CTFunction(args, convert_signature ctx p ret) + +let get_clsname ctx cpath = + match netpath_to_hx ctx.nstd cpath with + | (_,n) -> n + +let convert_delegate ctx p ilcls = + let p = { p with pfile = p.pfile ^" (abstract delegate)" } in + (* will have the following methods: *) + (* - new (haxeType:Func) *) + (* - FromHaxeFunction(haxeType) *) + (* - Invoke() *) + (* - AsDelegate():Super *) + (* - @:op(A+B) Add(d:absType) *) + (* - @:op(A-B) Remove(d:absType) *) + let abs_type = mk_type_path ctx (ilcls.cpath) (List.map (fun t -> TPType (mk_type_path ctx ([],[],"T" ^ string_of_int t.tnumber) [])) ilcls.ctypes) in + let invoke = List.find (fun m -> m.mname = "Invoke") ilcls.cmethods in + let ret = invoke.mret.snorm in + let args = List.map (fun (_,_,s) -> s.snorm) invoke.margs in + let haxe_type = convert_fun ctx p ret args in + let types = List.map (fun t -> + { + tp_name = "T" ^ string_of_int t.tnumber; + tp_params = []; + tp_constraints = []; + } + ) ilcls.ctypes in + let mk_op_fn op name p = + let fn_name = List.assoc op cs_binops in + let clsname = match ilcls.cpath with + | (ns,inner,n) -> get_clsname ctx (ns,inner,"Delegate_"^n) + in + let expr = (ECall( (EField( (EConst(Ident (clsname)),p), fn_name ),p), [(EConst(Ident"arg1"),p);(EConst(Ident"arg2"),p)]),p) in + FFun { + f_params = types; + f_args = ["arg1",false,Some abs_type,None;"arg2",false,Some abs_type,None]; + f_type = Some abs_type; + f_expr = Some ( (EReturn (Some expr), p) ); + } + in + let mk_op op name = + let p = { p with pfile = p.pfile ^" (op " ^ name ^ ")" } in + { + cff_name = name; + cff_doc = None; + cff_pos = p; + cff_meta = [ Meta.Extern,[],p ; Meta.Op, [ (EBinop(op, (EConst(Ident"A"),p), (EConst(Ident"B"),p)),p) ], p ]; + cff_access = [APublic;AInline;AStatic]; + cff_kind = mk_op_fn op name p; + } + in + let params = (List.map (fun s -> + TPType (mk_type_path ctx ([],[],s.tp_name) []) + ) types) in + let underlying_type = match ilcls.cpath with + | ns,inner,name -> + mk_type_path ctx (ns,inner,"Delegate_" ^ name) params + in + + let fn_new = FFun { + f_params = []; + f_args = ["hxfunc",false,Some haxe_type,None]; + f_type = None; + f_expr = Some ( EBinop(Ast.OpAssign, (EConst(Ident "this"),p), (mk_special_call "__delegate__" p [EConst(Ident "hxfunc"),p]) ), p ); + } in + let fn_from_hx = FFun { + f_params = types; + f_args = ["hxfunc",false,Some haxe_type,None]; + f_type = Some( mk_type_path ctx ilcls.cpath params ); + f_expr = Some( EReturn( Some (mk_special_call "__delegate__" p [EConst(Ident "hxfunc"),p] )), p); + } in + let i = ref 0 in + let j = ref 0 in + let fn_invoke = FFun { + f_params = []; + f_args = List.map (fun arg -> + incr i; + "arg" ^ string_of_int !i, false, Some (convert_fun_arg ctx p arg), None + ) args; + f_type = Some(convert_signature ctx p ret); + f_expr = Some( + EReturn( Some ( + mk_this_call "Invoke" p (List.map (fun arg -> + incr j; (EConst( Ident ("arg" ^ string_of_int !j) ), p) + ) args ) + )), p + ); + } in + let fn_asdel = FFun { + f_params = []; + f_args = []; + f_type = None; + f_expr = Some( + EReturn( Some ( EConst(Ident "this"), p ) ), p + ); + } in + let fn_new = mk_abstract_fun "new" p fn_new [Meta.Extern] [APublic;AInline] in + let fn_from_hx = mk_abstract_fun "FromHaxeFunction" p fn_from_hx [Meta.Extern;Meta.From] [APublic;AInline;AStatic] in + let fn_invoke = mk_abstract_fun "Invoke" p fn_invoke [Meta.Extern] [APublic;AInline] in + let fn_asdel = mk_abstract_fun "AsDelegate" p fn_asdel [Meta.Extern] [APublic;AInline] in + let _, c = netpath_to_hx ctx.nstd ilcls.cpath in + EAbstract { + d_name = netname_to_hx c; + d_doc = None; + d_params = types; + d_meta = mk_metas [Meta.Delegate] p; + d_flags = [AIsType underlying_type]; + d_data = [fn_new;fn_from_hx;fn_invoke;fn_asdel;mk_op Ast.OpAdd "Add";mk_op Ast.OpSub "Remove"]; + } + +let convert_ilclass ctx p ?(delegate=false) ilcls = match ilcls.csuper with + | Some { snorm = LClass ((["System"],[],"Enum"),[]) } -> + convert_ilenum ctx p ilcls + | _ -> + let flags = ref [HExtern] in + (* todo: instead of CsNative, use more specific definitions *) + if PMap.mem "net_loader_debug" ctx.ncom.defines then begin + let sup = match ilcls.csuper with | None -> [] | Some c -> [IlMetaDebug.ilsig_s c.ssig] in + let sup = sup @ List.map (fun i -> IlMetaDebug.ilsig_s i.ssig) ilcls.cimplements in + print_endline ("converting " ^ ilpath_s ilcls.cpath ^ " : " ^ (String.concat ", " sup)) + end; + let meta = ref [Meta.CsNative, [], p; Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p] in + let force_check = Common.defined ctx.ncom Define.ForceLibCheck in + if not force_check then + meta := (Meta.LibType,[],p) :: !meta; + + let is_interface = ref false in + List.iter (fun f -> match f with + | SSealed -> meta := (Meta.Final, [], p) :: !meta + | SInterface -> + is_interface := true; + flags := HInterface :: !flags + | SAbstract -> meta := (Meta.Abstract, [], p) :: !meta + | _ -> () + ) ilcls.cflags.tdf_semantics; + + (* (match ilcls.cflags.tdf_vis with *) + (* | VPublic | VNestedFamOrAssem | VNestedFamily -> () *) + (* | _ -> raise Exit); *) + (match ilcls.csuper with + | Some { snorm = LClass ( (["System"],[],"Object"), [] ) } -> () + | Some ({ snorm = LClass ( (["System"],[],"ValueType"), [] ) } as s) -> + flags := HExtends (get_type_path ctx (convert_signature ctx p s.snorm)) :: !flags; + meta := (Meta.Struct,[],p) :: !meta + | Some { snorm = LClass ( (["haxe";"lang"],[],"HxObject"), [] ) } -> + meta := (Meta.HxGen,[],p) :: !meta + | Some s -> + flags := HExtends (get_type_path ctx (convert_signature ctx p s.snorm)) :: !flags + | _ -> ()); + + let has_explicit_ifaces = ref false in + List.iter (fun i -> + match i.snorm with + | LClass ( (["haxe";"lang"],[], "IHxObject"), _ ) -> + meta := (Meta.HxGen,[],p) :: !meta + (* | i when is_explicit ctx ilcls i -> () *) + | i -> + if is_explicit ctx ilcls i then has_explicit_ifaces := true; + flags := if !is_interface then + HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags + else + HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags + ) ilcls.cimplements; + (* this is needed because of explicit interfaces. see http://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx *) + (* explicit interfaces can't be mapped into Haxe in any way - since their fields can't be accessed directly, but they still implement that interface *) + if !has_explicit_ifaces && force_check then (* do not check on this specific case *) + meta := (Meta.LibType,[],p) :: !meta; + + (* ArrayAccess *) + ignore (List.exists (function + | { psig = { snorm = LMethod(_,ret,[v]) } } -> + flags := if !is_interface then + (HExtends( raw_type_path ctx ([],"ArrayAccess") [ TPType (convert_signature ctx p ret) ]) :: !flags) + else + (HImplements( raw_type_path ctx ([],"ArrayAccess") [ TPType (convert_signature ctx p ret) ]) :: !flags); + true + | _ -> false) ilcls.cprops); + + let fields = ref [] in + let run_fields fn f = + List.iter (fun f -> + try + fields := fn f :: !fields + with + | Exit -> () + ) f + in + let meths = if !is_interface then + List.filter (fun m -> m.moverride = None) ilcls.cmethods + else + ilcls.cmethods + in + run_fields (fun m -> + convert_ilmethod ctx p m (List.exists (fun m2 -> m != m2 && String.get m2.mname 0 <> '.' && String.ends_with m2.mname ("." ^ m.mname)) meths) + ) meths; + run_fields (convert_ilfield ctx p) ilcls.cfields; + run_fields (fun prop -> + convert_ilprop ctx p prop (List.exists (fun p2 -> prop != p2 && String.get p2.pname 0 <> '.' && String.ends_with p2.pname ("." ^ prop.pname)) ilcls.cprops) + ) ilcls.cprops; + run_fields (convert_ilevent ctx p) ilcls.cevents; + + let params = List.map (fun p -> + { + tp_name = "T" ^ string_of_int p.tnumber; + tp_params = []; + tp_constraints = []; + }) ilcls.ctypes + in + + if delegate then begin + (* add op_Addition and op_Subtraction *) + let path = ilcls.cpath in + let thist = mk_type_path ctx path (List.map (fun t -> TPType (mk_type_path ctx ([],[],"T" ^ string_of_int t.tnumber) [])) ilcls.ctypes) in + let op name = + { + cff_name = name; + cff_doc = None; + cff_pos = p; + cff_meta = []; + cff_access = [APublic;AStatic]; + cff_kind = FFun { + f_params = params; + f_args = ["arg1",false,Some thist,None;"arg2",false,Some thist,None]; + f_type = Some thist; + f_expr = None; + }; + } + in + fields := op "op_Addition" :: op "op_Subtraction" :: !fields; + end; + let path = match ilcls.cpath with + | ns,inner,name when delegate -> + ns,inner,"Delegate_"^name + | _ -> ilcls.cpath + in + let _, c = netpath_to_hx ctx.nstd path in + EClass { + d_name = netname_to_hx c; + d_doc = None; + d_params = params; + d_meta = !meta; + d_flags = !flags; + d_data = !fields; + } + +type il_any_field = + | IlField of ilfield + | IlMethod of ilmethod + | IlProp of ilprop + +let get_fname = function + | IlField f -> f.fname + | IlMethod m -> m.mname + | IlProp p -> p.pname + +let is_static = function + | IlField f -> + List.mem CStatic f.fflags.ff_contract + | IlMethod m -> + List.mem CMStatic m.mflags.mf_contract + | IlProp p -> + List.exists (function + | None -> false + | Some (_,m) -> List.mem CMStatic m.mf_contract + ) [p.pget;p.pset] + (* | _ -> false *) + +let change_name name = function + | IlField f -> IlField { f with fname = name } + | IlMethod m -> IlMethod { m with mname = name } + | IlProp p -> IlProp { p with pname = name } + +let compatible_methods m1 m2 = match m1,m2 with + | IlMethod { msig = { snorm = LMethod(_,ret1,args1) } }, IlMethod { msig = { snorm = LMethod(_,ret2,args2) } } -> + ret1 = ret2 && args1 = args2 + | _ -> false + +let ilcls_from_ilsig ctx ilsig = + let path, params = match ilsig with + | LClass(path, params) | LValueType(path, params) -> + path, params + | LObject -> + (["System"],[],"Object"),[] + | _ -> raise Not_found (* all other types won't appear as superclass *) + in + match lookup_ilclass ctx.nstd ctx.ncom path with + | None -> raise Not_found + | Some c -> + c, params + +let rec ilapply_params params = function + | LManagedPointer s -> LManagedPointer (ilapply_params params s) + | LPointer s -> LPointer (ilapply_params params s) + | LValueType (p,pl) -> LValueType(p, List.map (ilapply_params params) pl) + | LClass (p,pl) -> LClass(p, List.map (ilapply_params params) pl) + | LTypeParam i -> + List.nth params i (* TODO: maybe i - 1? *) + | LVector s -> LVector (ilapply_params params s) + | LArray (s,a) -> LArray (ilapply_params params s, a) + | LMethod (c,r,args) -> LMethod (c, ilapply_params params r, List.map (ilapply_params params) args) + | p -> p + +let ilcls_with_params ctx cls params = + match cls.ctypes with + | [] -> cls + | _ -> + { cls with + cfields = List.map (fun f -> { f with fsig = { f.fsig with snorm = ilapply_params params f.fsig.snorm } }) cls.cfields; + cmethods = List.map (fun m -> { m with + msig = { m.msig with snorm = ilapply_params params m.msig.snorm }; + margs = List.map (fun (n,f,s) -> (n,f,{ s with snorm = ilapply_params params s.snorm })) m.margs; + mret = { m.mret with snorm = ilapply_params params m.mret.snorm }; + }) cls.cmethods; + cprops = List.map (fun p -> { p with psig = { p.psig with snorm = ilapply_params params p.psig.snorm } }) cls.cprops; + csuper = Option.map (fun s -> { s with snorm = ilapply_params params s.snorm } ) cls.csuper; + cimplements = List.map (fun s -> { s with snorm = ilapply_params params s.snorm } ) cls.cimplements; + } + +let rec compatible_params t1 t2 = match t1,t2 with + | LManagedPointer(s1), LManagedPointer(s2) -> compatible_params s1 s2 + | LManagedPointer(s1), s2 | s1, LManagedPointer(s2) -> + compatible_params s1 s2 + | _ -> t1 = t2 + +let compatible_methods m1 m2 = match m1, m2 with + | LMethod(_,r1,a1), LMethod(_,r2,a2) -> (try + List.for_all2 (fun a1 a2 -> compatible_params a1 a2) a1 a2 + with | Invalid_argument _ -> + false) + | _ -> false + +let compatible_field f1 f2 = match f1, f2 with + | IlMethod { msig = { snorm = LMethod(_,_,a1) } }, + IlMethod { msig = { snorm = LMethod(_,_,a2) } } -> + a1 = a2 + | IlProp p1, IlProp p2 -> + (* p1.psig.snorm = p2.psig.snorm *) + true + | IlField f1, IlField f2 -> + (* f1.fsig.snorm = f2.fsig.snorm *) + true + | _ -> false + +let get_all_fields cls = + let all_fields = List.map (fun f -> IlField f, cls.cpath, f.fname, List.mem CStatic f.fflags.ff_contract) cls.cfields in + let all_fields = all_fields @ List.map (fun m -> IlMethod m, cls.cpath, m.mname, List.mem CMStatic m.mflags.mf_contract) cls.cmethods in + let all_fields = all_fields @ List.map (function + | p -> + IlProp p, cls.cpath, p.pname, is_static (IlProp p) + ) cls.cprops in + all_fields + +let normalize_ilcls ctx cls = + let force_check = Common.defined ctx.ncom Define.ForceLibCheck in + (* first filter out overloaded fields of same signature *) + let rec loop acc = function + | [] -> acc + | m :: cmeths -> + let static = List.mem CMStatic m.mflags.mf_contract in + if List.exists (fun m2 -> m.mname = m2.mname && List.mem CMStatic m2.mflags.mf_contract = static && compatible_methods m.msig.snorm m2.msig.snorm) cmeths then + loop acc cmeths + else + loop (m :: acc) cmeths + in + let meths = loop [] cls.cmethods in + (* fix overrides *) + (* get only the methods that aren't declared as override, but may be *) + let meths = List.map (fun v -> ref v) meths in + let no_overrides = List.filter (fun m -> + let m = !m in + not (List.mem CMStatic m.mflags.mf_contract) + ) meths in + let no_overrides = ref no_overrides in + + let all_fields = ref [] in + let all_events_name = Hashtbl.create 0 in + (* avoid naming collision between events and functions *) + let add_cls_events_collision cls = + List.iter (fun m -> if not (List.mem CMStatic m.mflags.mf_contract) then Hashtbl.replace all_events_name m.mname true) cls.cmethods; + List.iter (fun p -> if not (is_static (IlProp p)) then Hashtbl.replace all_events_name p.pname true) cls.cprops; + in + + let rec loop cls = try + match cls.csuper with + | Some { snorm = LClass((["System"],[],"Object"),_) } + | Some { snorm = LObject } | None -> () + | Some s -> + let cls, params = ilcls_from_ilsig ctx s.snorm in + let cls = ilcls_with_params ctx cls params in + if force_check then no_overrides := List.filter (fun v -> + let m = !v in + let is_override_here = List.exists (fun m2 -> + m2.mname = m.mname && not (List.mem CMStatic m2.mflags.mf_contract) && compatible_methods m.msig.snorm m2.msig.snorm + ) cls.cmethods in + if is_override_here then v := { m with moverride = Some(cls.cpath, m.mname) }; + not is_override_here + ) !no_overrides; + all_fields := get_all_fields cls @ !all_fields; + + add_cls_events_collision cls; + List.iter (fun ev -> Hashtbl.replace all_events_name ev.ename true) cls.cevents; + + loop cls + with | Not_found -> () + in + loop cls; + + add_cls_events_collision cls; + if force_check then List.iter (fun v -> v := { !v with moverride = None }) !no_overrides; + let added = ref [] in + + let current_all = ref (get_all_fields cls @ !all_fields) in + (* look for interfaces and add missing implementations (some methods' implementation is optional) *) + let rec loop_interface cls iface = try + match iface.snorm with + | LClass((["System"],[],"Object"),_) | LObject -> () + | LClass(path,_) when path = cls.cpath -> () + | s -> + let cif, params = ilcls_from_ilsig ctx s in + let cif = ilcls_with_params ctx cif params in + List.iter (function + | (f,_,name,false) as ff -> + (* look for compatible fields *) + if not (List.exists (function + | (f2,_,name2,false) when (name = name2 || String.ends_with name2 ("." ^ name)) -> (* consider explicit implementations as implementations *) + compatible_field f f2 + | _ -> false + ) !current_all) then begin + current_all := ff :: !current_all; + added := ff :: !added + end else + (* ensure it's public *) + List.iter (fun mref -> match !mref with + | m when m.mname = name && compatible_field f (IlMethod m) -> + mref := { m with mflags = { m.mflags with mf_access = FAPublic } } + | _ -> () + ) meths + | _ -> () + ) (get_all_fields cif); + List.iter (loop_interface cif) cif.cimplements + with | Not_found -> () + in + List.iter (loop_interface cls) cls.cimplements; + let added = List.map (function + | (IlMethod m,a,name,b) when m.mflags.mf_access <> FAPublic -> + (IlMethod { m with mflags = { m.mflags with mf_access = FAPublic } },a,name,b) + | (IlField f,a,name,b) when f.fflags.ff_access <> FAPublic -> + (IlField { f with fflags = { f.fflags with ff_access = FAPublic } },a,name,b) + | s -> s + ) !added in + + (* filter out properties that were already declared *) + let props = if force_check then List.filter (function + | p -> + let static = is_static (IlProp p) in + let name = p.pname in + not (List.exists (function (IlProp _,_,n,s) -> s = static && name = n | _ -> false) !all_fields) + (* | _ -> false *) + ) cls.cprops + else + cls.cprops + in + let cls = { cls with cmethods = List.map (fun v -> !v) meths; cprops = props } in + + let clsfields = (get_all_fields cls) @ added in + let super_fields = !all_fields in + all_fields := clsfields @ !all_fields; + let refclsfields = (List.map (fun v -> ref v) clsfields) in + (* search static / non-static name clash *) + (* change field name to not collide with haxe keywords *) + let fold_field acc v = + let f, p, name, is_static = !v in + let change, copy = match name with + | _ when is_haxe_keyword name -> + true, false + | _ -> + ((is_static && List.exists (function | (f,_,n,false) -> name = n | _ -> false) !all_fields) || + (not is_static && match f with (* filter methods that have the same name as fields *) + | IlMethod _ -> + List.exists (function | ( (IlProp _ | IlField _),_,n,false) -> name = n | _ -> false) super_fields || + List.exists (function | ( (IlProp _ | IlField _),_,n,s) -> name = n | _ -> false) clsfields + | _ -> false)), true + in + if change then begin + let name = "%" ^ name in + let changed = change_name name f, p, name, is_static in + if not copy then + v := changed; + if copy then + v :: ref changed :: acc + else + v :: acc + end else + v :: acc + in + let refclsfields = List.fold_left fold_field [] refclsfields in + + let rec fold (fields,methods,props) f = match !f with + | IlField f,_,_,_ -> f :: fields,methods,props + | IlMethod m,_,_,_ -> fields,m :: methods,props + | IlProp p,_,_,_ -> fields,methods,p :: props + in + let fields, methods, props = List.fold_left fold ([],[],[]) refclsfields in + { cls with + cfields = fields; + cprops = props; + cmethods = methods; + cevents = List.filter (fun ev -> not (Hashtbl.mem all_events_name ev.ename)) cls.cevents; + } + +let add_net_std com file = + com.net_std <- file :: com.net_std + +let add_net_lib com file std = + let ilctx = ref None in + let netpath_to_hx = netpath_to_hx std in + let real_file = ref file in + let get_ctx () = + match !ilctx with + | Some c -> + c + | None -> + let file = if Sys.file_exists file then + file + else try Common.find_file com file with + | Not_found -> try Common.find_file com (file ^ ".dll") with + | Not_found -> + failwith (".NET lib " ^ file ^ " not found") + in + real_file := file; + let r = PeReader.create_r (open_in_bin file) com.defines in + let ctx = PeReader.read r in + let clr_header = PeReader.read_clr_header ctx in + let cache = IlMetaReader.create_cache () in + let meta = IlMetaReader.read_meta_tables ctx clr_header cache in + close_in (r.PeReader.ch); + if PMap.mem "net_loader_debug" com.defines then + print_endline ("for lib " ^ file); + let il_typedefs = Hashtbl.copy meta.il_typedefs in + Hashtbl.clear meta.il_typedefs; + + Hashtbl.iter (fun _ td -> + let path = IlMetaTools.get_path (TypeDef td) in + if PMap.mem "net_loader_debug" com.defines then + Printf.printf "found %s\n" (path_s (netpath_to_hx path)); + Hashtbl.replace com.net_path_map (netpath_to_hx path) path; + Hashtbl.replace meta.il_typedefs path td + ) il_typedefs; + let meta = { nstd = std; ncom = com; nil = meta } in + ilctx := Some meta; + meta + in + + let cache = Hashtbl.create 0 in + let lookup path = + try + Hashtbl.find cache path + with | Not_found -> try + let ctx = get_ctx() in + let ns, n, cl = hxpath_to_net ctx path in + let cls = IlMetaTools.convert_class ctx.nil (ns,n,cl) in + let cls = normalize_ilcls ctx cls in + Hashtbl.add cache path (Some cls); + Some cls + with | Not_found -> + Hashtbl.add cache path None; + None + in + + let all_files () = + Hashtbl.fold (fun path _ acc -> match path with + | _,_ :: _, _ -> acc + | _ -> netpath_to_hx path :: acc) (get_ctx()).nil.il_typedefs [] + in + + let build path = + let p = { pfile = !real_file ^ " @ " ^ path_s path; pmin = 0; pmax = 0; } in + let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in + let cp = ref [] in + let rec build path = try + if PMap.mem "net_loader_debug" com.defines then + Printf.printf "looking up %s\n" (path_s path); + match lookup path with + | Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls) + when List.mem SSealed cls.cflags.tdf_semantics -> + let ctx = get_ctx() in + let hxcls = convert_ilclass ctx p ~delegate:true cls in + let delegate = convert_delegate ctx p cls in + cp := (hxcls,p) :: (delegate,p) :: !cp; + List.iter (fun ilpath -> + let path = netpath_to_hx ilpath in + build path + ) cls.cnested + | Some cls -> + let ctx = get_ctx() in + let hxcls = convert_ilclass ctx p cls in + cp := (hxcls,p) :: !cp; + List.iter (fun ilpath -> + let path = netpath_to_hx ilpath in + build path + ) cls.cnested + | _ -> () + with | Not_found | Exit -> + () + in + build path; + match !cp with + | [] -> None + | cp -> Some (!real_file, (pack,cp)) + in + let build path p = + build path + in + com.load_extern_type <- com.load_extern_type @ [build]; + com.net_libs <- (file, std, all_files, lookup) :: com.net_libs + +let before_generate com = + (* net version *) + let net_ver = try + int_of_string (PMap.find "net_ver" com.defines) + with | Not_found -> + Common.define_value com Define.NetVer "20"; + 20 + in + if net_ver < 20 then + failwith ( + ".NET version is defined to target .NET " + ^ string_of_int net_ver + ^ ", but the compiler can only output code to versions equal or superior to .NET 2.0 (defined as 20)" + ); + let rec loop = function + | v :: acc when v <= net_ver -> + Common.raw_define com ("NET_" ^ string_of_int v); + loop acc + | _ -> () + in + loop [20;21;30;35;40;45]; + + (* net target *) + let net_target = try + String.lowercase (PMap.find "net_target" com.defines) + with | Not_found -> + "net" + in + Common.define_value com Define.NetTarget net_target; + Common.raw_define com net_target; + + (* std dirs *) + let stds = match com.net_std with + | [] -> ["netlib"] + | s -> s + in + (* look for all dirs that have the digraph NET_TARGET-NET_VER *) + let digraph = net_target ^ "-" ^ string_of_int net_ver in + let matched = ref [] in + List.iter (fun f -> try + let f = Common.find_file com (f ^ "/" ^ digraph) in + matched := (f, Unix.opendir f) :: !matched + with | _ -> ()) stds; + + if !matched = [] then failwith ( + "No .NET std lib directory with the pattern '" ^ digraph ^ "' was found in the -net-std search path. " ^ + "Try updating the hxcs lib to the latest version, or specifying another -net-std path."); + List.iter (fun (path,f) -> + let rec loop () = + try + let f = Unix.readdir f in + let finsens = String.lowercase f in + if String.ends_with finsens ".dll" then + add_net_lib com (path ^ "/" ^ f) true; + loop() + with | End_of_file -> + Unix.closedir f + in + loop() + ) !matched; + + (* now force all libraries to initialize *) + List.iter (function (_,_,_,lookup) -> ignore (lookup ([],""))) com.net_libs diff --git a/genjava.ml b/genjava.ml index bf9b614dda76082017ce0b194aea0d5019f11fc5..78f2ae98847ab00442a3cdb5ac0b70cf2bb66725 100644 --- a/genjava.ml +++ b/genjava.ml @@ -24,99 +24,133 @@ open JData open Unix open Ast open Common +open Type open Gencommon open Gencommon.SourceWriter -open Type open Printf open Option open ExtString +module SS = Set.Make(String) let is_boxed_type t = match follow t with - | TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) - | TInst ({ cl_path = (["java";"lang"], "Double") }, []) - | TInst ({ cl_path = (["java";"lang"], "Integer") }, []) - | TInst ({ cl_path = (["java";"lang"], "Byte") }, []) - | TInst ({ cl_path = (["java";"lang"], "Short") }, []) - | TInst ({ cl_path = (["java";"lang"], "Character") }, []) - | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> true - | _ -> false + | TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) + | TInst ({ cl_path = (["java";"lang"], "Double") }, []) + | TInst ({ cl_path = (["java";"lang"], "Integer") }, []) + | TInst ({ cl_path = (["java";"lang"], "Byte") }, []) + | TInst ({ cl_path = (["java";"lang"], "Short") }, []) + | TInst ({ cl_path = (["java";"lang"], "Character") }, []) + | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> true + | TAbstract ({ a_path = (["java";"lang"], "Boolean") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Double") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Integer") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Byte") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Short") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Character") }, []) + | TAbstract ({ a_path = (["java";"lang"], "Float") }, []) -> true + | _ -> false let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with - | TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool - | TInst ({ cl_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat - | TInst ({ cl_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint - | TInst ({ cl_path = (["java";"lang"], "Byte") }, []) -> tbyte - | TInst ({ cl_path = (["java";"lang"], "Short") }, []) -> tshort - | TInst ({ cl_path = (["java";"lang"], "Character") }, []) -> tchar - | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> tfloat - | _ -> assert false + | TInst ({ cl_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool + | TInst ({ cl_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat + | TInst ({ cl_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint + | TInst ({ cl_path = (["java";"lang"], "Byte") }, []) -> tbyte + | TInst ({ cl_path = (["java";"lang"], "Short") }, []) -> tshort + | TInst ({ cl_path = (["java";"lang"], "Character") }, []) -> tchar + | TInst ({ cl_path = (["java";"lang"], "Float") }, []) -> tfloat + | TAbstract ({ a_path = (["java";"lang"], "Boolean") }, []) -> gen.gcon.basic.tbool + | TAbstract ({ a_path = (["java";"lang"], "Double") }, []) -> gen.gcon.basic.tfloat + | TAbstract ({ a_path = (["java";"lang"], "Integer") }, []) -> gen.gcon.basic.tint + | TAbstract ({ a_path = (["java";"lang"], "Byte") }, []) -> tbyte + | TAbstract ({ a_path = (["java";"lang"], "Short") }, []) -> tshort + | TAbstract ({ a_path = (["java";"lang"], "Character") }, []) -> tchar + | TAbstract ({ a_path = (["java";"lang"], "Float") }, []) -> tfloat + | _ -> assert false let rec t_has_type_param t = match follow t with - | TInst({ cl_kind = KTypeParameter _ }, []) -> true - | TEnum(_, params) - | TInst(_, params) -> List.exists t_has_type_param params - | TFun(f,ret) -> t_has_type_param ret || List.exists (fun (_,_,t) -> t_has_type_param t) f - | _ -> false + | TInst({ cl_kind = KTypeParameter _ }, []) -> true + | TEnum(_, params) + | TAbstract(_, params) + | TInst(_, params) -> List.exists t_has_type_param params + | TFun(f,ret) -> t_has_type_param ret || List.exists (fun (_,_,t) -> t_has_type_param t) f + | _ -> false + +let is_type_param t = match follow t with + | TInst({ cl_kind = KTypeParameter _ }, _) -> true + | _ -> false let rec t_has_type_param_shallow last t = match follow t with - | TInst({ cl_kind = KTypeParameter _ }, []) -> true - | TEnum(_, params) - | TInst(_, params) when not last -> List.exists (t_has_type_param_shallow true) params - | TFun(f,ret) when not last -> t_has_type_param_shallow true ret || List.exists (fun (_,_,t) -> t_has_type_param_shallow true t) f - | _ -> false + | TInst({ cl_kind = KTypeParameter _ }, []) -> true + | TEnum(_, params) + | TAbstract(_, params) + | TInst(_, params) when not last -> List.exists (t_has_type_param_shallow true) params + | TFun(f,ret) when not last -> t_has_type_param_shallow true ret || List.exists (fun (_,_,t) -> t_has_type_param_shallow true t) f + | _ -> false + +let rec replace_type_param t = match follow t with + | TInst({ cl_kind = KTypeParameter _ }, []) -> t_dynamic + | TEnum(e, params) -> TEnum(e, List.map replace_type_param params) + | TAbstract(a, params) -> TAbstract(a, List.map replace_type_param params) + | TInst(cl, params) -> TInst(cl, List.map replace_type_param params) + | _ -> t let is_java_basic_type t = - match follow t with - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | TAbstract( { a_path = ([], "Single") }, [] ) - | TAbstract( { a_path = (["java"], ("Int8" | "Int16" | "Char16")) }, [] ) - | TInst( { cl_path = ([], "Int") }, [] ) | TAbstract( { a_path = ([], "Int") }, [] ) - | TInst( { cl_path = ([], "Float") }, [] ) | TAbstract( { a_path = ([], "Float") }, [] ) - | TEnum( { e_path = ([], "Bool") }, [] ) | TAbstract( { a_path = ([], "Bool") }, [] ) -> - true - | _ -> false + match follow t with + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) + | TAbstract( { a_path = ([], "Single") }, [] ) + | TAbstract( { a_path = (["java"], ("Int8" | "Int16" | "Char16" | "Int64")) }, [] ) + | TAbstract( { a_path = ([], "Int") }, [] ) + | TAbstract( { a_path = ([], "Float") }, [] ) + | TAbstract( { a_path = ([], "Bool") }, [] ) -> + true + | _ -> false let is_bool t = - match follow t with - | TEnum( { e_path = ([], "Bool") }, [] ) - | TAbstract ({ a_path = ([], "Bool") },[]) -> - true - | _ -> false + match follow t with + | TAbstract ({ a_path = ([], "Bool") },[]) -> + true + | _ -> false + +let like_bool t = + match follow t with + | TAbstract ({ a_path = ([], "Bool") },[]) + | TAbstract ({ a_path = (["java";"lang"],"Boolean") },[]) + | TInst ({ cl_path = (["java";"lang"],"Boolean") },[]) -> + true + | _ -> false let is_int_float gen t = - match follow (gen.greal_type t) with - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst( { cl_path = ([], "Int") }, [] ) | TAbstract( { a_path = ([], "Int") }, [] ) - | TInst( { cl_path = ([], "Float") }, [] ) | TAbstract( { a_path = ([], "Float") }, [] ) -> - true - | (TAbstract _ as t) when like_float t -> true - | _ -> false + match follow (gen.greal_type t) with + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TAbstract( { a_path = ([], "Int") }, [] ) + | TAbstract( { a_path = ([], "Float") }, [] ) -> + true + | (TAbstract _ as t) when like_float t && not (like_i64 t)-> true + | _ -> false let parse_explicit_iface = - let regex = Str.regexp "\\." in - let parse_explicit_iface str = - let split = Str.split regex str in - let rec get_iface split pack = - match split with - | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) - | pack_piece :: tl -> get_iface tl (pack_piece :: pack) - | _ -> assert false - in - get_iface split [] - in parse_explicit_iface + let regex = Str.regexp "\\." in + let parse_explicit_iface str = + let split = Str.split regex str in + let rec get_iface split pack = + match split with + | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) + | pack_piece :: tl -> get_iface tl (pack_piece :: pack) + | _ -> assert false + in + get_iface split [] + in parse_explicit_iface let is_string t = - match follow t with - | TInst( { cl_path = ([], "String") }, [] ) -> true - | _ -> false + match follow t with + | TInst( { cl_path = ([], "String") }, [] ) -> true + | _ -> false let is_cl t = match follow t with - | TInst({ cl_path = ["java";"lang"],"Class" },_) - | TAbstract({ a_path = [], ("Class"|"Enum") },_) -> true - | TAnon(a) when is_some (anon_class t) -> true - | _ -> false + | TInst({ cl_path = ["java";"lang"],"Class" },_) + | TAbstract({ a_path = [], ("Class"|"Enum") },_) -> true + | TAnon(a) when is_some (anon_class t) -> true + | _ -> false (* ******************************************* *) (* JavaSpecificESynf *) @@ -124,2975 +158,3501 @@ let is_cl t = match follow t with (* - Some Java-specific syntax filters that must run before ExpressionUnwrap + Some Java-specific syntax filters that must run before ExpressionUnwrap - dependencies: - It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions - It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr - It must run after CastDetect, as it changes casts - It must run after TryCatchWrapper, to change Std.is() calls inside there + dependencies: + It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions + It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr + It must run after CastDetect, as it changes casts + It must run after TryCatchWrapper, to change Std.is() calls inside there *) module JavaSpecificESynf = struct - let name = "java_specific_e" - - let priority = solve_deps name [ DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter CastDetect.priority; DAfter TryCatchWrapper.priority ] - - let get_cl_from_t t = - match follow t with - | TInst(cl,_) -> cl - | _ -> assert false - - let traverse gen runtime_cl = - let basic = gen.gcon.basic in - let float_cl = get_cl ( get_type gen (["java";"lang"], "Double")) in - let i8_md = ( get_type gen (["java";"lang"], "Byte")) in - let i16_md = ( get_type gen (["java";"lang"], "Short")) in - let i64_md = ( get_type gen (["java";"lang"], "Long")) in - let c16_md = ( get_type gen (["java";"lang"], "Character")) in - let f_md = ( get_type gen (["java";"lang"], "Float")) in - let bool_md = get_type gen (["java";"lang"], "Boolean") in - - let is_var = alloc_var "__is__" t_dynamic in - - let rec run e = - match e.eexpr with - (* Math changes *) - | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NaN" }) ) -> - mk_static_field_access_infer float_cl "NaN" e.epos [] - | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NEGATIVE_INFINITY" }) ) -> - mk_static_field_access_infer float_cl "NEGATIVE_INFINITY" e.epos [] - | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "POSITIVE_INFINITY" }) ) -> - mk_static_field_access_infer float_cl "POSITIVE_INFINITY" e.epos [] - | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isNaN"}) ) -> - mk_static_field_access_infer float_cl "_isNaN" e.epos [] - | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("ffloor" as f) }) ) } as fe), p) - | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fceil" as f) }) ) } as fe), p) -> - Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic (String.sub f 1 (String.length f - 1))) }, p) } - | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fround") }) ) } as fe), p) -> - Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic "rint") }, p) } - | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "floor" }) ) }, _) - | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "round" }) ) }, _) - | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "ceil" }) ) }, _) -> - mk_cast basic.tint (Type.map_expr run { e with etype = basic.tfloat }) - | TCall( ( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isFinite" }) ) } as efield ), [v]) -> - { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "isFinite" efield.epos [], [run v] ) } - (* end of math changes *) - - (* Std.is() *) - | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, - [ obj; { eexpr = TTypeExpr(md) } ] - ) -> - let mk_is is_basic obj md = - let obj = if is_basic then mk_cast t_dynamic obj else obj in - { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [ - run obj; - { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos } - ] ) } - in - (match follow_module follow md with - | TClassDecl({ cl_path = ([], "Float") }) - | TAbstractDecl({ a_path = ([], "Float") }) -> - { - eexpr = TCall( - mk_static_field_access_infer runtime_cl "isDouble" e.epos [], - [ run obj ] - ); - etype = basic.tbool; - epos = e.epos - } - | TClassDecl{ cl_path = ([], "Int") } - | TAbstractDecl{ a_path = ([], "Int") } -> - { - eexpr = TCall( - mk_static_field_access_infer runtime_cl "isInt" e.epos [], - [ run obj ] - ); - etype = basic.tbool; - epos = e.epos - } - | TAbstractDecl{ a_path = ([], "Bool") } - | TEnumDecl{ e_path = ([], "Bool") } -> - mk_is true obj bool_md - | TAbstractDecl{ a_path = ([], "Single") } -> - mk_is true obj f_md - | TAbstractDecl{ a_path = (["java"], "Int8") } -> - mk_is true obj i8_md - | TAbstractDecl{ a_path = (["java"], "Int16") } -> - mk_is true obj i16_md - | TAbstractDecl{ a_path = (["java"], "Char16") } -> - mk_is true obj c16_md - | TClassDecl{ cl_path = (["haxe"], "Int64") } -> - mk_is true obj i64_md - | TAbstractDecl{ a_path = ([], "Dynamic") } - | TClassDecl{ cl_path = ([], "Dynamic") } -> - (match obj.eexpr with - | TLocal _ | TConst _ -> { e with eexpr = TConst(TBool true) } - | _ -> { e with eexpr = TBlock([run obj; { e with eexpr = TConst(TBool true) }]) } - ) - | _ -> - mk_is false obj md - ) - (* end Std.is() *) - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "java_specific_e" + + let priority = solve_deps name [ DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter CastDetect.priority; DAfter TryCatchWrapper.priority ] + + let get_cl_from_t t = + match follow t with + | TInst(cl,_) -> cl + | _ -> assert false + + let traverse gen runtime_cl = + let basic = gen.gcon.basic in + let float_cl = get_cl ( get_type gen (["java";"lang"], "Double")) in + let i8_md = ( get_type gen (["java";"lang"], "Byte")) in + let i16_md = ( get_type gen (["java";"lang"], "Short")) in + let i64_md = ( get_type gen (["java";"lang"], "Long")) in + let c16_md = ( get_type gen (["java";"lang"], "Character")) in + let f_md = ( get_type gen (["java";"lang"], "Float")) in + let bool_md = get_type gen (["java";"lang"], "Boolean") in + + let is_var = alloc_var "__is__" t_dynamic in + + let rec run e = + match e.eexpr with + (* Math changes *) + | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NaN" }) ) -> + mk_static_field_access_infer float_cl "NaN" e.epos [] + | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "NEGATIVE_INFINITY" }) ) -> + mk_static_field_access_infer float_cl "NEGATIVE_INFINITY" e.epos [] + | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "POSITIVE_INFINITY" }) ) -> + mk_static_field_access_infer float_cl "POSITIVE_INFINITY" e.epos [] + | TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isNaN"}) ) -> + mk_static_field_access_infer float_cl "isNaN" e.epos [] + | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("ffloor" as f) }) ) } as fe), p) + | TCall( ({ eexpr = TField( (_ as ef), FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = ("fceil" as f) }) ) } as fe), p) -> + Type.map_expr run { e with eexpr = TCall({ fe with eexpr = TField(ef, FDynamic (String.sub f 1 (String.length f - 1))) }, p) } + | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "floor" }) ) }, _) + | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "round" }) ) }, _) + | TCall( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "ceil" }) ) }, _) -> + mk_cast basic.tint (Type.map_expr run { e with etype = basic.tfloat }) + | TCall( ( { eexpr = TField( _, FStatic({ cl_path = (["java";"lang"], "Math") }, { cf_name = "isFinite" }) ) } as efield ), [v]) -> + { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "isFinite" efield.epos [], [run v] ) } + (* end of math changes *) + + (* Std.is() *) + | TCall( + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, + [ obj; { eexpr = TTypeExpr(md) } ] + ) -> + let mk_is is_basic obj md = + let obj = if is_basic then mk_cast t_dynamic obj else obj in + { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [ + run obj; + { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos } + ] ) } + in + (match follow_module follow md with + | TAbstractDecl({ a_path = ([], "Float") }) -> + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "isDouble" e.epos [], + [ run obj ] + ); + etype = basic.tbool; + epos = e.epos + } + | TAbstractDecl{ a_path = ([], "Int") } -> + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "isInt" e.epos [], + [ run obj ] + ); + etype = basic.tbool; + epos = e.epos + } + | TAbstractDecl{ a_path = ([], "Bool") } -> + mk_is true obj bool_md + | TAbstractDecl{ a_path = ([], "Single") } -> + mk_is true obj f_md + | TAbstractDecl{ a_path = (["java"], "Int8") } -> + mk_is true obj i8_md + | TAbstractDecl{ a_path = (["java"], "Int16") } -> + mk_is true obj i16_md + | TAbstractDecl{ a_path = (["java"], "Char16") } -> + mk_is true obj c16_md + | TAbstractDecl{ a_path = (["java"], "Int64") } -> + mk_is true obj i64_md + | TClassDecl{ cl_path = (["haxe"], "Int64") } -> + mk_is true obj i64_md + | TAbstractDecl{ a_path = ([], "Dynamic") } + | TClassDecl{ cl_path = ([], "Dynamic") } -> + (match obj.eexpr with + | TLocal _ | TConst _ -> { e with eexpr = TConst(TBool true) } + | _ -> { e with eexpr = TBlock([run obj; { e with eexpr = TConst(TBool true) }]) } + ) + | _ -> + mk_is false obj md + ) + (* end Std.is() *) + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; - (* ******************************************* *) (* JavaSpecificSynf *) (* ******************************************* *) (* - Some Java-specific syntax filters that can run after ExprUnwrap + Some Java-specific syntax filters that can run after ExprUnwrap - dependencies: - Runs after ExprUnwarp + dependencies: + Runs after ExprUnwarp *) module JavaSpecificSynf = struct - let name = "java_specific" - - let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DBefore IntDivisionSynf.priority ] - - let java_hash s = - let h = ref Int32.zero in - let thirtyone = Int32.of_int 31 in - for i = 0 to String.length s - 1 do - h := Int32.add (Int32.mul thirtyone !h) (Int32.of_int (int_of_char (String.unsafe_get s i))); - done; - !h - - let rec is_final_return_expr is_switch e = - let is_final_return_expr = is_final_return_expr is_switch in - match e.eexpr with - | TReturn _ - | TThrow _ -> true - (* this is hack to not use 'break' on switch cases *) - | TLocal { v_name = "__fallback__" } when is_switch -> true - | TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> true - | TParenthesis p -> is_final_return_expr p - | TBlock bl -> is_final_return_block is_switch bl - | TSwitch (_, el_e_l, edef) -> - List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef - | TMatch (_, _, il_vl_e_l, edef) -> - List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef - | TIf (_,eif, Some eelse) -> - is_final_return_expr eif && is_final_return_expr eelse - | TFor (_,_,e) -> - is_final_return_expr e - | TWhile (_,e,_) -> - is_final_return_expr e - | TFunction tf -> - is_final_return_expr tf.tf_expr - | TTry (e, ve_l) -> - is_final_return_expr e && List.for_all (fun (_,e) -> is_final_return_expr e) ve_l - | _ -> false - - and is_final_return_block is_switch el = - match el with - | [] -> false - | final :: [] -> is_final_return_expr is_switch final - | hd :: tl -> is_final_return_block is_switch tl - - let is_null e = match e.eexpr with | TConst(TNull) -> true | _ -> false - - let rec is_equatable gen t = - match follow t with - | TInst(cl,_) -> - if cl.cl_path = (["haxe";"lang"], "IEquatable") then - true - else - List.exists (fun (cl,p) -> is_equatable gen (TInst(cl,p))) cl.cl_implements - || (match cl.cl_super with | Some(cl,p) -> is_equatable gen (TInst(cl,p)) | None -> false) - | _ -> false - - (* - Changing string switch - will take an expression like - switch(str) - { - case "a": - case "b": - } - - and modify it to: - { - var execute_def = true; - switch(str.hashCode()) - { - case (hashcode of a): - if (str == "a") - { - execute_def = false; - ..code here - } //else if (str == otherVariableWithSameHashCode) { - ... - } - ... - } - if (execute_def) - { - ..default code - } - } - - this might actually be slower in some cases than a if/else approach, but it scales well and as a bonus, - hashCode in java are cached, so we only have the performance hit once to cache it. - *) - let change_string_switch gen eswitch e1 ecases edefault = - let basic = gen.gcon.basic in - let is_final_ret = is_final_return_expr false eswitch in - - let has_default = is_some edefault in - let block = ref [] in - let local = match e1.eexpr with - | TLocal _ -> e1 - | _ -> - let var = mk_temp gen "svar" e1.etype in - let added = { e1 with eexpr = TVars([var, Some(e1)]); etype = basic.tvoid } in - let local = mk_local var e1.epos in - block := added :: !block; - local - in - let execute_def_var = mk_temp gen "executeDef" gen.gcon.basic.tbool in - let execute_def = mk_local execute_def_var e1.epos in - let execute_def_set = { eexpr = TBinop(Ast.OpAssign, execute_def, { eexpr = TConst(TBool false); etype = basic.tbool; epos = e1.epos }); etype = basic.tbool; epos = e1.epos } in - - let hash_cache = ref None in - - let local_hashcode = ref { local with - eexpr = TCall({ local with - eexpr = TField(local, FDynamic "hashCode"); - etype = TFun([], basic.tint); - }, []); - etype = basic.tint - } in - - let get_hash_cache () = - match !hash_cache with - | Some c -> c - | None -> - let var = mk_temp gen "hash" basic.tint in - let cond = !local_hashcode in - block := { eexpr = TVars([var, Some cond]); etype = basic.tvoid; epos = local.epos } :: !block; - let local = mk_local var local.epos in - local_hashcode := local; - hash_cache := Some local; - local - in - - 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 has_conflict = ref false in - - let rec reorder_cases unordered ordered = - match unordered with - | [] -> ordered - | (el, e) :: tl -> - let current = Hashtbl.create 1 in - List.iter (fun e -> - let str = get_str e in - let hash = java_hash str in - Hashtbl.add current hash true - ) el; - - let rec extract_fields cases found_cases ret_cases = - match cases with - | [] -> found_cases, ret_cases - | (el, e) :: tl -> - if List.exists (fun e -> Hashtbl.mem current (java_hash (get_str e)) ) el then begin - has_conflict := true; - List.iter (fun e -> Hashtbl.add current (java_hash (get_str e)) true) el; - extract_fields tl ( (el, e) :: found_cases ) ret_cases - end else - extract_fields tl found_cases ( (el, e) :: ret_cases ) - in - let found, remaining = extract_fields tl [] [] in - let ret = if found <> [] then - let ret = List.sort (fun (e1,_) (e2,_) -> compare (List.length e2) (List.length e1) ) ( (el, e) :: found ) in - let rec loop ret acc = - match ret with - | (el, e) :: ( (_,_) :: _ as tl ) -> loop tl ( (true, el, e) :: acc ) - | (el, e) :: [] -> ( (false, el, e) :: acc ) - | _ -> assert false - in - List.rev (loop ret []) - else - (false, el, e) :: [] - in - - reorder_cases remaining (ordered @ ret) - in - - let already_in_cases = Hashtbl.create 0 in - let change_case (has_fallback, el, e) = - let conds, el = List.fold_left (fun (conds,el) e -> - has_case := true; - match e.eexpr with - | TConst(TString s) -> - let hashed = java_hash s in - let equals_test = { - eexpr = TCall({ e with eexpr = TField(local, FDynamic "equals"); etype = TFun(["obj",false,t_dynamic],basic.tbool) }, [ e ]); - etype = basic.tbool; - epos = e.epos - } in - - let hashed_expr = { eexpr = TConst(TInt hashed); etype = basic.tint; epos = e.epos } in - let hashed_exprs = if !has_conflict then begin - if Hashtbl.mem already_in_cases hashed then - el - else begin - Hashtbl.add already_in_cases hashed true; - hashed_expr :: el - end - end else hashed_expr :: el in - - let conds = match conds with - | None -> equals_test - | Some c -> - (* - if there is more than one case, we should test first if hash equals to the one specified. - This way we can save a heavier string compare - *) - let equals_test = mk_paren { - eexpr = TBinop(Ast.OpBoolAnd, { eexpr = TBinop(Ast.OpEq, get_hash_cache(), hashed_expr); etype = basic.tbool; epos = e.epos }, equals_test); - etype = basic.tbool; - epos = e.epos; - } in - - { eexpr = TBinop(Ast.OpBoolOr, equals_test, c); etype = basic.tbool; epos = e1.epos } - in - - Some conds, hashed_exprs - | _ -> assert false - ) (None,[]) el in - let e = if has_default then Codegen.concat execute_def_set e else e in - let e = if !has_conflict then Codegen.concat e { e with eexpr = TBreak; etype = basic.tvoid } else e in - let e = { - eexpr = TIf(get conds, e, None); - etype = basic.tvoid; - epos = e.epos - } in - - let e = if has_fallback then { e with eexpr = TBlock([ e; mk_local (alloc_var "__fallback__" t_dynamic) e.epos]) } else e in - - (el, e) - in - - let switch = { eswitch with - eexpr = TSwitch(!local_hashcode, List.map change_case (reorder_cases ecases []), None); - } in - (if !has_case then begin - (if has_default then block := { e1 with eexpr = TVars([execute_def_var, Some({ e1 with eexpr = TConst(TBool true); etype = basic.tbool })]); etype = basic.tvoid } :: !block); - block := switch :: !block - end); - (match edefault with - | None -> () - | Some edef when not !has_case -> - block := edef :: !block - | Some edef -> - let eelse = if is_final_ret then Some { eexpr = TThrow { eexpr = TConst(TNull); etype = t_dynamic; epos = edef.epos }; etype = basic.tvoid; epos = edef.epos } else None in - block := { edef with eexpr = TIf(execute_def, edef, eelse); etype = basic.tvoid } :: !block - ); - { eswitch with eexpr = TBlock(List.rev !block) } - - - let get_cl_from_t t = - match follow t with - | TInst(cl,_) -> cl - | _ -> assert false - - let traverse gen runtime_cl = - let basic = gen.gcon.basic in - let tchar = mt_to_t_dyn ( get_type gen (["java"], "Char16") ) 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 - let tsingle = mt_to_t_dyn ( get_type gen ([], "Single") ) in - let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in - - let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in - - let rec run e = - match e.eexpr with - (* for new NativeArray issues *) - | TNew(({ cl_path = (["java"], "NativeArray") } as cl), [t], el) when t_has_type_param t -> - mk_cast (TInst(cl,[t])) (mk_cast t_dynamic ({ e with eexpr = TNew(cl, [t_empty], List.map run el) })) - - (* Std.int() *) - | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) }, - [obj] - ) -> - run (mk_cast basic.tint obj) - (* end Std.int() *) - - | TField( ef, FInstance({ cl_path = ([], "String") }, { cf_name = "length" }) ) -> - { e with eexpr = TCall(Type.map_expr run e, []) } - | TField( ef, field ) when field_name field = "length" && is_string ef.etype -> - { e with eexpr = TCall(Type.map_expr run e, []) } - | TCall( ( { eexpr = TField(ef, field) } as efield ), args ) when is_string ef.etype && String.get (field_name field) 0 = '_' -> - let field = field_name field in - { e with eexpr = TCall({ efield with eexpr = TField(run ef, FDynamic (String.sub field 1 ( (String.length field) - 1)) )}, List.map run args) } - | TCall( ( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, field )) } as efield ), args ) -> - let field = field.cf_name in - (match field with - | "charAt" | "charCodeAt" | "split" | "indexOf" - | "lastIndexOf" | "substring" | "substr" -> - { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) } - | _ -> - { e with eexpr = TCall(run efield, List.map run args) } - ) - - | TCast(expr, m) when is_boxed_type e.etype -> - (* let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with *) - run { e with etype = unboxed_type gen e.etype tbyte tshort tchar tsingle } - - | TCast(expr, _) when is_bool e.etype -> - { - eexpr = TCall( - mk_static_field_access_infer runtime_cl "toBool" expr.epos [], - [ run expr ] - ); - etype = basic.tbool; - epos = e.epos - } - - | TCast(expr, _) when is_int_float gen e.etype && not (is_int_float gen expr.etype) -> - let needs_cast = match gen.gfollow#run_f e.etype with - | TInst _ -> false - | _ -> true - in - - let fun_name = if like_int e.etype then "toInt" else "toDouble" in - - let ret = { - eexpr = TCall( - mk_static_field_access_infer runtime_cl fun_name expr.epos [], - [ run expr ] - ); - etype = if fun_name = "toDouble" then basic.tfloat else basic.tint; - epos = expr.epos - } in - - if needs_cast then mk_cast e.etype ret else ret - - (*| TCast(expr, c) when is_int_float gen e.etype -> - (* cases when float x = (float) (java.lang.Double val); *) - (* FIXME: this fix is broken since it will fail on cases where float x = (float) (java.lang.Float val) or similar. FIX THIS *) - let need_second_cast = match gen.gfollow#run_f e.etype with - | TInst _ -> false - | _ -> true - in - if need_second_cast then { e with eexpr = TCast(mk_cast (follow e.etype) (run expr), c) } else Type.map_expr run e*) - | TBinop( (Ast.OpAssignOp OpAdd as op), e1, e2) - | TBinop( (Ast.OpAdd as op), e1, e2) when is_string e.etype || is_string e1.etype || is_string e2.etype -> - let is_assign = match op with Ast.OpAssignOp _ -> true | _ -> false in - let mk_to_string e = { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" e.epos [], [run e] ); etype = gen.gcon.basic.tstring } in - let check_cast e = match gen.greal_type e.etype with - | TDynamic _ - | TAbstract({ a_path = ([], "Float") }, []) - | TAbstract({ a_path = ([], "Single") }, []) -> - mk_to_string e - | _ -> run e - in - - { e with eexpr = TBinop(op, (if is_assign then run e1 else check_cast e1), check_cast e2) } - | TCast(expr, _) when is_string e.etype -> - { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) } - - | TSwitch(cond, ecases, edefault) when is_string cond.etype -> - (*let change_string_switch gen eswitch e1 ecases edefault =*) - change_string_switch gen e (run cond) (List.map (fun (el,e) -> (el, run e)) ecases) (Option.map run edefault) - - | TBinop( (Ast.OpNotEq as op), e1, e2) - | TBinop( (Ast.OpEq as op), e1, e2) when not (is_null e2 || is_null e1) && (is_string e1.etype || is_string e2.etype || is_equatable gen e1.etype || is_equatable gen e2.etype) -> - let static = mk_static_field_access_infer (runtime_cl) "valEq" e1.epos [] in - let eret = { eexpr = TCall(static, [run e1; run e2]); etype = gen.gcon.basic.tbool; epos=e.epos } in - if op = Ast.OpNotEq then { eret with eexpr = TUnop(Ast.Not, Ast.Prefix, eret) } else eret - - | TBinop( (Ast.OpNotEq | Ast.OpEq as op), e1, e2) when is_cl e1.etype && is_cl e2.etype -> - { e with eexpr = TBinop(op, mk_cast t_empty (run e1), mk_cast t_empty (run e2)) } - | _ -> Type.map_expr run e - in - run - - let configure gen (mapping_func:texpr->texpr) = - (if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false); - let map e = Some(mapping_func e) in - gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map + let name = "java_specific" + + let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DBefore IntDivisionSynf.priority ] + + let java_hash s = + let h = ref Int32.zero in + let thirtyone = Int32.of_int 31 in + for i = 0 to String.length s - 1 do + h := Int32.add (Int32.mul thirtyone !h) (Int32.of_int (int_of_char (String.unsafe_get s i))); + done; + !h + + let rec is_final_return_expr is_switch e = + let is_final_return_expr = is_final_return_expr is_switch in + match e.eexpr with + | TReturn _ + | TThrow _ -> true + (* this is hack to not use 'break' on switch cases *) + | TLocal { v_name = "__fallback__" } when is_switch -> true + | TCall( { eexpr = TLocal { v_name = "__goto__" } }, _ ) -> true + | TParenthesis p | TMeta (_,p) -> is_final_return_expr p + | TBlock bl -> is_final_return_block is_switch bl + | TSwitch (_, el_e_l, edef) -> + List.for_all (fun (_,e) -> is_final_return_expr e) el_e_l && Option.map_default is_final_return_expr false edef +(* | TMatch (_, _, il_vl_e_l, edef) -> + List.for_all (fun (_,_,e) -> is_final_return_expr e)il_vl_e_l && Option.map_default is_final_return_expr false edef *) + | TIf (_,eif, Some eelse) -> + is_final_return_expr eif && is_final_return_expr eelse + | TFor (_,_,e) -> + is_final_return_expr e + | TWhile (_,e,_) -> + is_final_return_expr e + | TFunction tf -> + is_final_return_expr tf.tf_expr + | TTry (e, ve_l) -> + is_final_return_expr e && List.for_all (fun (_,e) -> is_final_return_expr e) ve_l + | _ -> false + + and is_final_return_block is_switch el = + match el with + | [] -> false + | final :: [] -> is_final_return_expr is_switch final + | hd :: tl -> is_final_return_block is_switch tl + + let is_null e = match e.eexpr with | TConst(TNull) -> true | _ -> false + + let rec is_equatable gen t = + match follow t with + | TInst(cl,_) -> + if cl.cl_path = (["haxe";"lang"], "IEquatable") then + true + else + List.exists (fun (cl,p) -> is_equatable gen (TInst(cl,p))) cl.cl_implements + || (match cl.cl_super with | Some(cl,p) -> is_equatable gen (TInst(cl,p)) | None -> false) + | _ -> false + + (* + Changing string switch + will take an expression like + switch(str) + { + case "a": + case "b": + } + + and modify it to: + { + var execute_def = true; + switch(str.hashCode()) + { + case (hashcode of a): + if (str == "a") + { + execute_def = false; + ..code here + } //else if (str == otherVariableWithSameHashCode) { + ... + } + ... + } + if (execute_def) + { + ..default code + } + } + + this might actually be slower in some cases than a if/else approach, but it scales well and as a bonus, + hashCode in java are cached, so we only have the performance hit once to cache it. + *) + let change_string_switch gen eswitch e1 ecases edefault = + let basic = gen.gcon.basic in + let is_final_ret = is_final_return_expr false eswitch in + + let has_default = is_some edefault in + let block = ref [] in + let local = match e1.eexpr with + | TLocal _ -> e1 + | _ -> + let var = mk_temp gen "svar" e1.etype in + let added = { e1 with eexpr = TVar(var, Some(e1)); etype = basic.tvoid } in + let local = mk_local var e1.epos in + block := added :: !block; + local + in + let execute_def_var = mk_temp gen "executeDef" gen.gcon.basic.tbool in + let execute_def = mk_local execute_def_var e1.epos in + let execute_def_set = { eexpr = TBinop(Ast.OpAssign, execute_def, { eexpr = TConst(TBool false); etype = basic.tbool; epos = e1.epos }); etype = basic.tbool; epos = e1.epos } in + + let hash_cache = ref None in + + let local_hashcode = ref { local with + eexpr = TCall({ local with + eexpr = TField(local, FDynamic "hashCode"); + etype = TFun([], basic.tint); + }, []); + etype = basic.tint + } in + + let get_hash_cache () = + match !hash_cache with + | Some c -> c + | None -> + let var = mk_temp gen "hash" basic.tint in + let cond = !local_hashcode in + block := { eexpr = TVar(var, Some cond); etype = basic.tvoid; epos = local.epos } :: !block; + let local = mk_local var local.epos in + local_hashcode := local; + hash_cache := Some local; + local + in + + 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 has_conflict = ref false in + + let rec reorder_cases unordered ordered = + match unordered with + | [] -> ordered + | (el, e) :: tl -> + let current = Hashtbl.create 1 in + List.iter (fun e -> + let str = get_str e in + let hash = java_hash str in + Hashtbl.add current hash true + ) el; + + let rec extract_fields cases found_cases ret_cases = + match cases with + | [] -> found_cases, ret_cases + | (el, e) :: tl -> + if List.exists (fun e -> Hashtbl.mem current (java_hash (get_str e)) ) el then begin + has_conflict := true; + List.iter (fun e -> Hashtbl.add current (java_hash (get_str e)) true) el; + extract_fields tl ( (el, e) :: found_cases ) ret_cases + end else + extract_fields tl found_cases ( (el, e) :: ret_cases ) + in + let found, remaining = extract_fields tl [] [] in + let ret = if found <> [] then + let ret = List.sort (fun (e1,_) (e2,_) -> compare (List.length e2) (List.length e1) ) ( (el, e) :: found ) in + let rec loop ret acc = + match ret with + | (el, e) :: ( (_,_) :: _ as tl ) -> loop tl ( (true, el, e) :: acc ) + | (el, e) :: [] -> ( (false, el, e) :: acc ) + | _ -> assert false + in + List.rev (loop ret []) + else + (false, el, e) :: [] + in + + reorder_cases remaining (ordered @ ret) + in + + let already_in_cases = Hashtbl.create 0 in + let change_case (has_fallback, el, e) = + let conds, el = List.fold_left (fun (conds,el) e -> + has_case := true; + match e.eexpr with + | TConst(TString s) -> + let hashed = java_hash s in + let equals_test = { + eexpr = TCall({ e with eexpr = TField(local, FDynamic "equals"); etype = TFun(["obj",false,t_dynamic],basic.tbool) }, [ e ]); + etype = basic.tbool; + epos = e.epos + } in + + let hashed_expr = { eexpr = TConst(TInt hashed); etype = basic.tint; epos = e.epos } in + let hashed_exprs = if !has_conflict then begin + if Hashtbl.mem already_in_cases hashed then + el + else begin + Hashtbl.add already_in_cases hashed true; + hashed_expr :: el + end + end else hashed_expr :: el in + + let conds = match conds with + | None -> equals_test + | Some c -> + (* + if there is more than one case, we should test first if hash equals to the one specified. + This way we can save a heavier string compare + *) + let equals_test = mk_paren { + eexpr = TBinop(Ast.OpBoolAnd, { eexpr = TBinop(Ast.OpEq, get_hash_cache(), hashed_expr); etype = basic.tbool; epos = e.epos }, equals_test); + etype = basic.tbool; + epos = e.epos; + } in + + { eexpr = TBinop(Ast.OpBoolOr, equals_test, c); etype = basic.tbool; epos = e1.epos } + in + + Some conds, hashed_exprs + | _ -> assert false + ) (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 + let e = { + eexpr = TIf(get conds, e, None); + etype = basic.tvoid; + epos = e.epos + } in + + let e = if has_fallback then { e with eexpr = TBlock([ e; mk_local (alloc_var "__fallback__" t_dynamic) e.epos]) } else e in + + (el, e) + in + + let switch = { eswitch with + eexpr = TSwitch(!local_hashcode, List.map change_case (reorder_cases ecases []), None); + } in + (if !has_case then begin + (if has_default then block := { e1 with eexpr = TVar(execute_def_var, Some({ e1 with eexpr = TConst(TBool true); etype = basic.tbool })); etype = basic.tvoid } :: !block); + block := switch :: !block + end); + (match edefault with + | None -> () + | Some edef when not !has_case -> + block := edef :: !block + | Some edef -> + let eelse = if is_final_ret then Some { eexpr = TThrow { eexpr = TConst(TNull); etype = t_dynamic; epos = edef.epos }; etype = basic.tvoid; epos = edef.epos } else None in + block := { edef with eexpr = TIf(execute_def, edef, eelse); etype = basic.tvoid } :: !block + ); + { eswitch with eexpr = TBlock(List.rev !block) } + + + let get_cl_from_t t = + match follow t with + | TInst(cl,_) -> cl + | _ -> assert false + + let traverse gen runtime_cl = + let basic = gen.gcon.basic in + (* let tchar = mt_to_t_dyn ( get_type gen (["java"], "Char16") ) 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 *) + (* let tsingle = mt_to_t_dyn ( get_type gen ([], "Single") ) in *) + let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in + + let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in + + let rec run e = + match e.eexpr with + (* for new NativeArray issues *) + | TNew(({ cl_path = (["java"], "NativeArray") } as cl), [t], el) when is_type_param t -> + mk_cast (TInst(cl,[t])) (mk_cast t_dynamic ({ e with eexpr = TNew(cl, [t_empty], List.map run el) })) + + (* Std.int() *) + | TCall( + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" })) }, + [obj] + ) -> + run (mk_cast basic.tint obj) + (* end Std.int() *) + + | TField( ef, FInstance({ cl_path = ([], "String") }, _, { cf_name = "length" }) ) -> + { e with eexpr = TCall(Type.map_expr run e, []) } + | TField( ef, field ) when field_name field = "length" && is_string ef.etype -> + { e with eexpr = TCall(Type.map_expr run e, []) } + | TCall( ( { eexpr = TField(ef, field) } as efield ), args ) when is_string ef.etype && String.get (field_name field) 0 = '_' -> + let field = field_name field in + { e with eexpr = TCall({ efield with eexpr = TField(run ef, FDynamic (String.sub field 1 ( (String.length field) - 1)) )}, List.map run args) } + | TCall( ( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, _, field )) } as efield ), args ) -> + let field = field.cf_name in + (match field with + | "charAt" | "charCodeAt" | "split" | "indexOf" + | "lastIndexOf" | "substring" | "substr" -> + { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) } + | _ -> + { e with eexpr = TCall(run efield, List.map run args) } + ) +(* | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("toString") })) }, [] ) -> + run ef *) + + (* | TCast(expr, m) when is_boxed_type e.etype -> *) + (* (* let unboxed_type gen t tbyte tshort tchar tfloat = match follow t with *) *) + (* run { e with etype = unboxed_type gen e.etype tbyte tshort tchar tsingle } *) + + | TCast(expr, _) when is_bool e.etype -> + { + eexpr = TCall( + mk_static_field_access_infer runtime_cl "toBool" expr.epos [], + [ run expr ] + ); + etype = basic.tbool; + epos = e.epos + } + + | TCast(expr, _) when is_int_float gen e.etype && not (is_int_float gen expr.etype) -> + let needs_cast = match gen.gfollow#run_f e.etype with + | TInst _ -> false + | _ -> true + in + + let fun_name = if like_int e.etype then "toInt" else "toDouble" in + + let ret = { + eexpr = TCall( + mk_static_field_access_infer runtime_cl fun_name expr.epos [], + [ run expr ] + ); + etype = if fun_name = "toDouble" then basic.tfloat else basic.tint; + epos = expr.epos + } in + + if needs_cast then mk_cast e.etype ret else ret + + (*| TCast(expr, c) when is_int_float gen e.etype -> + (* cases when float x = (float) (java.lang.Double val); *) + (* FIXME: this fix is broken since it will fail on cases where float x = (float) (java.lang.Float val) or similar. FIX THIS *) + let need_second_cast = match gen.gfollow#run_f e.etype with + | TInst _ -> false + | _ -> true + in + if need_second_cast then { e with eexpr = TCast(mk_cast (follow e.etype) (run expr), c) } else Type.map_expr run e*) + | TBinop( (Ast.OpAssignOp OpAdd as op), e1, e2) + | TBinop( (Ast.OpAdd as op), e1, e2) when is_string e.etype || is_string e1.etype || is_string e2.etype -> + let is_assign = match op with Ast.OpAssignOp _ -> true | _ -> false in + let mk_to_string e = { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" e.epos [], [run e] ); etype = gen.gcon.basic.tstring } in + let check_cast e = match gen.greal_type e.etype with + | TDynamic _ + | TAbstract({ a_path = ([], "Float") }, []) + | TAbstract({ a_path = ([], "Single") }, []) -> + mk_to_string e + | _ -> run e + in + + { e with eexpr = TBinop(op, (if is_assign then run e1 else check_cast e1), check_cast e2) } + | TCast(expr, _) when is_string e.etype -> + { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) } + + | TSwitch(cond, ecases, edefault) when is_string cond.etype -> + (*let change_string_switch gen eswitch e1 ecases edefault =*) + change_string_switch gen e (run cond) (List.map (fun (el,e) -> (el, run e)) ecases) (Option.map run edefault) + + | TBinop( (Ast.OpNotEq as op), e1, e2) + | TBinop( (Ast.OpEq as op), e1, e2) when not (is_null e2 || is_null e1) && (is_string e1.etype || is_string e2.etype || is_equatable gen e1.etype || is_equatable gen e2.etype) -> + let static = mk_static_field_access_infer (runtime_cl) "valEq" e1.epos [] in + let eret = { eexpr = TCall(static, [run e1; run e2]); etype = gen.gcon.basic.tbool; epos=e.epos } in + if op = Ast.OpNotEq then { eret with eexpr = TUnop(Ast.Not, Ast.Prefix, eret) } else eret + + | TBinop( (Ast.OpNotEq | Ast.OpEq as op), e1, e2) when is_cl e1.etype && is_cl e2.etype -> + { e with eexpr = TBinop(op, mk_cast t_empty (run e1), mk_cast t_empty (run e2)) } + | _ -> Type.map_expr run e + in + run + + let configure gen (mapping_func:texpr->texpr) = + (if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false); + let map e = Some(mapping_func e) in + gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map end;; + +(* ******************************************* *) +(* handle @:throws *) +(* ******************************************* *) +let rec is_checked_exc cl = + match cl.cl_path with + | ["java";"lang"],"RuntimeException" -> + false + | ["java";"lang"],"Throwable" -> + true + | _ -> match cl.cl_super with + | None -> false + | Some(c,_) -> is_checked_exc c + +let rec cls_any_super cl supers = + PMap.mem cl.cl_path supers || match cl.cl_super with + | None -> false + | Some(c,_) -> cls_any_super c supers + +let rec handle_throws gen cf = + List.iter (handle_throws gen) cf.cf_overloads; + match cf.cf_expr with + | Some ({ eexpr = TFunction(tf) } as e) -> + let rec collect_throws acc = function + | (Meta.Throws, [Ast.EConst (Ast.String path), _],_) :: meta -> (try + collect_throws (get_cl ( get_type gen (parse_path path)) :: acc) meta + with | Not_found | TypeNotFound _ -> + collect_throws acc meta) + | [] -> + acc + | _ :: meta -> + collect_throws acc meta + in + let cf_throws = collect_throws [] cf.cf_meta in + let throws = ref (List.fold_left (fun map cl -> + PMap.add cl.cl_path cl map + ) PMap.empty cf_throws) in + let rec iter e = match e.eexpr with + | TTry(etry,ecatches) -> + let old = !throws in + let needs_check_block = ref true in + List.iter (fun (v,e) -> + Type.iter iter e; + match follow (run_follow gen v.v_type) with + | TInst({ cl_path = ["java";"lang"],"Throwable" },_) + | TDynamic _ -> + needs_check_block := false + | TInst(c,_) when is_checked_exc c -> + throws := PMap.add c.cl_path c !throws + | _ ->() + ) ecatches; + if !needs_check_block then Type.iter iter etry; + throws := old + | TField(e, (FInstance(_,_,f) | FStatic(_,f) | FClosure(_,f))) -> + let tdefs = collect_throws [] f.cf_meta in + if tdefs <> [] && not (List.for_all (fun c -> cls_any_super c !throws) tdefs) then + raise Exit; + Type.iter iter e + | TThrow e -> (match follow (run_follow gen e.etype) with + | TInst(c,_) when is_checked_exc c && not (cls_any_super c !throws) -> + raise Exit + | _ -> iter e) + | _ -> Type.iter iter e + in + (try + Type.iter iter e + with | Exit -> (* needs typed exception to be caught *) + let throwable = get_cl (get_type gen (["java";"lang"],"Throwable")) 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 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) } + in + cf.cf_expr <- Some { e with + eexpr = TFunction({ tf with + tf_expr = mk_block { tf.tf_expr with eexpr = TTry(tf.tf_expr, List.map (map_throws) cf_throws @ [catch_var, wrapped]) } + }) + }) + | _ -> () + + let connecting_string = "?" (* ? see list here http://www.fileformat.info/info/unicode/category/index.htm and here for C# http://msdn.microsoft.com/en-us/library/aa664670.aspx *) -let default_package = "java" (* I'm having this separated as I'm still not happy with having a cs package. Maybe dotnet would be better? *) +let default_package = "java" let strict_mode = ref false (* strict mode is so we can check for unexpected information *) -(* reserved c# words *) +(* reserved java words *) let reserved = let res = Hashtbl.create 120 in - List.iter (fun lst -> Hashtbl.add res lst ("_" ^ lst)) ["abstract"; "assert"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class"; - "const"; "continue"; "default"; "do"; "double"; "else"; "enum"; "extends"; "final"; - "false"; "finally"; "float"; "for"; "goto"; "if"; "implements"; "import"; "instanceof"; "int"; - "interface"; "long"; "native"; "new"; "null"; "package"; "private"; "protected"; "public"; "return"; "short"; - "static"; "strictfp"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; "transient"; "true"; "try"; - "void"; "volatile"; "while"; ]; - res + List.iter (fun lst -> Hashtbl.add res lst ("_" ^ lst)) ["abstract"; "assert"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class"; + "const"; "continue"; "default"; "do"; "double"; "else"; "enum"; "extends"; "final"; + "false"; "finally"; "float"; "for"; "goto"; "if"; "implements"; "import"; "instanceof"; "int"; + "interface"; "long"; "native"; "new"; "null"; "package"; "private"; "protected"; "public"; "return"; "short"; + "static"; "strictfp"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; "transient"; "true"; "try"; + "void"; "volatile"; "while"; ]; + res let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } ) let rec get_class_modifiers meta cl_type cl_access cl_modifiers = - match meta with - | [] -> cl_type,cl_access,cl_modifiers - (*| (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers*) - | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers - | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "" cl_modifiers - (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) - | (Meta.Static,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *) - | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("final" :: cl_modifiers) - | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers + match meta with + | [] -> cl_type,cl_access,cl_modifiers + (*| (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers*) + | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers + | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "" cl_modifiers + (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers) + | (Meta.Static,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *) + | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("final" :: cl_modifiers) + | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers let rec get_fun_modifiers meta access modifiers = - match meta with - | [] -> access,modifiers - | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers - | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "" modifiers - (*| (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers)*) - (*| (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)*) - | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers) - | (Meta.Transient,[],_) :: meta -> get_fun_modifiers meta access ("transient" :: modifiers) - | _ :: meta -> get_fun_modifiers meta access modifiers + match meta with + | [] -> access,modifiers + | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers + | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "" modifiers + | (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("final" :: modifiers) + (*| (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: 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 -> get_fun_modifiers meta access modifiers (* this was the way I found to pass the generator context to be accessible across all functions here *) (* so 'configure' is almost 'top-level' and will have all functions needed to make this work *) let configure gen = - let basic = gen.gcon.basic in - - let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in - - let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in - - (*let string_ref = get_cl ( get_type gen (["haxe";"lang"], "StringRefl")) in*) - - let ti64 = match ( get_type gen (["haxe";"_Int64"], "NativeInt64") ) with | TTypeDecl t -> TType(t,[]) | _ -> assert false in - - let has_tdynamic params = - List.exists (fun e -> match run_follow gen e with | TDynamic _ -> true | _ -> false) params - in - - (* - The type parameters always need to be changed to their boxed counterparts - *) - let change_param_type md params = - match md with - | TClassDecl( { cl_path = (["java"], "NativeArray") } ) -> params - | _ -> - match params with - | [] -> [] - | _ -> - if has_tdynamic params then List.map (fun _ -> t_dynamic) params else - List.map (fun t -> - let f_t = gen.gfollow#run_f t in - match f_t with - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) - | TInst ({ cl_path = ["haxe"],"Int32" },[]) - | TInst ({ cl_path = ["haxe"],"Int64" },[]) - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TType ({ t_path = ["java"],"Int8" },[]) - | TAbstract ({ a_path = ["java"],"Int8" },[]) - | TType ({ t_path = ["java"],"Int16" },[]) - | TAbstract ({ a_path = ["java"],"Int16" },[]) - | TType ({ t_path = ["java"],"Char16" },[]) - | TAbstract ({ a_path = ["java"],"Char16" },[]) - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) -> - basic.tnull f_t - (*| TType ({ t_path = [], "Null"*) - | TInst (cl, ((_ :: _) as p)) -> - TInst(cl, List.map (fun _ -> t_dynamic) p) - | TEnum (e, ((_ :: _) as p)) -> - TEnum(e, List.map (fun _ -> t_dynamic) p) - | _ -> t - ) params - in - - let change_clname name = - String.map (function | '$' -> '.' | c -> c) name - in - let change_id name = try Hashtbl.find reserved name with | Not_found -> name in - let rec change_ns ns = match ns with - | [] -> ["haxe"; "root"] - | _ -> List.map change_id ns - in - let change_field = change_id in - - let write_id w name = write w (change_id name) in - - let write_field w name = write w (change_field name) in - - gen.gfollow#add ~name:"follow_basic" (fun t -> match t with - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) - | TEnum ({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TType ({ t_path = ["java"],"Int8" },[]) - | TAbstract ({ a_path = ["java"],"Int8" },[]) - | TType ({ t_path = ["java"],"Int16" },[]) - | TAbstract ({ a_path = ["java"],"Int16" },[]) - | TType ({ t_path = ["java"],"Char16" },[]) - | TAbstract ({ a_path = ["java"],"Char16" },[]) - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) - | TType ({ t_path = [],"Null" },[_]) -> Some t - | TAbstract ({ a_impl = Some _ } as a, pl) -> - Some (gen.gfollow#run_f ( Codegen.Abstract.get_underlying_type a pl) ) - | TAbstract( { a_path = ([], "EnumValue") }, _ ) - | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic - | _ -> None); - - let change_path path = (change_ns (fst path), change_clname (snd path)) in - - let path_s path = match path with - | (ns,clname) -> path_s (change_ns ns, change_clname clname) - in - - let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in - - let rec real_type t = - let t = gen.gfollow#run_f t in - match t with - | TAbstract ({ a_impl = Some _ } as a, pl) -> - real_type (Codegen.Abstract.get_underlying_type a pl) - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64 - | TAbstract( { a_path = ([], "Class") }, p ) - | TAbstract( { a_path = ([], "Enum") }, p ) - | TInst( { cl_path = ([], "Class") }, p ) - | TInst( { cl_path = ([], "Enum") }, p ) -> TInst(cl_cl,p) - | TEnum(e,params) -> TEnum(e, List.map (fun _ -> t_dynamic) params) - | TInst(c,params) when Meta.has Meta.Enum c.cl_meta -> - TInst(c, List.map (fun _ -> t_dynamic) params) - | TInst _ -> t - | TType({ t_path = ([], "Null") }, [t]) when is_java_basic_type t -> t_dynamic - | TType({ t_path = ([], "Null") }, [t]) -> - (match follow t with - | TInst( { cl_kind = KTypeParameter _ }, []) -> - (* t_dynamic *) - real_type t - | _ -> real_type t - ) - | TType _ | TAbstract _ -> t - | TAnon (anon) -> (match !(anon.a_status) with - | Statics _ | EnumStatics _ | AbstractStatics _ -> t - | _ -> t_dynamic) - | TFun _ -> TInst(fn_cl,[]) - | _ -> t_dynamic - in - - let scope = ref PMap.empty in - let imports = ref [] in - - let clear_scope () = - scope := PMap.empty; - imports := []; - in - - let add_scope name = - scope := PMap.add name () !scope - in - - let add_import pos path = - let name = snd path in - let rec loop = function - | (pack, n) :: _ when name = n -> - if path <> (pack,n) then - gen.gcon.error ("This expression cannot be generated because " ^ path_s path ^ " is shadowed by the current scope and ") pos - | _ :: tl -> - loop tl - | [] -> - (* add import *) - imports := path :: !imports - in - loop !imports - in - - let path_s_import pos path = match path with - | [], name when PMap.mem name !scope -> - gen.gcon.error ("This expression cannot be generated because " ^ name ^ " is shadowed by the current scope") pos; - name - | pack1 :: _, name when PMap.mem pack1 !scope -> (* exists in scope *) - add_import pos path; - (* check if name exists in scope *) - if PMap.mem name !scope then - gen.gcon.error ("This expression cannot be generated because " ^ pack1 ^ " and " ^ name ^ " are both shadowed by the current scope") pos; - name - | _ -> path_s path - in - - let is_dynamic t = match real_type t with - | TMono _ | TDynamic _ -> true - | TAnon anon -> - (match !(anon.a_status) with - | EnumStatics _ | Statics _ | AbstractStatics _ -> false - | _ -> true - ) - | _ -> false - in - - let rec t_s pos t = - match real_type t with - (* basic types *) - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean" - | TEnum ({ e_path = ([], "Void") }, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> - path_s_import pos (["java";"lang"], "Object") - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) -> "double" - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) -> "int" - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long" - | TType ({ t_path = ["java"],"Int8" },[]) - | TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte" - | TType ({ t_path = ["java"],"Int16" },[]) - | TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short" - | TType ({ t_path = ["java"],"Char16" },[]) - | TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char" - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) -> "float" - | TInst ({ cl_path = ["haxe"],"Int32" },[]) - | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int" - | TInst ({ cl_path = ["haxe"],"Int64" },[]) - | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long" - | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> - let rec check_t_s t = - match real_type t with - | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> - (check_t_s param) ^ "[]" - | _ -> t_s pos (run_follow gen t) - in - (check_t_s param) ^ "[]" - - (* end of basic types *) - | 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 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]) - | TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) -> - path_param_s pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p] - | TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _) - | TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) -> - path_s_import pos (["java";"lang"], "Class") - | TEnum ({e_path = p}, _) -> - path_s_import pos p - | TInst (({cl_path = p;} as cl), _) when Meta.has Meta.Enum cl.cl_meta -> - path_s_import pos p - | TInst (({cl_path = p;} as cl), params) -> (path_param_s pos (TClassDecl cl) p params) - | TType (({t_path = p;} as t), params) -> (path_param_s pos (TTypeDecl t) p params) - | TAnon (anon) -> - (match !(anon.a_status) with - | Statics _ | EnumStatics _ | AbstractStatics _ -> - path_s_import pos (["java";"lang"], "Class") - | _ -> - path_s_import pos (["java";"lang"], "Object")) - | 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) ^ " ]" - - and param_t_s pos t = - match run_follow gen t with - | TEnum ({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> - path_s_import pos (["java";"lang"], "Boolean") - | TInst ({ cl_path = ([],"Float") },[]) - | TAbstract ({ a_path = ([],"Float") },[]) -> - path_s_import pos (["java";"lang"], "Double") - | TInst ({ cl_path = ([],"Int") },[]) - | TAbstract ({ a_path = ([],"Int") },[]) -> - path_s_import pos (["java";"lang"], "Integer") - | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) - | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> - path_s_import pos (["java";"lang"], "Long") - | TInst ({ cl_path = ["haxe"],"Int64" },[]) - | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> - path_s_import pos (["java";"lang"], "Long") - | TInst ({ cl_path = ["haxe"],"Int32" },[]) - | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> - path_s_import pos (["java";"lang"], "Integer") - | TType ({ t_path = ["java"],"Int8" },[]) - | TAbstract ({ a_path = ["java"],"Int8" },[]) -> - path_s_import pos (["java";"lang"], "Byte") - | TType ({ t_path = ["java"],"Int16" },[]) - | TAbstract ({ a_path = ["java"],"Int16" },[]) -> - path_s_import pos (["java";"lang"], "Short") - | TType ({ t_path = ["java"],"Char16" },[]) - | TAbstract ({ a_path = ["java"],"Char16" },[]) -> - path_s_import pos (["java";"lang"], "Character") - | TType ({ t_path = [],"Single" },[]) - | TAbstract ({ a_path = [],"Single" },[]) -> - path_s_import pos (["java";"lang"], "Float") - | TDynamic _ -> "?" - | TInst (cl, params) -> t_s pos (TInst(cl, change_param_type (TClassDecl cl) params)) - | TType (cl, params) -> t_s pos (TType(cl, change_param_type (TTypeDecl cl) params)) - | TEnum (e, params) -> t_s pos (TEnum(e, change_param_type (TEnumDecl e) params)) - | _ -> t_s pos t - - and path_param_s pos md path params = - match params with - | [] -> path_s_import pos path - | _ when has_tdynamic (change_param_type md params) -> path_s_import pos path - | _ -> sprintf "%s<%s>" (path_s_import pos path) (String.concat ", " (List.map (fun t -> param_t_s pos t) (change_param_type md params))) - in - - let rett_s pos t = - match t with - | TEnum ({e_path = ([], "Void")}, []) - | TAbstract ({ a_path = ([], "Void") },[]) -> "void" - | _ -> t_s pos t - in - - let escape ichar b = - match ichar with - | 92 (* \ *) -> Buffer.add_string b "\\\\" - | 39 (* ' *) -> Buffer.add_string b "\\\'" - | 34 -> Buffer.add_string b "\\\"" - | 13 (* \r *) -> Buffer.add_string b "\\r" - | 10 (* \n *) -> Buffer.add_string b "\\n" - | 9 (* \t *) -> Buffer.add_string b "\\t" - | c when c < 32 || c >= 127 -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c) - | c -> Buffer.add_char b (Char.chr c) - in - - let escape s = - let b = Buffer.create 0 in - (try - UTF8.validate s; - UTF8.iter (fun c -> escape (UChar.code c) b) s - with - UTF8.Malformed_code -> - String.iter (fun c -> escape (Char.code c) b) s - ); - Buffer.contents b - in - - let has_semicolon e = - match e.eexpr with - | TLocal { v_name = "__fallback__" } - | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false - | TBlock _ | TFor _ | TSwitch _ | TMatch _ | TTry _ | TIf _ -> false - | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false - | _ -> true - in - - let in_value = ref false in - - let rec md_s pos md = - let md = follow_module (gen.gfollow#run_f) md in - match md with - | TClassDecl (cl) -> - t_s pos (TInst(cl,[])) - | TEnumDecl (e) -> - t_s pos (TEnum(e,[])) - | TTypeDecl t -> - t_s pos (TType(t, [])) - | TAbstractDecl a -> - t_s pos (TAbstract(a, [])) - in - - (* - it seems that Java doesn't like when you create a new array with the type parameter defined - so we'll just ignore all type parameters, and hope for the best! - *) - let rec transform_nativearray_t t = match real_type t with - | TInst( ({ cl_path = (["java"], "NativeArray") } as narr), [t]) -> - TInst(narr, [transform_nativearray_t t]) - | TInst(cl, params) -> TInst(cl, List.map (fun _ -> t_dynamic) params) - | TEnum(e, params) -> TEnum(e, List.map (fun _ -> t_dynamic) params) - | TType(t, params) -> TType(t, List.map (fun _ -> t_dynamic) params) - | _ -> t - in - - let expr_s w e = - in_value := false; - let rec expr_s w e = - let was_in_value = !in_value in - in_value := true; - match e.eexpr with - | TConst c -> - (match c with - | TInt i32 -> - print w "%ld" i32; - (match real_type e.etype with - | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L"; - | _ -> () - ) - | TFloat s -> - write w s; - (* fix for Int notation, which only fit in a Float *) - (if not (String.contains s '.' || String.contains s 'e' || String.contains s 'E') then write w ".0"); - (match real_type e.etype with - | TType( { t_path = ([], "Single") }, [] ) -> write w "f" - | _ -> () - ) - | TString s -> print w "\"%s\"" (escape s) - | TBool b -> write w (if b then "true" else "false") - | TNull -> - (match real_type e.etype with - | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) - | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> write w "0L" - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst({ cl_path = ([], "Int") },[]) - | TAbstract ({ a_path = ([], "Int") },[]) -> expr_s w ({ e with eexpr = TConst(TInt Int32.zero) }) - | TInst({ cl_path = ([], "Float") },[]) - | TAbstract ({ a_path = ([], "Float") },[]) -> expr_s w ({ e with eexpr = TConst(TFloat "0.0") }) - | TEnum({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> write w "false" - | TAbstract _ when like_int e.etype -> - expr_s w { e with eexpr = TConst(TInt Int32.zero) } - | TAbstract _ when like_float e.etype -> - expr_s w { e with eexpr = TConst(TFloat "0.0") } - | _ -> write w "null") - | TThis -> write w "this" - | TSuper -> write w "super") - | TLocal { v_name = "__fallback__" } -> () - | TLocal { v_name = "__sbreak__" } -> write w "break" - | TLocal { v_name = "__undefined__" } -> - write w (t_s e.epos (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types))); - write w ".undefined"; - | TLocal var -> - write_id w var.v_name - | TField(_, FEnum(en,ef)) -> - let s = ef.ef_name in - print w "%s." (path_s_import e.epos en.e_path); write_field w s - | TArray (e1, e2) -> - expr_s w e1; write w "["; expr_s w e2; write w "]" - | TBinop ((Ast.OpAssign as op), e1, e2) - | TBinop ((Ast.OpAssignOp _ as op), e1, e2) -> - expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2 - | TBinop (op, e1, e2) -> - write w "( "; - expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2; - write w " )" - | TField (e, FStatic(_, cf)) when Meta.has Meta.Native cf.cf_meta -> - let rec loop meta = match meta with - | (Meta.Native, [EConst (String s), _],_) :: _ -> - expr_s w e; write w "."; write_field w s - | _ :: tl -> loop tl - | [] -> expr_s w e; write w "."; write_field w (cf.cf_name) - in - loop cf.cf_meta - | TField (e, s) -> - expr_s w e; write w "."; write_field w (field_name s) - | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int32") }) -> - write w (path_s_import e.epos (["haxe"], "Int32")) - | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int64") }) -> - write w (path_s_import e.epos (["haxe"], "Int64")) - | TTypeExpr mt -> write w (md_s e.epos mt) - | TParenthesis e -> - write w "("; expr_s w e; write w ")" - | TArrayDecl el when t_has_type_param_shallow false e.etype -> - print w "( (%s) (new java.lang.Object[] " (t_s e.epos e.etype); - write w "{"; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w "}) )" - | TArrayDecl el -> - print w "new %s" (param_t_s e.epos (transform_nativearray_t e.etype)); - let is_double = match follow e.etype with - | TInst(_,[ t ]) -> if like_float t && not (like_int t) then Some t else None - | _ -> None - in - - write w "{"; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - (* this is a hack so we are able to convert ints to boxed Double / Float when needed *) - let e = if is_some is_double then mk_cast (get is_double) e else e in - - expr_s w e; - acc + 1 - ) 0 el); - write w "}" - | TCall( ( { eexpr = TField(_, FStatic({ cl_path = ([], "String") }, { cf_name = "fromCharCode" })) } ), [cc] ) -> - write w "Character.toString((char) "; - expr_s w cc; - write w ")" - | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> - write w "( "; - expr_s w expr; - write w " instanceof "; - write w (md_s e.epos md); - write w " )" - | TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) -> - write w s - | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) -> - write w "synchronized("; - expr_s w eobj; - write w ")"; - expr_s w (mk_block eblock) - | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> - print w "break label%ld" v - | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> - print w "label%ld:" v - | TCall ({ eexpr = TLocal( { v_name = "__typeof__" } ) }, [ { eexpr = TTypeExpr md } as expr ] ) -> - expr_s w expr; - write w ".class" - | TCall (e, el) -> - let rec extract_tparams params el = - match el with - | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl -> - extract_tparams (tp.etype :: params) tl - | _ -> (params, el) - in - let params, el = extract_tparams [] el in - - expr_s w e; - - (*(match params with - | [] -> () - | params -> - let md = match e.eexpr with - | TField(ef, _) -> t_to_md (run_follow gen ef.etype) - | _ -> assert false - in - write w "<"; - ignore (List.fold_left (fun acc t -> - (if acc <> 0 then write w ", "); - write w (param_t_s (change_param_type md t)); - acc + 1 - ) 0 params); - write w ">" - );*) - - write w "("; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w ")" - | TNew (({ cl_path = (["java"], "NativeArray") } as cl), params, [ size ]) -> - let rec check_t_s t times = - match real_type t with - | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> - (check_t_s param (times+1)) - | _ -> - print w "new %s[" (t_s e.epos (transform_nativearray_t t)); - expr_s w size; - print w "]"; - let rec loop i = - if i <= 0 then () else (write w "[]"; loop (i-1)) - in - loop (times - 1) - in - check_t_s (TInst(cl, params)) 0 - | TNew ({ cl_path = ([], "String") } as cl, [], el) -> - write w "new "; - write w (t_s e.epos (TInst(cl, []))); - write w "("; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w ")" - | TNew (cl, params, el) -> - write w "new "; - write w (path_param_s e.epos (TClassDecl cl) cl.cl_path params); - write w "("; - ignore (List.fold_left (fun acc e -> - (if acc <> 0 then write w ", "); - expr_s w e; - acc + 1 - ) 0 el); - write w ")" - | TUnop ((Ast.Increment as op), flag, e) - | TUnop ((Ast.Decrement as op), flag, e) -> - (match flag with - | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e - | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op)) - | TUnop (op, flag, e) -> - (match flag with - | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") " - | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op)) - | TVars (v_eop_l) -> - ignore (List.fold_left (fun acc (var, eopt) -> - (if acc <> 0 then write w "; "); - print w "%s " (t_s e.epos var.v_type); - write_id w var.v_name; - (match eopt with - | None -> - write w " = "; - expr_s w (null var.v_type e.epos) - | Some e -> - write w " = "; - expr_s w e - ); - acc + 1 - ) 0 v_eop_l); - | TBlock [e] when was_in_value -> - expr_s w e - | TBlock el -> - begin_block w; - (*let last_line = ref (-1) in - let line_directive p = - let cur_line = Lexer.get_error_line p in - let is_relative_path = (String.sub p.pfile 0 1) = "." in - let file = if is_relative_path then "../" ^ p.pfile else p.pfile in - if cur_line <> ((!last_line)+1) then begin print w "//#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end; - last_line := cur_line in*) - List.iter (fun e -> - (*line_directive e.epos;*) - in_value := false; - (match e.eexpr with - | TConst _ -> () - | _ -> - expr_s w e; - (if has_semicolon e then write w ";"); - newline w); - ) el; - end_block w - | TIf (econd, e1, Some(eelse)) when was_in_value -> - write w "( "; - expr_s w (mk_paren econd); - write w " ? "; - expr_s w (mk_paren e1); - write w " : "; - expr_s w (mk_paren eelse); - write w " )"; - | TIf (econd, e1, eelse) -> - write w "if "; - expr_s w (mk_paren econd); - write w " "; - in_value := false; - expr_s w (mk_block e1); - (match eelse with - | None -> () - | Some e -> - write w " else "; - in_value := false; - expr_s w (mk_block e) - ) - | TWhile (econd, eblock, flag) -> - (match flag with - | Ast.NormalWhile -> - write w "while "; - expr_s w (mk_paren econd); - write w ""; - in_value := false; - expr_s w (mk_block eblock) - | Ast.DoWhile -> - write w "do "; - in_value := false; - expr_s w (mk_block eblock); - write w "while "; - in_value := true; - expr_s w (mk_paren econd); - ) - | TSwitch (econd, ele_l, default) -> - write w "switch "; - expr_s w (mk_paren econd); - begin_block w; - List.iter (fun (el, e) -> - List.iter (fun e -> - write w "case "; - in_value := true; - expr_s w e; - write w ":"; - ) el; - newline w; - in_value := false; - expr_s w (mk_block e); - newline w; - newline w - ) ele_l; - if is_some default then begin - write w "default:"; - newline w; - in_value := false; - expr_s w (get default); - newline w; - end; - end_block w - | TTry (tryexpr, ve_l) -> - write w "try "; - in_value := false; - expr_s w (mk_block tryexpr); - let pos = e.epos in - List.iter (fun (var, e) -> - print w "catch (%s %s)" (t_s pos var.v_type) (var.v_name); - in_value := false; - expr_s w (mk_block e); - newline w - ) ve_l - | TReturn eopt -> - write w "return "; - if is_some eopt then expr_s w (get eopt) - | TBreak -> write w "break" - | TContinue -> write w "continue" - | TThrow e -> - write w "throw "; - expr_s w e - | TCast (e1,md_t) -> - ((*match gen.gfollow#run_f e.etype with - | TType({ t_path = ([], "UInt") }, []) -> - write w "( unchecked ((uint) "; - expr_s w e1; - write w ") )" - | _ ->*) - (* FIXME I'm ignoring module type *) - print w "((%s) (" (t_s e.epos e.etype); - expr_s w e1; - write w ") )" - ) - | TFor (_,_,content) -> - 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 - | TMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false - in - expr_s w e - in - - let get_string_params cl_types = - match cl_types with - | [] -> - ("","") - | _ -> - let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_types)) in - let params_extends = List.fold_left (fun acc (name, t) -> - match run_follow gen t with - | TInst (cl, p) -> - (match cl.cl_implements with - | [] -> 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 Ast.null_pos t); assert false (* FIXME it seems that a cl_types will never be anything other than cl.cl_types. I'll take the risk and fail if not, just to see if that confirms *) - ) [] cl_types in - (params, String.concat " " params_extends) - in - - let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf = - let is_interface = cl.cl_interface in - let name, is_new, is_explicit_iface = match cf.cf_name with - | "new" -> snd cl.cl_path, true, false - | name when String.contains name '.' -> - let fn_name, path = parse_explicit_iface name in - (path_s path) ^ "." ^ fn_name, false, true - | name -> name, false, false - in - (match cf.cf_kind with - | Var _ - | Method (MethDynamic) when not (Type.is_extern_field cf) -> - (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then - gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos); - if not is_interface then begin - let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in - print w "%s %s%s %s %s" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s cf.cf_pos (run_follow gen cf.cf_type)) (change_field name); - (match cf.cf_expr with - | Some e -> - write w " = "; - expr_s w e; - write w ";" - | None -> write w ";" - ) - end (* TODO see how (get,set) variable handle when they are interfaces *) - | Method _ when Type.is_extern_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 - gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf - ) cf.cf_overloads - | Var _ | Method MethDynamic -> () - | Method mkind -> - List.iter (fun cf -> - if cl.cl_interface || cf.cf_expr <> None then - gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf - ) cf.cf_overloads; - let is_virtual = is_new || (not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false) in - let is_override = match cf.cf_name with - | "equals" when not is_static -> - (match cf.cf_type with - | TFun([_,_,t], ret) -> - (match (real_type t, real_type ret) with - | TDynamic _, TEnum( { e_path = ([], "Bool") }, []) - | TDynamic _, TAbstract ({ a_path = ([], "Bool") },[]) - | TAnon _, TEnum( { e_path = ([], "Bool") }, []) - | TAnon _, TAbstract ({ a_path = ([], "Bool") },[]) -> true - | _ -> List.memq cf cl.cl_overrides - ) - | _ -> List.memq cf cl.cl_overrides) - | "toString" when not is_static -> - (match cf.cf_type with - | TFun([], ret) -> - (match real_type ret with - | TInst( { cl_path = ([], "String") }, []) -> true - | _ -> gen.gcon.error "A toString() function should return a String!" cf.cf_pos; false - ) - | _ -> List.memq cf cl.cl_overrides - ) - | "hashCode" when not is_static -> - (match cf.cf_type with - | TFun([], ret) -> - (match real_type ret with - | TInst( { cl_path = ([], "Int") }, []) - | TAbstract ({ a_path = ([], "Int") },[]) -> - true - | _ -> gen.gcon.error "A hashCode() function should return an Int!" cf.cf_pos; false - ) - | _ -> List.memq cf cl.cl_overrides - ) - | _ -> List.memq cf cl.cl_overrides - in - let visibility = if is_interface then "" else "public" in - - 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_types)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in - - let params = List.map snd cl.cl_types in - let ret_type, args = match follow cf_type, follow cf.cf_type with - | TFun (strbtl, t), TFun(rargs, _) -> - (apply_params cl.cl_types params (real_type t), List.map2 (fun(_,_,t) (n,o,_) -> (n,o,apply_params cl.cl_types params (real_type t))) strbtl rargs) - | _ -> assert false - in - - (if is_override && not is_interface then write w "@Override "); - (* public static void funcName *) - let params, _ = get_string_params cf.cf_params in - print w "%s %s%s %s %s %s" (visibility) v_n (String.concat " " modifiers) params (if is_new then "" else rett_s cf.cf_pos (run_follow gen ret_type)) (change_field name); - - (* (string arg1, object arg2) with T : object *) - (match cf.cf_expr with - | Some { eexpr = TFunction tf } -> - print w "(%s)" (String.concat ", " (List.map2 (fun (var,_) (_,_,t) -> sprintf "%s %s" (t_s cf.cf_pos (run_follow gen t)) (change_id var.v_name)) tf.tf_args args)) - | _ -> - print w "(%s)" (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (t_s cf.cf_pos (run_follow gen t)) (change_id name)) args)) - ); - if is_interface then - write w ";" - else begin - let rec loop meta = - match meta with - | [] -> - let expr = match cf.cf_expr with - | None -> mk (TBlock([])) t_dynamic Ast.null_pos - | Some s -> - match s.eexpr with - | TFunction tf -> - mk_block (tf.tf_expr) - | _ -> assert false (* FIXME *) - in - (if is_new then begin - (*let rec get_super_call el = - match el with - | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest -> - Some call, rest - | ( { eexpr = TBlock(bl) } as block ) :: rest -> - let ret, mapped = get_super_call bl in - ret, ( { block with eexpr = TBlock(mapped) } :: rest ) - | _ -> - None, el - in*) - expr_s w expr - end else begin - expr_s w expr; - end) - | (Meta.Throws, [Ast.EConst (Ast.String t), _], _) :: tl -> - print w " throws %s" t; - loop tl - | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> - begin_block w; - write w contents; - end_block w - | _ :: tl -> loop tl - in - loop cf.cf_meta - - end); - newline w; - newline w - in - - let gen_class w cl = - let should_close = match change_ns (fst cl.cl_path) with - | [] -> false - | ns -> - print w "package %s;" (String.concat "." (change_ns ns)); - newline w; - false - in - - let rec loop_meta meta acc = - match meta with - | (Meta.SuppressWarnings, [Ast.EConst (Ast.String w),_],_) :: meta -> loop_meta meta (w :: acc) - | _ :: meta -> loop_meta meta acc - | _ -> acc - in - - let suppress_warnings = loop_meta cl.cl_meta [ "rawtypes"; "unchecked" ] in - - write w "import haxe.root.*;"; - newline w; - let w_header = w in - let w = new_source_writer () in - clear_scope(); - - (* add all haxe.root.* to imports *) - List.iter (function - | TClassDecl { cl_path = ([],c) } -> - imports := ([],c) :: !imports - | TEnumDecl { e_path = ([],c) } -> - imports := ([],c) :: !imports - | TAbstractDecl { a_path = ([],c) } -> - imports := ([],c) :: !imports - | _ -> () - ) gen.gcon.types; - - newline w; - write w "@SuppressWarnings(value={"; - let first = ref true in - List.iter (fun s -> - (if !first then first := false else write w ", "); - print w "\"%s\"" (escape s) - ) suppress_warnings; - write w "})"; - newline w; - - let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in - let is_final = Meta.has Meta.Final cl.cl_meta in - - print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path)); - (* type parameters *) - let params, _ = get_string_params cl.cl_types in - let cl_p_to_string (c,p) = path_param_s cl.cl_pos (TClassDecl c) c.cl_path p in - print w "%s" params; - (if is_some cl.cl_super then print w " extends %s" (cl_p_to_string (get cl.cl_super))); - (match cl.cl_implements with - | [] -> () - | _ -> print w " %s %s" (if cl.cl_interface then "extends" else "implements") (String.concat ", " (List.map cl_p_to_string cl.cl_implements)) - ); - (* class head ok: *) - (* 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;*) - - let rec loop cl = - List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_fields; - List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_statics; - match cl.cl_super with - | Some(c,_) -> loop c - | None -> () - in - loop cl; - - let rec loop meta = - match meta with - | [] -> () - | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> - write w contents - | _ :: tl -> loop tl - 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 "main();"; - end_block w - | _ -> () - ); - - (match cl.cl_init with - | None -> () - | Some init -> - write w "static "; - expr_s w (mk_block init)); - (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor)); - (if not cl.cl_interface then - List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics); - List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields; - end_block w; - if should_close then end_block w; - - (* add imports *) - List.iter (function - | ["haxe";"root"], _ | [], _ -> () - | path -> - write w_header "import "; - write w_header (path_s path); - write w_header ";\n" - ) !imports; - add_writer w w_header - in - - - let gen_enum w e = - let should_close = match change_ns (fst e.e_path) with - | [] -> false - | ns -> - print w "package %s;" (String.concat "." (change_ns ns)); - newline w; - false - in - - print w "public enum %s" (change_clname (snd e.e_path)); - begin_block w; - write w (String.concat ", " (List.map (change_id) e.e_names)); - end_block w; - - if should_close then end_block w - in - - let module_type_gen w md_tp = - match md_tp with - | TClassDecl cl -> - if not cl.cl_extern then begin - gen_class w cl; - newline w; - newline w - end; - (not cl.cl_extern) - | TEnumDecl e -> - if not e.e_extern then begin - gen_enum w e; - newline w; - newline w - end; - (not e.e_extern) - | TTypeDecl e -> - false - | TAbstractDecl a -> - false - in - - let module_gen w md = - module_type_gen w md - in - - (* generate source code *) - init_ctx gen; - - Hashtbl.add gen.gspecial_vars "__label__" true; - Hashtbl.add gen.gspecial_vars "__goto__" true; - Hashtbl.add gen.gspecial_vars "__is__" true; - Hashtbl.add gen.gspecial_vars "__typeof__" true; - Hashtbl.add gen.gspecial_vars "__java__" true; - Hashtbl.add gen.gspecial_vars "__lock__" true; - - gen.greal_type <- real_type; - gen.greal_type_param <- change_param_type; - - SetHXGen.run_filter gen SetHXGen.default_hxgen_func; - - (* before running the filters, follow all possible types *) - (* this is needed so our module transformations don't break some core features *) - (* like multitype selection *) - let run_follow_gen = run_follow gen in - let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen) (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in - let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in - List.iter (function - | TClassDecl cl -> - let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in - List.iter (fun cf -> - cf.cf_type <- run_follow_gen cf.cf_type; - cf.cf_expr <- Option.map type_map cf.cf_expr - ) all_fields; - cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic; - cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access; - cl.cl_init <- Option.map type_map cl.cl_init; - cl.cl_super <- Option.map super_map cl.cl_super; - cl.cl_implements <- List.map super_map cl.cl_implements - | _ -> () - ) gen.gcon.types; - - let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in - - (*let closure_t = ClosuresToClass.create gen 10 float_cl - (fun l -> l) - (fun l -> l) - (fun args -> args) - (fun args -> []) - in - ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e)); - - StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*) - - FixOverrides.configure gen; - NormalizeType.configure gen; - AbstractImplementationFix.configure gen; - - IteratorsInterface.configure gen (fun e -> e); - - ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) )); - - EnumToClass.configure gen (None) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) false false; - - InterfaceVarsDeleteModf.configure gen; - - let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in - - let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in - - (*fixme: THIS IS A HACK. take this off *) - let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in - (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*) - - let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in - let empty_ef = - try - PMap.find "EMPTY" empty_e.e_constrs - with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false - in - OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen; - - let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in - (*let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in*) - - let can_be_float t = like_float (real_type t) in - - let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe = - let is_float = can_be_float (if is_none may_set then main_expr.etype else (get may_set).etype) in - let fn_name = if is_some may_set then "setField" else "getField" in - let fn_name = if is_float then fn_name ^ "_f" else fn_name in - let pos = field_expr.epos in - - let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in - - let should_cast = match main_expr.etype with | TInst({ cl_path = ([], "Float") }, []) -> false | _ -> true in - let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in - let first_args = - [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ] - @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else [] - in - let args = first_args @ match is_float, may_set with - | true, Some(set) -> - [ if should_cast then mk_cast basic.tfloat set else set ] - | false, Some(set) -> - [ set ] - | _ -> - [ is_unsafe ] - in - - let call = { main_expr with eexpr = TCall(infer,args) } in - let call = if is_float && should_cast then mk_cast main_expr.etype call else call in - call - in - - let rcf_on_call_field ecall field_expr field may_hash args = - let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in - - let hash_arg = match may_hash with - | None -> [] - | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ] - in - - let arr_call = if args <> [] then - { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos } - else - null (basic.tarray t_dynamic) ecall.epos - in - - - let call_args = - [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ] - @ hash_arg - @ [ arr_call ] - in - - mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args); etype = t_dynamic } - in - - let rcf_ctx = ReflectionCFs.new_ctx gen closure_t object_iface false rcf_on_getset_field rcf_on_call_field (fun hash hash_array -> - { hash with eexpr = TCall(rcf_static_find, [hash; hash_array]); etype=basic.tint } - ) (fun hash -> hash ) false in - - ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object; - - ReflectionCFs.configure_dynamic_field_access rcf_ctx false; - - (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *) - let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in - - let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in - - ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) ); - - let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in - ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> { - eexpr = TCall(slow_invoke, [ethis; efield; eargs]); - etype = t_dynamic; - epos = ethis.epos; - } ) object_iface; - - let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in - - ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn); - - InitFunction.configure gen true; - TArrayTransform.configure gen (TArrayTransform.default_implementation gen ( - fun e -> - match e.eexpr with - | TArray(e1, e2) -> - ( match run_follow gen e1.etype with - | TInst({ cl_path = (["java"], "NativeArray") }, _) -> false - | _ -> true ) - | _ -> assert false - ) "__get" "__set" ); - - let field_is_dynamic t field = - match field_access gen (gen.greal_type t) field with - | FClassField (cl,p,_,_,_,t,_) -> - is_dynamic (apply_params cl.cl_types p t) - | FEnumField _ -> false - | _ -> true - in - - let is_type_param e = match follow e with - | TInst( { cl_kind = KTypeParameter _ },[]) -> true - | _ -> false - in - - let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with - | TField(tf, f) -> field_is_dynamic tf.etype (field_name f) - | _ -> false - in - - let may_nullable t = match gen.gfollow#run_f t with - | TType({ t_path = ([], "Null") }, [t]) -> - (match follow t with - | TInst({ cl_path = ([], "String") }, []) - | TInst({ cl_path = ([], "Float") }, []) - | TAbstract ({ a_path = ([], "Float") },[]) - | TInst({ cl_path = (["haxe"], "Int32")}, [] ) - | TInst({ cl_path = (["haxe"], "Int64")}, [] ) - | TInst({ cl_path = ([], "Int") }, []) - | TAbstract ({ a_path = ([], "Int") },[]) - | TEnum({ e_path = ([], "Bool") }, []) - | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t - | _ -> None ) - | _ -> None - in - - let is_double t = like_float t && not (like_int t) in - let is_int t = like_int t in - - DynamicOperators.configure gen - (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with - | TBinop (Ast.OpEq, e1, e2) - | TBinop (Ast.OpAdd, e1, e2) - | TBinop (Ast.OpNotEq, e1, e2) -> is_dynamic e1.etype or is_dynamic e2.etype or is_type_param e1.etype or is_type_param e2.etype - | TBinop (Ast.OpLt, e1, e2) - | TBinop (Ast.OpLte, e1, e2) - | TBinop (Ast.OpGte, e1, e2) - | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2 or is_string e1.etype or is_string e2.etype - | TBinop (_, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2 - | TUnop (_, _, e1) -> is_dynamic_expr e1 - | _ -> false) - (fun e1 e2 -> - let is_null e = match e.eexpr with | TConst(TNull) | TLocal({ v_name = "__undefined__" }) -> true | _ -> false in - - if is_null e1 || is_null e2 then - match e1.eexpr, e2.eexpr with - | TConst c1, TConst c2 -> - { e1 with eexpr = TConst(TBool (c1 = c2)); etype = basic.tbool } - | _ -> - { e1 with eexpr = TBinop(Ast.OpEq, e1, e2); etype = basic.tbool } - else begin - let is_ref = match follow e1.etype, follow e2.etype with - | TDynamic _, _ - | _, TDynamic _ - | TInst({ cl_path = ([], "Float") },[]), _ - | TAbstract ({ a_path = ([], "Float") },[]) , _ - | TInst( { cl_path = (["haxe"], "Int32") }, [] ), _ - | TInst( { cl_path = (["haxe"], "Int64") }, [] ), _ - | TInst({ cl_path = ([], "Int") },[]), _ - | TAbstract ({ a_path = ([], "Int") },[]) , _ - | TEnum({ e_path = ([], "Bool") },[]), _ - | TAbstract ({ a_path = ([], "Bool") },[]) , _ - | _, TInst({ cl_path = ([], "Float") },[]) - | _, TAbstract ({ a_path = ([], "Float") },[]) - | _, TInst({ cl_path = ([], "Int") },[]) - | _, TAbstract ({ a_path = ([], "Int") },[]) - | _, TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | _, TInst( { cl_path = (["haxe"], "Int64") }, [] ) - | _, TEnum({ e_path = ([], "Bool") },[]) - | _, TAbstract ({ a_path = ([], "Bool") },[]) - | TInst( { cl_kind = KTypeParameter _ }, [] ), _ - | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false - | _, _ -> true - in - - let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in - { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos } - end - ) - (fun e e1 e2 -> - match may_nullable e1.etype, may_nullable e2.etype with - | Some t1, Some t2 -> - let t1, t2 = if is_string t1 || is_string t2 then - basic.tstring, basic.tstring - else if is_double t1 || is_double t2 then - basic.tfloat, basic.tfloat - else if is_int t1 || is_int t2 then - basic.tint, basic.tint - else t1, t2 in - { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos } - | _ -> - let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in - mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos }) - (fun e1 e2 -> - if is_string e1.etype then begin - { e1 with eexpr = TCall(mk_field_access gen e1 "compareTo" e1.epos, [ e2 ]); etype = gen.gcon.basic.tint } - end else begin - let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in - { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos } - end)); - - FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func); - - let base_exception = get_cl (get_type gen (["java"; "lang"], "Throwable")) in - let base_exception_t = TInst(base_exception, []) in - - let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in - let hx_exception_t = TInst(hx_exception, []) in - - let rec is_exception t = - match follow t with - | TInst(cl,_) -> - if cl == base_exception then - true - else - (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg))) - | _ -> false - in - - TryCatchWrapper.configure gen - ( - TryCatchWrapper.traverse gen - (fun t -> not (is_exception (real_type t))) - (fun throwexpr expr -> - let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in - { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid } - ) - (fun v_to_unwrap pos -> - let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in - mk_field_access gen local "obj" pos - ) - (fun rethrow -> - let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) rethrow.epos in - { rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]) }; } - ) - (base_exception_t) - (hx_exception_t) - (fun v e -> e) - ); - - let get_typeof e = - { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) } - in - - ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> get_typeof e)); - - (*let v = alloc_var "$type_param" t_dynamic in*) - TypeParams.configure gen (fun ecall efield params elist -> - { ecall with eexpr = TCall(efield, elist) } - ); - - CastDetect.configure gen (CastDetect.default_implementation gen ~native_string_cast:false (Some (TEnum(empty_e, []))) false); - - (*FollowAll.configure gen;*) - - SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e -> - match e.eexpr with - | TSwitch(cond, cases, def) -> - (match gen.gfollow#run_f cond.etype with - | TInst( { cl_path = (["haxe"], "Int32") }, [] ) - | TInst({ cl_path = ([], "Int") },[]) - | TAbstract ({ a_path = ([], "Int") },[]) - | TInst({ cl_path = ([], "String") },[]) -> - (List.exists (fun (c,_) -> - List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c - ) cases) - | _ -> true - ) - | _ -> assert false - ) true ); - - let native_arr_cl = get_cl ( get_type gen (["java"], "NativeArray") ) in - - ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVars([mk_temp gen "expr" e.etype, Some e]); etype = gen.gcon.basic.tvoid; epos = e.epos })); - - UnnecessaryCastsRemoval.configure gen; - - IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true); - - UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true true); - - ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl); - - let goto_special = alloc_var "__goto__" t_dynamic in - let label_special = alloc_var "__label__" t_dynamic in - SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen - (fun e_loop n api -> - { e_loop with eexpr = TBlock( { eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos } :: [e_loop] ) }; - ) - (fun e_break n api -> - { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos } - ) - ); - - DefaultArguments.configure gen (DefaultArguments.traverse gen); - - JavaSpecificSynf.configure gen (JavaSpecificSynf.traverse gen runtime_cl); - JavaSpecificESynf.configure gen (JavaSpecificESynf.traverse 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 - str_cl.cl_super <- Some (get_cl (get_type gen (["haxe";"lang"], "NativeString")), []); - - let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in - mkdir gen.gcon.file; - mkdir (gen.gcon.file ^ "/src"); - - (* add resources array *) - (try - let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in - let cf = PMap.find "content" res.cl_statics in - let res = ref [] in - Hashtbl.iter (fun name v -> - res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res; - let f = open_out (gen.gcon.file ^ "/src/" ^ name) in - output_string f v; - close_out f - ) gen.gcon.resources; - cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos }) - with | Not_found -> ()); - - run_filters gen; - - TypeParams.RenameTypeParameters.run gen; - - let t = Common.timer "code generation" in - - generate_modules_t gen "java" "src" change_path module_gen; - - dump_descriptor gen ("hxjava_build.txt") path_s (fun md -> path_s (t_infos md).mt_path); + 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_len <- (fun e p -> mk_field_access gen e "length" p); + + let basic = gen.gcon.basic in + + let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in + + let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in + let nulltdef = get_tdef (get_type gen ([],"Null")) in + + (*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 has_tdynamic params = + List.exists (fun e -> match run_follow gen e with | TDynamic _ -> true | _ -> false) params + in + + (* + The type parameters always need to be changed to their boxed counterparts + *) + let change_param_type md params = + match md with + | TClassDecl( { cl_path = (["java"], "NativeArray") } ) -> params + | TAbstractDecl { a_path=[],("Class" | "Enum") } | TClassDecl { cl_path = (["java";"lang"],("Class"|"Enum")) } -> + List.map (fun _ -> t_dynamic) params + | _ -> + match params with + | [] -> [] + | _ -> + if has_tdynamic params then List.map (fun _ -> t_dynamic) params else + List.map (fun t -> + let f_t = gen.gfollow#run_f t in + match f_t with + | TAbstract ({ a_path = ([], "Bool") },[]) + | TAbstract ({ a_path = ([],"Float") },[]) + | TInst ({ cl_path = ["haxe"],"Int32" },[]) + | TInst ({ cl_path = ["haxe"],"Int64" },[]) + | TAbstract ({ a_path = ([],"Int") },[]) + | TType ({ t_path = ["java"], "Int64" },[]) + | TAbstract ({ a_path = ["java"], "Int64" },[]) + | TType ({ t_path = ["java"],"Int8" },[]) + | TAbstract ({ a_path = ["java"],"Int8" },[]) + | TType ({ t_path = ["java"],"Int16" },[]) + | TAbstract ({ a_path = ["java"],"Int16" },[]) + | TType ({ t_path = ["java"],"Char16" },[]) + | TAbstract ({ a_path = ["java"],"Char16" },[]) + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> + TType(nulltdef, [f_t]) + (*| TType ({ t_path = [], "Null"*) + | TInst (cl, ((_ :: _) as p)) when cl.cl_path <> (["java"],"NativeArray") -> + (* TInst(cl, List.map (fun _ -> t_dynamic) p) *) + TInst(cl,p) + | TEnum (e, ((_ :: _) as p)) -> + TEnum(e, List.map (fun _ -> t_dynamic) p) + | _ -> t + ) params + in + + let change_clname name = + String.map (function | '$' -> '.' | c -> c) name + in + let change_id name = try Hashtbl.find reserved name with | Not_found -> name in + let rec change_ns ns = match ns with + | [] -> ["haxe"; "root"] + | _ -> List.map change_id ns + in + let change_field = change_id in + + let write_id w name = write w (change_id name) in + + let write_field w name = write w (change_field name) in + + gen.gfollow#add ~name:"follow_basic" (fun t -> match t with + | TAbstract ({ a_path = ([], "Bool") },[]) + | TAbstract ({ a_path = ([], "Void") },[]) + | TAbstract ({ a_path = ([],"Float") },[]) + | TAbstract ({ a_path = ([],"Int") },[]) + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) + | TType ({ t_path = ["java"], "Int64" },[]) + | TAbstract ({ a_path = ["java"], "Int64" },[]) + | TType ({ t_path = ["java"],"Int8" },[]) + | TAbstract ({ a_path = ["java"],"Int8" },[]) + | TType ({ t_path = ["java"],"Int16" },[]) + | TAbstract ({ a_path = ["java"],"Int16" },[]) + | TType ({ t_path = ["java"],"Char16" },[]) + | TAbstract ({ a_path = ["java"],"Char16" },[]) + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> + Some t + | TType (({ t_path = [],"Null" } as tdef),[t2]) -> + Some (TType(tdef,[gen.gfollow#run_f t2])) + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + Some (gen.gfollow#run_f ( Abstract.get_underlying_type a pl) ) + | TAbstract( { a_path = ([], "EnumValue") }, _ ) + | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic + | _ -> None); + + let change_path path = (change_ns (fst path), change_clname (snd path)) in + + let path_s path meta = try + match Meta.get Meta.JavaCanonical meta with + | (Meta.JavaCanonical, [EConst(String pack), _; EConst(String name), _], _) -> + if pack = "" then + name + else + pack ^ "." ^ name + | _ -> raise Not_found + with Not_found -> match path with + | (ns,clname) -> path_s (change_ns ns, change_clname clname) + in + + let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in + + let rec real_type t = + let t = gen.gfollow#run_f t in + match t with + | TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) -> + real_type (Abstract.get_underlying_type a pl) + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64 + | TAbstract( { a_path = ([], "Class") }, p ) + | TAbstract( { a_path = ([], "Enum") }, p ) + | TInst( { cl_path = ([], "Class") }, p ) + | TInst( { cl_path = ([], "Enum") }, p ) -> TInst(cl_cl,[t_dynamic]) + | TEnum(e,params) -> TEnum(e, List.map (fun _ -> t_dynamic) params) + | TInst(c,params) when Meta.has Meta.Enum c.cl_meta -> + TInst(c, List.map (fun _ -> t_dynamic) params) + | TInst _ -> t + | TType({ t_path = ([], "Null") }, [t]) when is_java_basic_type (gen.gfollow#run_f t) -> t_dynamic + | TType({ t_path = ([], "Null") }, [t]) -> + (match follow t with + | TInst( { cl_kind = KTypeParameter _ }, []) -> + t_dynamic + (* real_type t *) + | _ -> real_type t + ) + | TType _ | TAbstract _ -> t + | TAnon (anon) -> (match !(anon.a_status) with + | Statics _ | EnumStatics _ | AbstractStatics _ -> t + | _ -> t_dynamic) + | TFun _ -> TInst(fn_cl,[]) + | _ -> t_dynamic + in + + let scope = ref PMap.empty in + let imports = ref [] in + + let clear_scope () = + scope := PMap.empty; + imports := []; + in + + let add_scope name = + scope := PMap.add name () !scope + in + + let add_import pos path meta = + let name = snd path in + let rec loop = function + | (pack, n) :: _ when name = n -> + if path <> (pack,n) then + gen.gcon.error ("This expression cannot be generated because " ^ path_s path meta ^ " is shadowed by the current scope and ") pos + | _ :: tl -> + loop tl + | [] -> + (* add import *) + imports := path :: !imports + in + loop !imports + in + + let path_s_import pos path meta = match path with + | [], name when PMap.mem name !scope -> + gen.gcon.error ("This expression cannot be generated because " ^ name ^ " is shadowed by the current scope") pos; + name + | pack1 :: _, name when PMap.mem pack1 !scope -> (* exists in scope *) + add_import pos path meta; + (* check if name exists in scope *) + if PMap.mem name !scope then + gen.gcon.error ("This expression cannot be generated because " ^ pack1 ^ " and " ^ name ^ " are both shadowed by the current scope") pos; + name + | _ -> path_s path meta + in + + let is_dynamic t = match real_type t with + | TMono _ | TDynamic _ + | TInst({ cl_kind = KTypeParameter _ }, _) -> true + | TAnon anon -> + (match !(anon.a_status) with + | EnumStatics _ | Statics _ | AbstractStatics _ -> false + | _ -> true + ) + | _ -> false + in + + let rec t_s pos t = + match real_type t with + (* basic types *) + | TAbstract ({ a_path = ([], "Bool") },[]) -> "boolean" + | TAbstract ({ a_path = ([], "Void") },[]) -> + path_s_import pos (["java";"lang"], "Object") [] + | TAbstract ({ a_path = ([],"Float") },[]) -> "double" + | TAbstract ({ a_path = ([],"Int") },[]) -> "int" + | TType ({ t_path = ["java"], "Int64" },[]) + | TAbstract ({ a_path = ["java"], "Int64" },[]) -> "long" + | TType ({ t_path = ["java"],"Int8" },[]) + | TAbstract ({ a_path = ["java"],"Int8" },[]) -> "byte" + | TType ({ t_path = ["java"],"Int16" },[]) + | TAbstract ({ a_path = ["java"],"Int16" },[]) -> "short" + | TType ({ t_path = ["java"],"Char16" },[]) + | TAbstract ({ a_path = ["java"],"Char16" },[]) -> "char" + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> "float" + | TInst ({ cl_path = ["haxe"],"Int32" },[]) + | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int" + | TInst ({ cl_path = ["haxe"],"Int64" },[]) + | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long" + | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> + let rec check_t_s t = + match real_type t with + | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> + (check_t_s param) ^ "[]" + | _ -> t_s pos (run_follow gen t) + in + (check_t_s param) ^ "[]" + + (* end of basic types *) + | 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 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]) + | TInst ({ cl_path = [], "Class" }, [p]) | TInst ({ cl_path = [], "Enum" }, [p]) -> + path_param_s pos (TClassDecl cl_cl) (["java";"lang"], "Class") [p] [] + | TAbstract ({ a_path = [], "Class" }, _) | TAbstract ({ a_path = [], "Enum" }, _) + | TInst ({ cl_path = [], "Class" }, _) | TInst ({ cl_path = [], "Enum" }, _) -> + path_s_import pos (["java";"lang"], "Class") [] + | TEnum ({e_path = p; e_meta = meta}, _) -> + path_s_import pos p meta + | TInst (({cl_path = p; cl_meta = meta} as cl), _) when Meta.has Meta.Enum cl.cl_meta -> + path_s_import pos p meta + | TInst (({cl_path = p; cl_meta = meta} as cl), params) -> (path_param_s pos (TClassDecl cl) p params meta) + | TType (({t_path = p; t_meta = meta} as t), params) -> (path_param_s pos (TTypeDecl t) p params meta) + | TAnon (anon) -> + (match !(anon.a_status) with + | Statics _ | EnumStatics _ | AbstractStatics _ -> + path_s_import pos (["java";"lang"], "Class") [] + | _ -> + path_s_import pos (["java";"lang"], "Object") []) + | 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) ^ " ]" + + and param_t_s pos t = + match run_follow gen t with + | TAbstract ({ a_path = ([], "Bool") },[]) -> + path_s_import pos (["java";"lang"], "Boolean") [] + | TAbstract ({ a_path = ([],"Float") },[]) -> + path_s_import pos (["java";"lang"], "Double") [] + | TAbstract ({ a_path = ([],"Int") },[]) -> + path_s_import pos (["java";"lang"], "Integer") [] + | TType ({ t_path = ["java"], "Int64" },[]) + | TAbstract ({ a_path = ["java"], "Int64" },[]) -> + path_s_import pos (["java";"lang"], "Long") [] + | TInst ({ cl_path = ["haxe"],"Int64" },[]) + | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> + path_s_import pos (["java";"lang"], "Long") [] + | TInst ({ cl_path = ["haxe"],"Int32" },[]) + | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> + path_s_import pos (["java";"lang"], "Integer") [] + | TType ({ t_path = ["java"],"Int8" },[]) + | TAbstract ({ a_path = ["java"],"Int8" },[]) -> + path_s_import pos (["java";"lang"], "Byte") [] + | TType ({ t_path = ["java"],"Int16" },[]) + | TAbstract ({ a_path = ["java"],"Int16" },[]) -> + path_s_import pos (["java";"lang"], "Short") [] + | TType ({ t_path = ["java"],"Char16" },[]) + | TAbstract ({ a_path = ["java"],"Char16" },[]) -> + path_s_import pos (["java";"lang"], "Character") [] + | TType ({ t_path = [],"Single" },[]) + | TAbstract ({ a_path = [],"Single" },[]) -> + path_s_import pos (["java";"lang"], "Float") [] + | TDynamic _ -> "?" + | TInst (cl, params) -> t_s pos (TInst(cl, change_param_type (TClassDecl cl) params)) + | TType (cl, params) -> t_s pos (TType(cl, change_param_type (TTypeDecl cl) params)) + | TEnum (e, params) -> t_s pos (TEnum(e, change_param_type (TEnumDecl e) params)) + | _ -> t_s pos t + + and path_param_s pos md path params meta = + match params with + | [] -> path_s_import pos path meta + | _ when has_tdynamic (change_param_type md params) -> path_s_import pos path meta + | _ -> sprintf "%s<%s>" (path_s_import pos path meta) (String.concat ", " (List.map (fun t -> param_t_s pos t) (change_param_type md params))) + in + + let rett_s pos t = + match t with + | TAbstract ({ a_path = ([], "Void") },[]) -> "void" + | _ -> t_s pos t + in + + let high_surrogate c = (c lsr 10) + 0xD7C0 in + let low_surrogate c = (c land 0x3FF) lor 0xDC00 in + + let escape ichar b = + match ichar with + | 92 (* \ *) -> Buffer.add_string b "\\\\" + | 39 (* ' *) -> Buffer.add_string b "\\\'" + | 34 -> Buffer.add_string b "\\\"" + | 13 (* \r *) -> Buffer.add_string b "\\r" + | 10 (* \n *) -> Buffer.add_string b "\\n" + | 9 (* \t *) -> Buffer.add_string b "\\t" + | c when c < 32 || (c >= 127 && c <= 0xFFFF) -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c) + | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\u%.4x\\u%.4x" (high_surrogate c) (low_surrogate c)) + | c -> Buffer.add_char b (Char.chr c) + in + + let escape s = + let b = Buffer.create 0 in + (try + UTF8.validate s; + UTF8.iter (fun c -> escape (UChar.code c) b) s + with + UTF8.Malformed_code -> + String.iter (fun c -> escape (Char.code c) b) s + ); + Buffer.contents b + in + + let has_semicolon e = + match e.eexpr with + | TLocal { v_name = "__fallback__" } + | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt _) } ] ) -> false + | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, _ ) -> false + | TBlock _ | TFor _ | TSwitch _ | TTry _ | TIf _ -> false + | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false + | _ -> true + in + + let in_value = ref false in + + let rec md_s pos md = + let md = follow_module (gen.gfollow#run_f) md in + match md with + | TClassDecl (cl) -> + t_s pos (TInst(cl,[])) + | TEnumDecl (e) -> + t_s pos (TEnum(e,[])) + | TTypeDecl t -> + t_s pos (TType(t, [])) + | TAbstractDecl a -> + t_s pos (TAbstract(a, [])) + in + + (* + it seems that Java doesn't like when you create a new array with the type parameter defined + so we'll just ignore all type parameters, and hope for the best! + *) + let rec transform_nativearray_t t = match real_type t with + | TInst( ({ cl_path = (["java"], "NativeArray") } as narr), [t]) -> + TInst(narr, [transform_nativearray_t t]) + | TInst(cl, params) -> TInst(cl, List.map (fun _ -> t_dynamic) params) + | TEnum(e, params) -> TEnum(e, List.map (fun _ -> t_dynamic) params) + | TType(t, params) -> TType(t, List.map (fun _ -> t_dynamic) params) + | _ -> t + in + + let rec extract_tparams params el = + match el with + | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl -> + extract_tparams (tp.etype :: params) tl + | _ -> (params, el) + in + + let line_directive = + if Common.defined gen.gcon Define.RealPosition then + fun w p -> () + else fun w p -> + let cur_line = Lexer.get_error_line p in + let file = Common.get_full_path p.pfile in + print w "//line %d \"%s\"" cur_line (Ast.s_escape file); newline w + in + + let extract_statements expr = + let ret = ref [] in + let rec loop expr = match expr.eexpr with + | TCall ({ eexpr = TLocal { + v_name = "__is__" | "__typeof__" | "__array__" + } }, el) -> + List.iter loop el + | TNew ({ cl_path = (["java"], "NativeArray") }, params, [ size ]) -> + () + | TUnop (Ast.Increment, _, _) + | TUnop (Ast.Decrement, _, _) + | TBinop (Ast.OpAssign, _, _) + | TBinop (Ast.OpAssignOp _, _, _) + | TLocal { v_name = "__fallback__" } + | TLocal { v_name = "__sbreak__" } -> + ret := expr :: !ret + | TConst _ + | TLocal _ + | TArray _ + | TBinop _ + | TField _ + | TEnumParameter _ + | TTypeExpr _ + | TObjectDecl _ + | TArrayDecl _ + | TCast _ + | TMeta _ + | TParenthesis _ + | TUnop _ -> + Type.iter loop expr + | TFunction _ -> () (* do not extract parameters from inside of it *) + | _ -> + ret := expr :: !ret + in + loop expr; + (* [expr] *) + List.rev !ret + in + + let expr_s w e = + in_value := false; + let rec expr_s w e = + let was_in_value = !in_value in + in_value := true; + match e.eexpr with + | TConst c -> + (match c with + | TInt i32 -> + print w "%ld" i32; + (match real_type e.etype with + | TType( { t_path = (["java"], "Int64") }, [] ) -> write w "L"; + | _ -> () + ) + | TFloat s -> + write w s; + (* fix for Int notation, which only fit in a Float *) + (if not (String.contains s '.' || String.contains s 'e' || String.contains s 'E') then write w ".0"); + (match real_type e.etype with + | TType( { t_path = ([], "Single") }, [] ) -> write w "f" + | _ -> () + ) + | TString s -> print w "\"%s\"" (escape s) + | TBool b -> write w (if b then "true" else "false") + | TNull -> + (match real_type e.etype with + | TAbstract( { a_path = (["java"], "Int64") }, [] ) + | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> write w "0L" + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TAbstract ({ a_path = ([], "Int") },[]) -> expr_s w ({ e with eexpr = TConst(TInt Int32.zero) }) + | TAbstract ({ a_path = ([], "Float") },[]) -> expr_s w ({ e with eexpr = TConst(TFloat "0.0") }) + | TAbstract ({ a_path = ([], "Bool") },[]) -> write w "false" + | TAbstract _ when like_int e.etype -> + expr_s w (mk_cast e.etype { e with eexpr = TConst(TInt Int32.zero) }) + | TAbstract _ when like_float e.etype -> + expr_s w (mk_cast e.etype { e with eexpr = TConst(TFloat "0.0") } ) + | t -> write w ("null") ) + | TThis -> write w "this" + | TSuper -> write w "super") + | TLocal { v_name = "__fallback__" } -> () + | TLocal { v_name = "__sbreak__" } -> write w "break" + | TLocal { v_name = "__undefined__" } -> + write w (t_s e.epos (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_params))); + write w ".undefined"; + | TLocal var -> + write_id w var.v_name + | TField(_, FEnum(en,ef)) -> + let s = ef.ef_name in + print w "%s." (path_s_import e.epos en.e_path en.e_meta); write_field w s + | TArray (e1, e2) -> + expr_s w e1; write w "["; expr_s w e2; write w "]" + | TBinop ((Ast.OpAssign as op), e1, e2) + | TBinop ((Ast.OpAssignOp _ as op), e1, e2) -> + expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2 + | TBinop (op, e1, e2) -> + write w "( "; + expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2; + write w " )" + | TField (e, FStatic(_, cf)) when Meta.has Meta.Native cf.cf_meta -> + let rec loop meta = match meta with + | (Meta.Native, [EConst (String s), _],_) :: _ -> + expr_s w e; write w "."; write_field w s + | _ :: tl -> loop tl + | [] -> expr_s w e; write w "."; write_field w (cf.cf_name) + in + loop cf.cf_meta + | TField (e, s) -> + expr_s w e; write w "."; write_field w (field_name s) + | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int32") }) -> + write w (path_s_import e.epos (["haxe"], "Int32") []) + | TTypeExpr (TClassDecl { cl_path = (["haxe"], "Int64") }) -> + write w (path_s_import e.epos (["haxe"], "Int64") []) + | TTypeExpr mt -> write w (md_s e.epos mt) + | TParenthesis e -> + write w "("; expr_s w e; write w ")" + | TMeta (_,e) -> + expr_s w e + | TCall ({ eexpr = TLocal { v_name = "__array__" } }, el) + | TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el) + | TArrayDecl el when t_has_type_param e.etype -> + let _, el = extract_tparams [] el in + print w "( (%s) (new %s " (t_s e.epos e.etype) (t_s e.epos (replace_type_param e.etype)); + write w "{"; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w "}) )" + | TCall ({ eexpr = TLocal { v_name = "__array__" } }, el) + | TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el) + | TArrayDecl el -> + let _, el = extract_tparams [] el in + print w "new %s" (param_t_s e.epos (transform_nativearray_t e.etype)); + let is_double = match follow e.etype with + | TInst(_,[ t ]) -> if like_float t && not (like_int t) then Some t else None + | _ -> None + in + + write w "{"; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + (* this is a hack so we are able to convert ints to boxed Double / Float when needed *) + let e = if is_some is_double then mk_cast (get is_double) e else e in + + expr_s w e; + acc + 1 + ) 0 el); + write w "}" + | TCall( ( { eexpr = TField(_, FStatic({ cl_path = ([], "String") }, { cf_name = "fromCharCode" })) } ), [cc] ) -> + write w "Character.toString((char) "; + expr_s w cc; + write w ")" + | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) -> + write w "( "; + expr_s w expr; + write w " instanceof "; + write w (md_s e.epos md); + write w " )" + | TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) -> + write w s + | TCall ({ eexpr = TLocal( { v_name = "__java__" } ) }, { eexpr = TConst(TString(s)) } :: tl ) -> + Codegen.interpolate_code gen.gcon s tl (write w) (expr_s w) e.epos + | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) -> + write w "synchronized("; + let rec loop eobj = match eobj.eexpr with + | TTypeExpr md -> + expr_s w eobj; + write w ".class" + | TMeta(_,e) | TParenthesis(e) -> + loop e + | _ -> + expr_s w eobj + in + loop eobj; + write w ")"; + (match eblock.eexpr with + | TBlock(_ :: _) -> + expr_s w eblock + | _ -> + begin_block w; + expr_s w eblock; + if has_semicolon eblock then write w ";"; + end_block w; + ) + | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> + print w "break label%ld" v + | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) -> + print w "label%ld:" v + | TCall ({ eexpr = TLocal( { v_name = "__typeof__" } ) }, [ { eexpr = TTypeExpr md } as expr ] ) -> + expr_s w expr; + write w ".class" + | TCall (e, el) -> + let params, el = extract_tparams [] el in + + expr_s w e; + + (*(match params with + | [] -> () + | params -> + let md = match e.eexpr with + | TField(ef, _) -> t_to_md (run_follow gen ef.etype) + | _ -> assert false + in + write w "<"; + ignore (List.fold_left (fun acc t -> + (if acc <> 0 then write w ", "); + write w (param_t_s (change_param_type md t)); + acc + 1 + ) 0 params); + write w ">" + );*) + + write w "("; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w ")" + | TNew (({ cl_path = (["java"], "NativeArray") } as cl), params, [ size ]) -> + let rec check_t_s t times = + match real_type t with + | TInst({ cl_path = (["java"], "NativeArray") }, [param]) -> + (check_t_s param (times+1)) + | _ -> + print w "new %s[" (t_s e.epos (transform_nativearray_t t)); + expr_s w size; + print w "]"; + let rec loop i = + if i <= 0 then () else (write w "[]"; loop (i-1)) + in + loop (times - 1) + in + check_t_s (TInst(cl, params)) 0 + | TNew ({ cl_path = ([], "String") } as cl, [], el) -> + write w "new "; + write w (t_s e.epos (TInst(cl, []))); + write w "("; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w ")" + | TNew ({ cl_kind = KTypeParameter _ } as cl, params, el) -> + print w "null /* This code should never be reached. It was produced by the use of @:generic on a new type parameter instance: %s */" (path_param_s e.epos (TClassDecl cl) cl.cl_path params cl.cl_meta) + | TNew (cl, params, el) -> + write w "new "; + write w (path_param_s e.epos (TClassDecl cl) cl.cl_path params cl.cl_meta); + write w "("; + ignore (List.fold_left (fun acc e -> + (if acc <> 0 then write w ", "); + expr_s w e; + acc + 1 + ) 0 el); + write w ")" + | TUnop ((Ast.Increment as op), flag, e) + | TUnop ((Ast.Decrement as op), flag, e) -> + (match flag with + | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e + | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op)) + | TUnop (op, flag, e) -> + (match flag with + | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") " + | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op)) + | TVar (var, eopt) -> + print w "%s " (t_s e.epos var.v_type); + write_id w var.v_name; + (match eopt with + | None -> + write w " = "; + expr_s w (null var.v_type e.epos) + | Some e -> + write w " = "; + expr_s w e + ) + | TBlock [e] when was_in_value -> + expr_s w e + | TBlock el -> + begin_block w; + List.iter (fun e -> + List.iter (fun e -> + in_value := false; + line_directive w e.epos; + expr_s w e; + if has_semicolon e then write w ";"; + newline w; + ) (extract_statements e) + ) el; + end_block w + | TIf (econd, e1, Some(eelse)) when was_in_value -> + write w "( "; + expr_s w (mk_paren econd); + write w " ? "; + expr_s w (mk_paren e1); + write w " : "; + expr_s w (mk_paren eelse); + write w " )"; + | TIf (econd, e1, eelse) -> + write w "if "; + expr_s w (mk_paren econd); + write w " "; + in_value := false; + expr_s w (mk_block e1); + (match eelse with + | None -> () + | Some e -> + write w "else"; + in_value := false; + expr_s w (mk_block e) + ) + | TWhile (econd, eblock, flag) -> + (match flag with + | Ast.NormalWhile -> + write w "while "; + expr_s w (mk_paren econd); + write w ""; + in_value := false; + expr_s w (mk_block eblock) + | Ast.DoWhile -> + write w "do "; + in_value := false; + expr_s w (mk_block eblock); + write w "while "; + in_value := true; + expr_s w (mk_paren econd); + ) + | TSwitch (econd, ele_l, default) -> + write w "switch "; + expr_s w (mk_paren econd); + begin_block w; + List.iter (fun (el, e) -> + List.iter (fun e -> + write w "case "; + in_value := true; + (match e.eexpr with + | TField(_,FEnum(e,ef)) -> + write w ef.ef_name + | _ -> + expr_s w e); + write w ":"; + newline w; + ) el; + in_value := false; + expr_s w (mk_block e); + newline w; + newline w + ) ele_l; + if is_some default then begin + write w "default:"; + newline w; + in_value := false; + expr_s w (get default); + newline w; + end; + end_block w + | TTry (tryexpr, ve_l) -> + write w "try "; + in_value := false; + expr_s w (mk_block tryexpr); + let pos = e.epos in + List.iter (fun (var, e) -> + print w "catch (%s %s)" (t_s pos var.v_type) (var.v_name); + in_value := false; + expr_s w (mk_block e); + newline w + ) ve_l + | TReturn eopt -> + write w "return "; + if is_some eopt then expr_s w (get eopt) + | TBreak -> write w "break" + | TContinue -> write w "continue" + | TThrow e -> + write w "throw "; + expr_s w e + | TCast (e1,md_t) -> + ((*match gen.gfollow#run_f e.etype with + | TType({ t_path = ([], "UInt") }, []) -> + write w "( unchecked ((uint) "; + expr_s w e1; + write w ") )" + | _ ->*) + (* FIXME I'm ignoring module type *) + print w "((%s) (" (t_s e.epos e.etype); + expr_s w e1; + write w ") )" + ) + | TFor (_,_,content) -> + 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 + in + expr_s w e + in + + let rec gen_fpart_attrib w = function + | EConst( Ident i ), _ -> + write w i + | EField( ef, f ), _ -> + gen_fpart_attrib w ef; + write w "."; + write w f + | _, p -> + gen.gcon.error "Invalid expression inside @:meta metadata" p + in + + let rec gen_spart w = function + | EConst c, p -> (match c with + | Int s | Float s | Ident s -> + write w s + | String s -> + write w "\""; + write w (escape s); + write w "\"" + | _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p) + | EField( ef, f ), _ -> + gen_spart w ef; + write w "."; + write w f + | EBinop( Ast.OpAssign, (EConst (Ident s), _), e2 ), _ -> + write w s; + write w " = "; + gen_spart w e2 + | EArrayDecl( el ), _ -> + write w "{"; + let fst = ref true in + List.iter (fun e -> + if !fst then fst := false else write w ", "; + gen_spart w e + ) el; + write w "}" + | ECall(fpart,args), _ -> + gen_fpart_attrib w fpart; + write w "("; + let fst = ref true in + List.iter (fun e -> + if !fst then fst := false else write w ", "; + gen_spart w e + ) args; + write w ")" + | _, p -> + gen.gcon.error "Invalid expression inside @:meta metadata" p + in + + let gen_annotations w ?(add_newline=true) metadata = + List.iter (function + | Meta.Meta, [meta], _ -> + write w "@"; + gen_spart w meta; + if add_newline then newline w else write w " "; + | _ -> () + ) metadata + in + + let argt_s p t = + let w = new_source_writer () in + let rec run t = + match t with + | TType (tdef,p) -> + gen_annotations w ~add_newline:false tdef.t_meta; + run (follow_once t) + | TMono r -> + (match !r with + | Some t -> run t + | _ -> () (* avoid infinite loop / should be the same in this context *)) + | TLazy f -> + run (!f()) + | _ -> () + in + run t; + let ret = t_s p t in + let c = contents w in + if c <> "" then + c ^ " " ^ ret + else + ret + in + + let get_string_params cl_params = + match cl_params with + | [] -> + ("","") + | _ -> + 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_extends = List.fold_left (fun acc (name, t) -> + match run_follow gen t with + | TInst (cl, p) -> + (match cl.cl_implements with + | [] -> 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 Ast.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 *) + ) [] cl_params in + (params, String.concat " " params_extends) + in + + let write_parts w parts = + let parts = List.filter (fun s -> s <> "") parts in + write w (String.concat " " parts) + in + + let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf = + let is_interface = cl.cl_interface in + let name, is_new, is_explicit_iface = match cf.cf_name with + | "new" -> snd cl.cl_path, true, false + | name when String.contains name '.' -> + let fn_name, path = parse_explicit_iface name in + (path_s path cl.cl_meta) ^ "." ^ fn_name, false, true + | name -> name, false, false + in + (match cf.cf_kind with + | Var _ + | Method (MethDynamic) when not (Type.is_extern_field cf) -> + (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then + gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos); + if not is_interface then begin + let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in + write_parts w (access :: (if is_static then "static" else "") :: modifiers @ [(t_s cf.cf_pos (run_follow gen cf.cf_type)); (change_field name)]); + (match cf.cf_expr with + | Some e -> + write w " = "; + expr_s w e; + write w ";" + | None -> write w ";" + ) + end (* TODO see how (get,set) variable handle when they are interfaces *) + | Method _ when Type.is_extern_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 + gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf + ) cf.cf_overloads + | Var _ | Method MethDynamic -> () + | Method mkind -> + List.iter (fun cf -> + if cl.cl_interface || cf.cf_expr <> None then + gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf + ) cf.cf_overloads; + let is_virtual = is_new || (not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false) in + let is_override = match cf.cf_name with + | "equals" when not is_static -> + (match cf.cf_type with + | TFun([_,_,t], ret) -> + (match (real_type t, real_type ret) with + | TDynamic _, TAbstract ({ a_path = ([], "Bool") },[]) + | TAnon _, TAbstract ({ a_path = ([], "Bool") },[]) -> true + | _ -> List.memq cf cl.cl_overrides + ) + | _ -> List.memq cf cl.cl_overrides) + | "toString" when not is_static -> + (match cf.cf_type with + | TFun([], ret) -> + (match real_type ret with + | TInst( { cl_path = ([], "String") }, []) -> true + | _ -> gen.gcon.error "A toString() function should return a String!" cf.cf_pos; false + ) + | _ -> List.memq cf cl.cl_overrides + ) + | "hashCode" when not is_static -> + (match cf.cf_type with + | TFun([], ret) -> + (match real_type ret with + | TAbstract ({ a_path = ([], "Int") },[]) -> + true + | _ -> gen.gcon.error "A hashCode() function should return an Int!" cf.cf_pos; false + ) + | _ -> List.memq cf cl.cl_overrides + ) + | _ -> List.memq cf cl.cl_overrides + in + let visibility = if is_interface then "" else "public" in + + 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 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 + in + + (if is_override && not is_interface then write w "@Override "); + gen_annotations w cf.cf_meta; + (* public static void funcName *) + let params, _ = get_string_params cf.cf_params in + + write_parts w (visibility :: v_n :: modifiers @ [params; (if is_new then "" else rett_s cf.cf_pos (run_follow gen ret_type)); (change_field name)]); + + (* (string arg1, object arg2) with T : object *) + (match cf.cf_expr with + | Some { eexpr = TFunction tf } -> + print w "(%s)" (String.concat ", " (List.map2 (fun (var,_) (_,_,t) -> sprintf "%s %s" (argt_s cf.cf_pos (run_follow gen t)) (change_id var.v_name)) tf.tf_args args)) + | _ -> + print w "(%s)" (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s cf.cf_pos (run_follow gen t)) (change_id name)) args)) + ); + if is_interface || List.mem "native" modifiers then + write w ";" + else begin + let rec loop meta = + match meta with + | [] -> + let expr = match cf.cf_expr with + | None -> mk (TBlock([])) t_dynamic Ast.null_pos + | Some s -> + match s.eexpr with + | TFunction tf -> + mk_block (tf.tf_expr) + | _ -> assert false (* FIXME *) + in + (if is_new then begin + (*let rec get_super_call el = + match el with + | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest -> + Some call, rest + | ( { eexpr = TBlock(bl) } as block ) :: rest -> + let ret, mapped = get_super_call bl in + ret, ( { block with eexpr = TBlock(mapped) } :: rest ) + | _ -> + None, el + in*) + expr_s w expr + end else begin + expr_s w expr; + end) + | (Meta.Throws, [Ast.EConst (Ast.String t), _], _) :: tl -> + print w " throws %s" t; + loop tl + | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> + begin_block w; + write w contents; + end_block w + | _ :: tl -> loop tl + in + loop cf.cf_meta + + end); + newline w; + newline w + in + + let gen_class w cl = + let cf_filters = [ handle_throws ] in + List.iter (fun f -> List.iter (f gen) cl.cl_ordered_fields) cf_filters; + List.iter (fun f -> List.iter (f gen) cl.cl_ordered_statics) cf_filters; + let should_close = match change_ns (fst cl.cl_path) with + | [] -> false + | ns -> + print w "package %s;" (String.concat "." (change_ns ns)); + newline w; + newline w; + false + in + + let rec loop_meta meta acc = + match meta with + | (Meta.SuppressWarnings, [Ast.EConst (Ast.String w),_],_) :: meta -> loop_meta meta (w :: acc) + | _ :: meta -> loop_meta meta acc + | _ -> acc + in + + let suppress_warnings = loop_meta cl.cl_meta [ "rawtypes"; "unchecked" ] in + + write w "import haxe.root.*;"; + newline w; + let w_header = w in + let w = new_source_writer () in + clear_scope(); + + (* add all haxe.root.* to imports *) + List.iter (function + | TClassDecl { cl_path = ([],c) } -> + imports := ([],c) :: !imports + | TEnumDecl { e_path = ([],c) } -> + imports := ([],c) :: !imports + | TAbstractDecl { a_path = ([],c) } -> + imports := ([],c) :: !imports + | _ -> () + ) gen.gtypes_list; + + newline w; + write w "@SuppressWarnings(value={"; + let first = ref true in + List.iter (fun s -> + (if !first then first := false else write w ", "); + print w "\"%s\"" (escape s) + ) suppress_warnings; + write w "})"; + newline w; + gen_annotations w cl.cl_meta; + + let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in + let is_final = Meta.has Meta.Final cl.cl_meta in + + write_parts w (access :: modifiers @ [clt; (change_clname (snd cl.cl_path))]); + + (* type parameters *) + let params, _ = get_string_params cl.cl_params in + let cl_p_to_string (c,p) = + let p = List.map (fun t -> match follow t with + | TMono _ | TDynamic _ -> t_empty + | _ -> t) p + in + path_param_s cl.cl_pos (TClassDecl c) c.cl_path p c.cl_meta + in + print w "%s" params; + (if is_some cl.cl_super then print w " extends %s" (cl_p_to_string (get cl.cl_super))); + (match cl.cl_implements with + | [] -> () + | _ -> print w " %s %s" (if cl.cl_interface then "extends" else "implements") (String.concat ", " (List.map cl_p_to_string cl.cl_implements)) + ); + (* class head ok: *) + (* 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;*) + + let rec loop cl = + List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_fields; + List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_statics; + match cl.cl_super with + | Some(c,_) -> loop c + | None -> () + in + loop cl; + + let rec loop meta = + match meta with + | [] -> () + | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl -> + write w contents + | _ :: tl -> loop tl + 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 "main();"; + end_block w; + newline w + | _ -> () + ); + + (match cl.cl_init with + | None -> () + | Some init -> + write w "static"; + expr_s w (mk_block init); + newline w + ); + + (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor)); + (if not cl.cl_interface then List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics); + List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields; + + end_block w; + if should_close then end_block w; + + (* add imports *) + List.iter (function + | ["haxe";"root"], _ | [], _ -> () + | path -> + write w_header "import "; + write w_header (path_s path []); + write w_header ";\n" + ) !imports; + add_writer w w_header + in + + + let gen_enum w e = + let should_close = match change_ns (fst e.e_path) with + | [] -> false + | ns -> + print w "package %s;" (String.concat "." (change_ns ns)); + newline w; + newline w; + false + in + + gen_annotations w e.e_meta; + print w "public enum %s" (change_clname (snd e.e_path)); + begin_block w; + write w (String.concat ", " (List.map (change_id) e.e_names)); + end_block w; + + if should_close then end_block w + in + + let module_type_gen w md_tp = + match md_tp with + | TClassDecl cl -> + if not cl.cl_extern then begin + gen_class w cl; + newline w; + newline w + end; + (not cl.cl_extern) + | TEnumDecl e -> + if not e.e_extern && not (Meta.has Meta.Class e.e_meta) then begin + gen_enum w e; + newline w; + newline w + end; + (not e.e_extern) + | TTypeDecl e -> + false + | TAbstractDecl a -> + false + in + + let module_gen w md = + module_type_gen w md + in + + (* generate source code *) + init_ctx gen; + + Hashtbl.add gen.gspecial_vars "__label__" true; + Hashtbl.add gen.gspecial_vars "__goto__" true; + Hashtbl.add gen.gspecial_vars "__is__" true; + Hashtbl.add gen.gspecial_vars "__typeof__" true; + Hashtbl.add gen.gspecial_vars "__java__" true; + Hashtbl.add gen.gspecial_vars "__lock__" true; + Hashtbl.add gen.gspecial_vars "__array__" true; + + gen.greal_type <- real_type; + gen.greal_type_param <- change_param_type; + + SetHXGen.run_filter gen SetHXGen.default_hxgen_func; + + (* before running the filters, follow all possible types *) + (* this is needed so our module transformations don't break some core features *) + (* like multitype selection *) + let run_follow_gen = run_follow gen in + let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen) (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in + let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in + List.iter (function + | TClassDecl cl -> + let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in + List.iter (fun cf -> + cf.cf_type <- run_follow_gen cf.cf_type; + cf.cf_expr <- Option.map type_map cf.cf_expr + ) all_fields; + cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic; + cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access; + cl.cl_init <- Option.map type_map cl.cl_init; + cl.cl_super <- Option.map super_map cl.cl_super; + cl.cl_implements <- List.map super_map cl.cl_implements + | _ -> () + ) gen.gtypes_list; + + let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in + + (*let closure_t = ClosuresToClass.create gen 10 float_cl + (fun l -> l) + (fun l -> l) + (fun args -> args) + (fun args -> []) + in + ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e)); + + StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*) + + let get_vmtype t = match real_type t with + | TInst({ cl_path = ["java"],"NativeArray" }, tl) -> t + | TInst(c,tl) -> TInst(c,List.map (fun _ -> t_dynamic) tl) + | TEnum(e,tl) -> TEnum(e, List.map (fun _ -> t_dynamic) tl) + | TType(t,tl) -> TType(t, List.map (fun _ -> t_dynamic) tl) + | TAbstract(a,tl) -> TAbstract(a, List.map (fun _ -> t_dynamic) tl) + | t -> t + in + + FixOverrides.configure ~get_vmtype gen; + Normalize.configure gen ~metas:(Hashtbl.create 0); + AbstractImplementationFix.configure gen; + + IteratorsInterface.configure gen (fun e -> e); + + ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) )); + + let enum_base = (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) in + let param_enum_base = (get_cl (get_type gen (["haxe";"lang"],"ParamEnum")) ) in + EnumToClass.configure gen (None) false true enum_base param_enum_base false false; + + InterfaceVarsDeleteModf.configure gen; + + let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in + + let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in + + (*fixme: THIS IS A HACK. take this off *) + let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in + (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*) + + let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in + let empty_ef = + try + PMap.find "EMPTY" empty_e.e_constrs + with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false + in + OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen; + + let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in + (*let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in*) + let get_specialized_postfix t = match t with + | TAbstract({a_path = [],"Float"}, _) -> "Float" + | TInst({cl_path = [],"String"},_) -> "String" + | TAnon _ | TDynamic _ -> "Dynamic" + | _ -> print_endline (debug_type t); assert false + in + let rcf_static_insert t = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("insert" ^ get_specialized_postfix t) Ast.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) Ast.null_pos [] in + + let can_be_float t = like_float (real_type t) in + + let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe = + let is_float = can_be_float (if is_none may_set then main_expr.etype else (get may_set).etype) in + let fn_name = if is_some may_set then "setField" else "getField" in + let fn_name = if is_float then fn_name ^ "_f" else fn_name in + let pos = field_expr.epos in + + let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in + + let should_cast = match main_expr.etype with | TAbstract({ a_path = ([], "Float") }, []) -> false | _ -> true in + let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in + let first_args = + [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ] + @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else [] + in + let args = first_args @ match is_float, may_set with + | true, Some(set) -> + [ if should_cast then mk_cast basic.tfloat set else set ] + | false, Some(set) -> + [ set ] + | _ -> + [ is_unsafe ] + in + + let call = { main_expr with eexpr = TCall(infer,args) } in + let call = if is_float && should_cast then mk_cast main_expr.etype call else call in + call + in + + let rcf_on_call_field ecall field_expr field may_hash args = + let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in + + let hash_arg = match may_hash with + | None -> [] + | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ] + in + + let arr_call = if args <> [] then + { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos } + else + null (basic.tarray t_dynamic) ecall.epos + in + + + let call_args = + [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ] + @ hash_arg + @ [ arr_call ] + in + + mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args); etype = t_dynamic } + in + + let rcf_ctx = + ReflectionCFs.new_ctx + gen + closure_t + object_iface + false + rcf_on_getset_field + rcf_on_call_field + (fun hash hash_array length -> { hash with eexpr = TCall(rcf_static_find, [hash; hash_array; length]); etype=basic.tint }) + (fun hash -> hash) + (fun hash_array length pos value -> + { hash_array with + eexpr = TBinop(OpAssign, + hash_array, + mk (TCall(rcf_static_insert value.etype, [hash_array; length; pos; value])) hash_array.etype hash_array.epos) + }) + (fun hash_array length pos -> + let t = gen.gclasses.nativearray_type hash_array.etype in + { hash_array with eexpr = TCall(rcf_static_remove t, [hash_array; length; pos]); etype = gen.gcon.basic.tvoid } + ) + false + in + + ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object; + + ReflectionCFs.configure_dynamic_field_access rcf_ctx false; + + (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *) + let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in + + let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in + + ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) ); + + let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in + ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> { + eexpr = TCall(slow_invoke, [ethis; efield; eargs]); + etype = t_dynamic; + epos = ethis.epos; + } ) object_iface; + + let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in + + ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn); + + InitFunction.configure gen true true; + TArrayTransform.configure gen (TArrayTransform.default_implementation gen ( + fun e _ -> + match e.eexpr with + | TArray ({ eexpr = TLocal { v_extra = Some( _ :: _, _) } }, _) -> (* captured transformation *) + false + | TArray(e1, e2) -> + ( match run_follow gen (follow e1.etype) with + | TInst({ cl_path = (["java"], "NativeArray") }, _) -> false + | _ -> true ) + | _ -> assert false + ) "__get" "__set" ); + + let field_is_dynamic t field = + match field_access_esp gen (gen.greal_type t) field with + | FClassField (cl,p,_,_,_,t,_) -> + let p = change_param_type (TClassDecl cl) p in + is_dynamic (apply_params cl.cl_params p t) + | FEnumField _ -> false + | _ -> true + in + + let is_type_param e = match follow e with + | TInst( { cl_kind = KTypeParameter _ },[]) -> true + | _ -> false + in + + let is_dynamic_expr e = + is_dynamic e.etype || match e.eexpr with + | TField(tf, f) -> + field_is_dynamic tf.etype f + | _ -> + false + in + + let may_nullable t = match gen.gfollow#run_f t with + | TType({ t_path = ([], "Null") }, [t]) -> + (match follow t with + | TInst({ cl_path = ([], "String") }, []) + | TAbstract ({ a_path = ([], "Float") },[]) + | TInst({ cl_path = (["haxe"], "Int32")}, [] ) + | TInst({ cl_path = (["haxe"], "Int64")}, [] ) + | TAbstract ({ a_path = ([], "Int") },[]) + | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t + | t when is_java_basic_type t -> Some t + | _ -> None ) + | _ -> None + in + + let is_double t = like_float t && not (like_int t) in + let is_int t = like_int t in + + DynamicOperators.configure gen + (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with + | TBinop (Ast.OpEq, e1, e2) -> + is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype + | TBinop (Ast.OpAdd, e1, e2) + | TBinop (Ast.OpNotEq, e1, e2) -> is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype + | TBinop (Ast.OpLt, e1, e2) + | TBinop (Ast.OpLte, e1, e2) + | TBinop (Ast.OpGte, e1, e2) + | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 || is_string e1.etype || is_string e2.etype + | TBinop (_, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 + | TUnop (_, _, e1) -> + is_dynamic_expr e1 + | _ -> false) + (fun e1 e2 -> + let is_null e = match e.eexpr with | TConst(TNull) | TLocal({ v_name = "__undefined__" }) -> true | _ -> false in + + match e1.eexpr, e2.eexpr with + | TConst c1, TConst c2 when is_null e1 || is_null e2 -> + { e1 with eexpr = TConst(TBool (c1 = c2)); etype = basic.tbool } + | _ when is_null e1 || is_null e2 && not (is_java_basic_type e1.etype || is_java_basic_type e2.etype) -> + { e1 with eexpr = TBinop(Ast.OpEq, e1, e2); etype = basic.tbool } + | _ -> + let is_ref = match follow e1.etype, follow e2.etype with + | TDynamic _, _ + | _, TDynamic _ + | TAbstract ({ a_path = ([], "Float") },[]) , _ + | TInst( { cl_path = (["haxe"], "Int32") }, [] ), _ + | TInst( { cl_path = (["haxe"], "Int64") }, [] ), _ + | TAbstract ({ a_path = ([], "Int") },[]) , _ + | TAbstract ({ a_path = ([], "Bool") },[]) , _ + | _, TAbstract ({ a_path = ([], "Float") },[]) + | _, TAbstract ({ a_path = ([], "Int") },[]) + | _, TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | _, TInst( { cl_path = (["haxe"], "Int64") }, [] ) + | _, TAbstract ({ a_path = ([], "Bool") },[]) + | TInst( { cl_kind = KTypeParameter _ }, [] ), _ + | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false + | _, _ -> true + in + + let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in + { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos } + ) + (fun e e1 e2 -> + match may_nullable e1.etype, may_nullable e2.etype with + | Some t1, Some t2 -> + let t1, t2 = if is_string t1 || is_string t2 then + basic.tstring, basic.tstring + else if is_double t1 || is_double t2 then + basic.tfloat, basic.tfloat + else if is_int t1 || is_int t2 then + basic.tint, basic.tint + else t1, t2 in + { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos } + | _ -> + let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in + mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos }) + (fun e1 e2 -> + if is_string e1.etype then begin + { e1 with eexpr = TCall(mk_field_access gen e1 "compareTo" e1.epos, [ e2 ]); etype = gen.gcon.basic.tint } + end else begin + let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in + { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos } + end)); + + FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func); + + let base_exception = get_cl (get_type gen (["java"; "lang"], "Throwable")) in + let base_exception_t = TInst(base_exception, []) in + + let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in + let hx_exception_t = TInst(hx_exception, []) in + + let rec is_exception t = + match follow t with + | TInst(cl,_) -> + if cl == base_exception then + true + else + (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg))) + | _ -> false + in + + TryCatchWrapper.configure gen + ( + TryCatchWrapper.traverse gen + (fun t -> not (is_exception (real_type t))) + (fun throwexpr expr -> + let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], hx_exception_t)) expr.epos in + { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid } + ) + (fun v_to_unwrap pos -> + let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in + mk_field_access gen local "obj" pos + ) + (fun rethrow -> + let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], hx_exception_t)) rethrow.epos in + { rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]); etype = hx_exception_t }; } + ) + (base_exception_t) + (hx_exception_t) + (fun v e -> + + let exc_cl = get_cl (get_type gen (["haxe";"lang"],"Exceptions")) in + let exc_field = mk_static_field_access_infer exc_cl "setException" e.epos [] in + let esetstack = { eexpr = TCall(exc_field,[mk_local v e.epos]); etype = gen.gcon.basic.tvoid; epos = e.epos } in + + Type.concat esetstack e; + ) + ); + + let get_typeof e = + { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) } + in + + ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt -> get_typeof e)); + + (*let v = alloc_var "$type_param" t_dynamic in*) + TypeParams.configure gen (fun ecall efield params elist -> + { ecall with eexpr = TCall(efield, elist) } + ); + + CastDetect.configure gen (CastDetect.default_implementation gen ~native_string_cast:false (Some (TEnum(empty_e, []))) false); + + (*FollowAll.configure gen;*) + + SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e -> + match e.eexpr with + | TSwitch(cond, cases, def) -> + (match gen.gfollow#run_f cond.etype with + | TInst( { cl_path = (["haxe"], "Int32") }, [] ) + | TAbstract ({ a_path = ([], "Int") },[]) + | TInst({ cl_path = ([], "String") },[]) -> + (List.exists (fun (c,_) -> + List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c + ) cases) + | _ -> true + ) + | _ -> assert false + ) true ); + + ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVar(mk_temp gen "expr" e.etype, Some e); etype = gen.gcon.basic.tvoid; epos = e.epos })); + + UnnecessaryCastsRemoval.configure gen; + + IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true); + + UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true true); + + ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl); + + let goto_special = alloc_var "__goto__" t_dynamic in + let label_special = alloc_var "__label__" t_dynamic in + SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen + (fun e_loop n api -> + { e_loop with eexpr = TBlock( { eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos } :: [e_loop] ) }; + ) + (fun e_break n api -> + { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos } + ) + ); + + DefaultArguments.configure gen (DefaultArguments.traverse gen); + InterfaceMetas.configure gen; + + JavaSpecificSynf.configure gen (JavaSpecificSynf.traverse gen runtime_cl); + JavaSpecificESynf.configure gen (JavaSpecificESynf.traverse 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 + str_cl.cl_super <- Some (get_cl (get_type gen (["haxe";"lang"], "NativeString")), []); + + let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in + mkdir gen.gcon.file; + mkdir (gen.gcon.file ^ "/src"); + + let out_files = ref [] in + + (* add resources array *) + let res = ref [] in + Hashtbl.iter (fun name v -> + res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res; + let name = Codegen.escape_res_name name true in + let full_path = gen.gcon.file ^ "/src/" ^ name in + mkdir_from_path full_path; + + let f = open_out_bin full_path in + output_string f v; + close_out f; + + out_files := (unique_full_path full_path) :: !out_files + ) gen.gcon.resources; + (try + let c = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in + let cf = PMap.find "content" c.cl_statics in + cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos }) + with | Not_found -> ()); + + run_filters gen; + + TypeParams.RenameTypeParameters.run gen; + + let t = Common.timer "code generation" in + + let parts = Str.split_delim (Str.regexp "[\\/]+") gen.gcon.file in + mkdir_recursive "" parts; + generate_modules_t gen "java" "src" change_path module_gen out_files; + + if not (Common.defined gen.gcon Define.KeepOldOutput) then + clean_files (gen.gcon.file ^ "/src") !out_files gen.gcon.verbose; + + let path_s_desc path = path_s path [] in + dump_descriptor gen ("hxjava_build.txt") path_s_desc (fun md -> path_s_desc (t_infos md).mt_path); if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin let old_dir = Sys.getcwd() in Sys.chdir gen.gcon.file; - let cmd = "haxelib run hxjava hxjava_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) in + let cmd = "haxelib run hxjava hxjava_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) ^ " --feature-level 1" in print_endline cmd; if gen.gcon.run_command cmd <> 0 then failwith "Build failed"; Sys.chdir old_dir; end; - t() + t() (* end of configure function *) let before_generate con = - let java_ver = try - int_of_string (PMap.find "java_ver" con.defines) - with | Not_found -> - Common.define_value con Define.JavaVer "7"; - 7 - in + let java_ver = try + int_of_string (PMap.find "java_ver" con.defines) + with | Not_found -> + Common.define_value con Define.JavaVer "7"; + 7 + in if java_ver < 5 then failwith ("Java version is defined to target Java " ^ string_of_int java_ver ^ ", but the compiler can only output code to versions equal or superior to Java 5"); - let rec loop i = - Common.raw_define con ("java" ^ (string_of_int i)); - if i > 0 then loop (i - 1) - in - loop java_ver; - () + let rec loop i = + Common.raw_define con ("java" ^ (string_of_int i)); + if i > 0 then loop (i - 1) + in + loop java_ver; + () let generate con = - let exists = ref false in - con.java_libs <- List.map (fun (file,std,close,la,gr) -> - if String.ends_with file "hxjava-std.jar" then begin - exists := true; - (file,true,close,la,gr) - end else - (file,std,close,la,gr)) con.java_libs; - if not !exists then - failwith "Your version of hxjava is outdated. Please update it by running: `haxelib update hxjava`"; - let gen = new_ctx con in - gen.gallow_tp_dynamic_conversion <- true; - - let basic = con.basic in - (* make the basic functions in java *) - let basic_fns = - [ - mk_class_field "equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) []; - mk_class_field "toString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) []; - mk_class_field "hashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) []; - ] in - List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns; - - (try - configure gen - with | TypeNotFound path -> con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos); - debug_mode := false + let exists = ref false in + con.java_libs <- List.map (fun (file,std,close,la,gr) -> + if String.ends_with file "hxjava-std.jar" then begin + exists := true; + (file,true,close,la,gr) + end else + (file,std,close,la,gr)) con.java_libs; + if not !exists then + failwith "Your version of hxjava is outdated. Please update it by running: `haxelib update hxjava`"; + let gen = new_ctx con in + gen.gallow_tp_dynamic_conversion <- true; + + let basic = con.basic in + (* make the basic functions in java *) + let cl_cl = get_cl (get_type gen (["java";"lang"],"Class")) in + let basic_fns = + [ + mk_class_field "equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "toString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "hashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "getClass" (TFun([], (TInst(cl_cl,[t_dynamic])))) true Ast.null_pos (Method MethNormal) []; + mk_class_field "wait" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "notify" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) []; + mk_class_field "notifyAll" (TFun([], basic.tvoid)) true Ast.null_pos (Method MethNormal) []; + ] in + List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns; + + (try + configure gen + with | TypeNotFound path -> con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos); + debug_mode := false (** Java lib *) open JData type java_lib_ctx = { - jcom : Common.context; - (* current tparams context *) - mutable jtparams : jtypes list; + jcom : Common.context; + (* current tparams context *) + mutable jtparams : jtypes list; } exception ConversionError of string * pos let error s p = raise (ConversionError (s, p)) +let is_haxe_keyword = function + | "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true + | _ -> false + let jname_to_hx name = - (* handle non-inner classes with same final name as non-inner *) - let name = String.concat "__" (String.nsplit name "_") in - (* handle with inner classes *) - String.map (function | '$' -> '_' | c -> c) name + let name = + if name <> "" && (String.get name 0 < 'A' || String.get name 0 > 'Z') then + Char.escaped (Char.uppercase (String.get name 0)) ^ String.sub name 1 (String.length name - 1) + else + name + in + let name = String.concat "__" (String.nsplit name "_") in + String.map (function | '$' -> '_' | c -> c) name + +let normalize_pack pack = + List.map (function + | "" -> "" + | str when String.get str 0 >= 'A' && String.get str 0 <= 'Z' -> + String.lowercase str + | str -> str + ) pack let jpath_to_hx (pack,name) = match pack, name with - | ["haxe";"root"], name -> [], name - | "com" :: ("oracle" | "sun") :: _, _ - | "javax" :: _, _ - | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _ - | "sun" :: _, _ - | "sunw" :: _, _ -> "java" :: pack, jname_to_hx name - | pack, name -> pack, jname_to_hx name - -let hxname_to_j name = - let name = String.implode (List.rev (String.explode name)) in - let fl = String.nsplit name "__" in - let fl = List.map (String.map (fun c -> if c = '_' then '$' else c)) fl in - let ret = String.concat "_" fl in - String.implode (List.rev (String.explode ret)) - -let hxpath_to_j (pack,name) = match pack, name with - | "java" :: "com" :: ("oracle" | "sun") :: _, _ - | "java" :: "javax" :: _, _ - | "java" :: "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _ - | "java" :: "sun" :: _, _ - | "java" :: "sunw" :: _, _ -> List.tl pack, hxname_to_j name - | pack, name -> pack, hxname_to_j name + | ["haxe";"root"], name -> [], name + | "com" :: ("oracle" | "sun") :: _, _ + | "javax" :: _, _ + | "org" :: ("ietf" | "jcp" | "omg" | "w3c" | "xml") :: _, _ + | "sun" :: _, _ + | "sunw" :: _, _ -> "java" :: normalize_pack pack, jname_to_hx name + | pack, name -> normalize_pack pack, jname_to_hx name let real_java_path ctx (pack,name) = - path_s (pack, name) + path_s (pack, name) let lookup_jclass com path = - let path = jpath_to_hx path in - List.fold_right (fun (_,_,_,_,get_raw_class) acc -> - match acc with - | None -> get_raw_class path - | Some p -> Some p - ) com.java_libs None + let path = jpath_to_hx path in + List.fold_right (fun (_,_,_,_,get_raw_class) acc -> + match acc with + | None -> get_raw_class path + | Some p -> Some p + ) com.java_libs None let mk_type_path ctx path params = - let name, sub = try - let p, _ = String.split (snd path) "$" in - jname_to_hx p, Some (jname_to_hx (snd path)) - with | Invalid_string -> - jname_to_hx (snd path), None - in - CTPath { - tpackage = fst (jpath_to_hx path); - tname = name; - tparams = params; - tsub = sub; - } + let name, sub = try + let p, _ = String.split (snd path) "$" in + jname_to_hx p, Some (jname_to_hx (snd path)) + with | Invalid_string -> + jname_to_hx (snd path), None + in + let pack = fst (jpath_to_hx path) in + let pack, sub, name = match path with + | [], ("Float" as c) + | [], ("Int" as c) + | [], ("Single" as c) + | [], ("Bool" as c) + | [], ("Dynamic" as c) + | [], ("Iterator" as c) + | [], ("ArrayAccess" as c) + | [], ("Iterable" as c) -> + [], Some c, "StdTypes" + | [], ("String" as c) -> + ["std"], None, c + | _ -> + pack, sub, name + in + CTPath { + tpackage = pack; + tname = name; + tparams = params; + tsub = sub; + } let has_tparam name params = List.exists(fun (n,_,_) -> n = name) params let rec convert_arg ctx p arg = - match arg with - | TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") []) - | TType (_, jsig) -> TPType (convert_signature ctx p jsig) + match arg with + | TAny | TType (WSuper, _) -> TPType (mk_type_path ctx ([], "Dynamic") []) + | TType (_, jsig) -> TPType (convert_signature ctx p jsig) and convert_signature ctx p jsig = - match jsig with - | TByte -> mk_type_path ctx (["java"; "types"], "Int8") [] - | TChar -> mk_type_path ctx (["java"; "types"], "Char16") [] - | TDouble -> mk_type_path ctx ([], "Float") [] - | TFloat -> mk_type_path ctx ([], "Single") [] - | TInt -> mk_type_path ctx ([], "Int") [] - | TLong -> mk_type_path ctx (["haxe"], "Int64") [] - | TShort -> mk_type_path ctx (["java"; "types"], "Int16") [] - | TBool -> mk_type_path ctx ([], "Bool") [] - | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args) - (** nullable types *) - | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ] - | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ] - | TObject ( (["java";"lang"], "Single"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ] - | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ] - | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ] - | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ] - | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ] - | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ] - (** other std types *) - | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") [] - | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") [] - (** other types *) - | TObject ( path, [] ) -> - (match lookup_jclass ctx.jcom path with - | Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes) - | None -> mk_type_path ctx path []) - | TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args) - | TObjectInner (pack, (name, params) :: inners) -> - let actual_param = match List.rev inners with - | (_, p) :: _ -> p - | _ -> assert false 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 - | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig) ] - | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type" - | TTypeParameter s -> (match ctx.jtparams with - | cur :: others -> - if has_tparam s cur then - mk_type_path ctx ([], s) [] - else begin - if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!"); - mk_type_path ctx ([], "Dynamic") [] - end - | _ -> - if ctx.jcom.verbose then print_endline ("Empty type parameter stack!"); - mk_type_path ctx ([], "Dynamic") []) + match jsig with + | TByte -> mk_type_path ctx (["java"; "types"], "Int8") [] + | TChar -> mk_type_path ctx (["java"; "types"], "Char16") [] + | TDouble -> mk_type_path ctx ([], "Float") [] + | TFloat -> mk_type_path ctx ([], "Single") [] + | TInt -> mk_type_path ctx ([], "Int") [] + | TLong -> mk_type_path ctx (["haxe"], "Int64") [] + | TShort -> mk_type_path ctx (["java"; "types"], "Int16") [] + | TBool -> mk_type_path ctx ([], "Bool") [] + | TObject ( (["haxe";"root"], name), args ) -> mk_type_path ctx ([], name) (List.map (convert_arg ctx p) args) + (** nullable types *) + (* replaced from Null to the actual abstract type to fix #2738 *) + (* | TObject ( (["java";"lang"], "Integer"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Int") []) ] *) + (* | TObject ( (["java";"lang"], "Double"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Float") []) ] *) + (* | TObject ( (["java";"lang"], "Float"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Single") []) ] *) + (* | TObject ( (["java";"lang"], "Boolean"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx ([], "Bool") []) ] *) + (* | TObject ( (["java";"lang"], "Byte"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int8") []) ] *) + (* | TObject ( (["java";"lang"], "Character"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Char16") []) ] *) + (* | TObject ( (["java";"lang"], "Short"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["java";"types"], "Int16") []) ] *) + (* | TObject ( (["java";"lang"], "Long"), [] ) -> mk_type_path ctx ([], "Null") [ TPType (mk_type_path ctx (["haxe"], "Int64") []) ] *) + (** other std types *) + | TObject ( (["java";"lang"], "Object"), [] ) -> mk_type_path ctx ([], "Dynamic") [] + | TObject ( (["java";"lang"], "String"), [] ) -> mk_type_path ctx ([], "String") [] + | TObject ( (["java";"lang"], "Enum"), [_] ) -> mk_type_path ctx ([], "EnumValue") [] + (** other types *) + | TObject ( path, [] ) -> + (match lookup_jclass ctx.jcom path with + | Some (jcl, _, _) -> mk_type_path ctx path (List.map (fun _ -> convert_arg ctx p TAny) jcl.ctypes) + | None -> mk_type_path ctx path []) + | TObject ( path, args ) -> mk_type_path ctx path (List.map (convert_arg ctx p) args) + | TObjectInner (pack, (name, params) :: inners) -> + let actual_param = match List.rev inners with + | (_, p) :: _ -> p + | _ -> assert false 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 + | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig) ] + | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type" + | TTypeParameter s -> (match ctx.jtparams with + | cur :: others -> + if has_tparam s cur then + mk_type_path ctx ([], s) [] + else begin + if ctx.jcom.verbose && not(List.exists (has_tparam s) others) then print_endline ("Type parameter " ^ s ^ " was not found while building type!"); + mk_type_path ctx ([], "Dynamic") [] + end + | _ -> + if ctx.jcom.verbose then print_endline ("Empty type parameter stack!"); + mk_type_path ctx ([], "Dynamic") []) let convert_constant ctx p const = - Option.map_default (function - | ConstString s -> Some (EConst (String s), p) - | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p) - | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p) - | _ -> None) None const + Option.map_default (function + | ConstString s -> Some (EConst (String s), p) + | ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p) + | ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p) + | _ -> None) None const let rec same_sig parent jsig = - match jsig with - | TObject (p,targs) -> parent = p || List.exists (function | TType (_,s) -> same_sig parent s | _ -> false) targs - | TObjectInner(p, ntargs) -> - parent = (p, String.concat "$" (List.map fst ntargs)) || - List.exists (fun (_,targs) -> List.exists (function | TType(_,s) -> same_sig parent s | _ -> false) targs) ntargs - | TArray(s,_) -> same_sig parent s - | _ -> false + match jsig with + | TObject (p,targs) -> parent = p || List.exists (function | TType (_,s) -> same_sig parent s | _ -> false) targs + | TObjectInner(p, ntargs) -> + parent = (p, String.concat "$" (List.map fst ntargs)) || + List.exists (fun (_,targs) -> List.exists (function | TType(_,s) -> same_sig parent s | _ -> false) targs) ntargs + | TArray(s,_) -> same_sig parent s + | _ -> false let convert_param ctx p parent param = - let name, constraints = match param with - | (name, Some extends_sig, implem_sig) -> - name, extends_sig :: implem_sig - | (name, None, implemem_sig) -> - name, implemem_sig - in - let constraints = List.map (fun s -> if same_sig parent s then (TObject( (["java";"lang"], "Object"), [])) else s) constraints in - { - tp_name = name; - tp_params = []; - tp_constraints = List.map (convert_signature ctx p) constraints; - } + let name, constraints = match param with + | (name, Some extends_sig, implem_sig) -> + name, extends_sig :: implem_sig + | (name, None, implemem_sig) -> + name, implemem_sig + in + let constraints = List.map (fun s -> if same_sig parent s then (TObject( (["java";"lang"], "Object"), [])) else s) constraints in + { + tp_name = name; + tp_params = []; + tp_constraints = List.map (convert_signature ctx p) constraints; + } let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false let is_override field = - List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes + List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes let mk_override field = - { field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) } + { field with jf_attributes = ((AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), [] ); ann_elements = [] }]) :: field.jf_attributes) } let del_override field = - { field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes } + { field with jf_attributes = List.filter (fun a -> not (is_override_attrib a)) field.jf_attributes } + +let get_canonical ctx p pack name = + (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst (String name), p], p) let convert_java_enum ctx p pe = - let meta = ref [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ] in - let data = ref [] in - List.iter (fun f -> - if List.mem JEnum f.jf_flags then - data := { ec_name = f.jf_name; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data; - ) pe.cfields; - - EEnum { - d_name = jname_to_hx (snd pe.cpath); - d_doc = None; - d_params = []; (* enums never have type parameters *) - d_meta = !meta; - d_flags = [EExtern]; - d_data = !data; - } - - let convert_java_field ctx p jc field = - let p = { p with pfile = p.pfile ^" (" ^field.jf_name ^")" } in - let cff_doc = None in - let cff_pos = p in - let cff_meta = ref [] in - let cff_access = ref [] in - let cff_name = match field.jf_name with - | "" -> "new" - | ""-> raise Exit (* __init__ field *) - | name when String.length name > 5 -> - (match String.sub name 0 5 with - | "__hx_" | "this$" -> raise Exit - | _ -> name) - | name -> name - in - let jf_constant = ref field.jf_constant in - let readonly = ref false in - - List.iter (function - | JPublic -> cff_access := APublic :: !cff_access - | JPrivate -> raise Exit (* private instances aren't useful on externs *) - | JProtected -> cff_access := APrivate :: !cff_access - | JStatic -> cff_access := AStatic :: !cff_access - | JFinal -> - cff_meta := (Meta.Final, [], p) :: !cff_meta; - (match field.jf_kind, field.jf_vmsignature, field.jf_constant with - | JKField, TObject _, _ -> - jf_constant := None - | JKField, _, Some _ -> - readonly := true; - jf_constant := None; - | _ -> jf_constant := None) - (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *) - | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta - | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta - (* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *) - | _ -> () - ) field.jf_flags; - - List.iter (function - | AttrDeprecated -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta - (* TODO: pass anotations as @:meta *) - | AttrVisibleAnnotations ann -> - List.iter (function - | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } -> - cff_access := AOverride :: !cff_access - | _ -> () - ) ann - | _ -> () - ) field.jf_attributes; - - let kind = match field.jf_kind with - | JKField when !readonly -> - FProp ("default", "null", Some (convert_signature ctx p field.jf_signature), None) - | JKField -> - FVar (Some (convert_signature ctx p field.jf_signature), None) - | JKMethod -> - match field.jf_signature with - | TMethod (args, ret) -> - let old_types = ctx.jtparams in - (match ctx.jtparams with - | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others - | [] -> ctx.jtparams <- field.jf_types :: []); - let i = ref 0 in - let args = List.map (fun s -> - incr i; - "param" ^ string_of_int !i, false, Some(convert_signature ctx p s), None - ) args in - let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in - cff_meta := (Meta.Overload, [], p) :: !cff_meta; - - let types = List.map (function - | (name, Some ext, impl) -> - { - tp_name = name; - tp_params = []; - tp_constraints = List.map (convert_signature ctx p) (ext :: impl); - } - | (name, None, impl) -> - { - tp_name = name; - tp_params = []; - tp_constraints = List.map (convert_signature ctx p) (impl); - } - ) field.jf_types in - ctx.jtparams <- old_types; - - FFun ({ - f_params = types; - f_args = args; - f_type = Some t; - f_expr = None - }) - | _ -> error "Method signature was expected" p - in - let cff_name, cff_meta = - if String.get cff_name 0 = '%' then - let name = (String.sub cff_name 1 (String.length cff_name - 1)) in - "_" ^ name, - (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta - else - cff_name, !cff_meta - in - - { - cff_name = cff_name; - cff_doc = cff_doc; - cff_pos = cff_pos; - cff_meta = cff_meta; - cff_access = !cff_access; - cff_kind = kind - } - - let rec japply_params params jsig = match params with - | [] -> jsig - | _ -> match jsig with - | TTypeParameter s -> (try - List.assoc s params - with | Not_found -> jsig) - | TObject(p,tl) -> - TObject(p, args params tl) - | TObjectInner(sl, stll) -> - TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll) - | TArray(s,io) -> - TArray(japply_params params s, io) - | TMethod(sl, sopt) -> - TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt) - | _ -> jsig - - and args params tl = match params with - | [] -> tl - | _ -> List.map (function - | TAny -> TAny - | TType(w,s) -> TType(w,japply_params params s)) tl - - let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes - - let convert_java_class ctx p jc = - match List.mem JEnum jc.cflags with - | true -> (* is enum *) - convert_java_enum ctx p jc - | false -> - let flags = ref [HExtern] in - (* todo: instead of JavaNative, use more specific definitions *) - let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath) ), p], p] in - - let is_interface = ref false in - List.iter (fun f -> match f with - | JFinal -> meta := (Meta.Final, [], p) :: !meta - | JInterface -> - is_interface := true; - flags := HInterface :: !flags - | JAbstract -> meta := (Meta.Abstract, [], p) :: !meta - | JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta - | _ -> () - ) jc.cflags; - - (match jc.csuper with - | TObject( (["java";"lang"], "Object"), _ ) -> () - | TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta - | _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper)) :: !flags - ); - - List.iter (fun i -> - match i with - | TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta - | _ -> flags := - if !is_interface then - HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags - else - HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags - ) jc.cinterfaces; - - let fields = ref [] in - let jfields = ref [] in - - if jc.cpath <> (["java";"lang"], "CharSequence") then - List.iter (fun f -> - try - if !is_interface && List.mem JStatic f.jf_flags then - () - else begin - fields := convert_java_field ctx p jc f :: !fields; - jfields := f :: !jfields - end - with - | Exit -> () - ) (jc.cfields @ jc.cmethods); - - EClass { - d_name = jname_to_hx (snd jc.cpath); - d_doc = None; - d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes; - d_meta = !meta; - d_flags = !flags; - d_data = !fields; - } - - let create_ctx com = - { - jcom = com; - jtparams = []; - } - - let rec has_type_param = function - | TTypeParameter _ -> true - | TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt - | TArray (s,_) -> has_type_param s - | TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl - | TObject(_, pl) -> List.exists has_type_param_arg pl - | _ -> false - - and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false + let meta = ref (get_canonical ctx p (fst pe.cpath) (snd pe.cpath) :: [Meta.Native, [EConst (String (real_java_path ctx pe.cpath) ), p], p ]) in + let data = ref [] in + List.iter (fun f -> + (* if List.mem JEnum f.jf_flags then *) + match f.jf_vmsignature with + | TObject( path, [] ) when path = pe.cpath && List.mem JStatic f.jf_flags && List.mem JFinal f.jf_flags -> + data := { ec_name = f.jf_name; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data; + | _ -> () + ) pe.cfields; + + EEnum { + d_name = jname_to_hx (snd pe.cpath); + d_doc = None; + d_params = []; (* enums never have type parameters *) + d_meta = !meta; + d_flags = [EExtern]; + d_data = List.rev !data; + } + + let convert_java_field ctx p jc field = + let p = { p with pfile = p.pfile ^" (" ^field.jf_name ^")" } in + let cff_doc = None in + let cff_pos = p in + let cff_meta = ref [] in + let cff_access = ref [] in + let cff_name = match field.jf_name with + | "" -> "new" + | ""-> raise Exit (* __init__ field *) + | name when String.length name > 5 -> + (match String.sub name 0 5 with + | "__hx_" | "this$" -> raise Exit + | _ -> name) + | name -> name + in + let jf_constant = ref field.jf_constant in + let readonly = ref false in + + List.iter (function + | JPublic -> cff_access := APublic :: !cff_access + | JPrivate -> raise Exit (* private instances aren't useful on externs *) + | JProtected -> cff_access := APrivate :: !cff_access + | JStatic -> cff_access := AStatic :: !cff_access + | JFinal -> + cff_meta := (Meta.Final, [], p) :: !cff_meta; + (match field.jf_kind, field.jf_vmsignature, field.jf_constant with + | JKField, TObject _, _ -> + jf_constant := None + | JKField, _, Some _ -> + readonly := true; + jf_constant := None; + | _ -> jf_constant := None) + (* | JSynchronized -> cff_meta := (Meta.Synchronized, [], p) :: !cff_meta *) + | JVolatile -> cff_meta := (Meta.Volatile, [], p) :: !cff_meta + | JTransient -> cff_meta := (Meta.Transient, [], p) :: !cff_meta + (* | JVarArgs -> cff_meta := (Meta.VarArgs, [], p) :: !cff_meta *) + | _ -> () + ) field.jf_flags; + + List.iter (function + | AttrDeprecated when jc.cpath <> (["java";"util"],"Date") -> cff_meta := (Meta.Deprecated, [], p) :: !cff_meta + (* TODO: pass anotations as @:meta *) + | AttrVisibleAnnotations ann -> + List.iter (function + | { ann_type = TObject( (["java";"lang"], "Override"), [] ) } -> + cff_access := AOverride :: !cff_access + | _ -> () + ) ann + | _ -> () + ) field.jf_attributes; + + List.iter (fun jsig -> + match convert_signature ctx p jsig with + | CTPath path -> + cff_meta := (Meta.Throws, [Ast.EConst (Ast.String (path_s (path.tpackage,path.tname))), p],p) :: !cff_meta + | _ -> () + ) field.jf_throws; + + let kind = match field.jf_kind with + | JKField when !readonly -> + FProp ("default", "null", Some (convert_signature ctx p field.jf_signature), None) + | JKField -> + FVar (Some (convert_signature ctx p field.jf_signature), None) + | JKMethod -> + match field.jf_signature with + | TMethod (args, ret) -> + let old_types = ctx.jtparams in + (match ctx.jtparams with + | c :: others -> ctx.jtparams <- (c @ field.jf_types) :: others + | [] -> ctx.jtparams <- field.jf_types :: []); + let i = ref 0 in + let args = List.map (fun s -> + incr i; + "param" ^ string_of_int !i, false, Some(convert_signature ctx p s), None + ) args in + let t = Option.map_default (convert_signature ctx p) (mk_type_path ctx ([], "Void") []) ret in + cff_meta := (Meta.Overload, [], p) :: !cff_meta; + + let types = List.map (function + | (name, Some ext, impl) -> + { + tp_name = name; + tp_params = []; + tp_constraints = List.map (convert_signature ctx p) (ext :: impl); + } + | (name, None, impl) -> + { + tp_name = name; + tp_params = []; + tp_constraints = List.map (convert_signature ctx p) (impl); + } + ) field.jf_types in + ctx.jtparams <- old_types; + + FFun ({ + f_params = types; + f_args = args; + f_type = Some t; + f_expr = None + }) + | _ -> error "Method signature was expected" p + in + let cff_name, cff_meta = + match String.get cff_name 0 with + | '%' -> + let name = (String.sub cff_name 1 (String.length cff_name - 1)) in + if not (is_haxe_keyword name) then + cff_meta := (Meta.Deprecated, [EConst(String( + "This static field `_" ^ name ^ "` is deprecated and will be removed in later versions. Please use `" ^ name ^ "` instead") + ),p], p) :: !cff_meta; + "_" ^ name, + (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta + | _ -> + match String.nsplit cff_name "$" with + | [ no_dollar ] -> + cff_name, !cff_meta + | parts -> + String.concat "_" parts, + (Meta.Native, [EConst (String (cff_name) ), cff_pos], cff_pos) :: !cff_meta + in + if PMap.mem "java_loader_debug" ctx.jcom.defines then + Printf.printf "\t%s%sfield %s : %s\n" (if List.mem AStatic !cff_access then "static " else "") (if List.mem AOverride !cff_access then "override " else "") cff_name (s_sig field.jf_signature); + + { + cff_name = cff_name; + cff_doc = cff_doc; + cff_pos = cff_pos; + cff_meta = cff_meta; + cff_access = !cff_access; + cff_kind = kind + } + + let rec japply_params params jsig = match params with + | [] -> jsig + | _ -> match jsig with + | TTypeParameter s -> (try + List.assoc s params + with | Not_found -> jsig) + | TObject(p,tl) -> + TObject(p, args params tl) + | TObjectInner(sl, stll) -> + TObjectInner(sl, List.map (fun (s,tl) -> (s, args params tl)) stll) + | TArray(s,io) -> + TArray(japply_params params s, io) + | TMethod(sl, sopt) -> + TMethod(List.map (japply_params params) sl, Option.map (japply_params params) sopt) + | _ -> jsig + + and args params tl = match params with + | [] -> tl + | _ -> List.map (function + | TAny -> TAny + | TType(w,s) -> TType(w,japply_params params s)) tl + + let mk_params jtypes = List.map (fun (s,_,_) -> (s,TTypeParameter s)) jtypes + + let convert_java_class ctx p jc = + match List.mem JEnum jc.cflags with + | true -> (* is enum *) + [convert_java_enum ctx p jc] + | false -> + let flags = ref [HExtern] in + if PMap.mem "java_loader_debug" ctx.jcom.defines then begin + let sup = jc.csuper :: jc.cinterfaces in + print_endline ("converting " ^ (if List.mem JAbstract jc.cflags then "abstract " else "") ^ JData.path_s jc.cpath ^ " : " ^ (String.concat ", " (List.map s_sig sup))); + end; + (* todo: instead of JavaNative, use more specific definitions *) + let meta = ref [Meta.JavaNative, [], p; Meta.Native, [EConst (String (real_java_path ctx jc.cpath) ), p], p; get_canonical ctx p (fst jc.cpath) (snd jc.cpath)] in + let force_check = Common.defined ctx.jcom Define.ForceLibCheck in + if not force_check then + meta := (Meta.LibType,[],p) :: !meta; + + let is_interface = ref false in + List.iter (fun f -> match f with + | JFinal -> meta := (Meta.Final, [], p) :: !meta + | JInterface -> + is_interface := true; + flags := HInterface :: !flags + | JAbstract -> meta := (Meta.Abstract, [], p) :: !meta + | JAnnotation -> meta := (Meta.Annotation, [], p) :: !meta + | _ -> () + ) jc.cflags; + + (match jc.csuper with + | TObject( (["java";"lang"], "Object"), _ ) -> () + | TObject( (["haxe";"lang"], "HxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta + | _ -> flags := HExtends (get_type_path ctx (convert_signature ctx p jc.csuper)) :: !flags + ); + + List.iter (fun i -> + match i with + | TObject ( (["haxe";"lang"], "IHxObject"), _ ) -> meta := (Meta.HxGen,[],p) :: !meta + | _ -> flags := + if !is_interface then + HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags + else + HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags + ) jc.cinterfaces; + + let fields = ref [] in + let jfields = ref [] in + + if jc.cpath <> (["java";"lang"], "CharSequence") then + List.iter (fun f -> + try + if !is_interface && List.mem JStatic f.jf_flags then + () + else begin + fields := convert_java_field ctx p jc f :: !fields; + jfields := f :: !jfields + end + with + | Exit -> () + ) (jc.cfields @ jc.cmethods); + + (* make sure the throws types are imported correctly *) + let imports = List.concat (List.map (fun f -> + List.map (fun jsig -> + match convert_signature ctx p jsig with + | 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 + ) f.jf_throws + ) jc.cmethods) in + + (EClass { + d_name = jname_to_hx (snd jc.cpath); + d_doc = None; + d_params = List.map (convert_param ctx p jc.cpath) jc.ctypes; + d_meta = !meta; + d_flags = !flags; + d_data = !fields; + }) :: imports + + let create_ctx com = + { + jcom = com; + jtparams = []; + } + + let rec has_type_param = function + | TTypeParameter _ -> true + | TMethod (lst, opt) -> List.exists has_type_param lst || Option.map_default has_type_param false opt + | TArray (s,_) -> has_type_param s + | TObjectInner (_, stpl) -> List.exists (fun (_,sigs) -> List.exists has_type_param_arg sigs) stpl + | TObject(_, pl) -> List.exists has_type_param_arg pl + | _ -> false + + and has_type_param_arg = function | TType(_,s) -> has_type_param s | _ -> false let rec japply_params jparams jsig = match jparams with - | [] -> jsig - | _ -> - match jsig with - | TObject(path,p) -> - TObject(path, List.map (japply_params_tp jparams ) p) - | TObjectInner(sl,stargl) -> - TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl) - | TArray(jsig,io) -> - TArray(japply_params jparams jsig,io) - | TMethod(args,ret) -> - TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret) - | TTypeParameter s -> (try - List.assoc s jparams - with | Not_found -> jsig) - | _ -> jsig + | [] -> jsig + | _ -> + match jsig with + | TObject(path,p) -> + TObject(path, List.map (japply_params_tp jparams ) p) + | TObjectInner(sl,stargl) -> + TObjectInner(sl,List.map (fun (s,targ) -> (s, List.map (japply_params_tp jparams) targ)) stargl) + | TArray(jsig,io) -> + TArray(japply_params jparams jsig,io) + | TMethod(args,ret) -> + TMethod(List.map (japply_params jparams ) args, Option.map (japply_params jparams ) ret) + | TTypeParameter s -> (try + List.assoc s jparams + with | Not_found -> jsig) + | _ -> jsig and japply_params_tp jparams jtype_argument = match jtype_argument with - | TAny -> TAny - | TType(w,jsig) -> TType(w,japply_params jparams jsig) + | TAny -> TAny + | TType(w,jsig) -> TType(w,japply_params jparams jsig) let mk_jparams jtypes params = match jtypes, params with - | [], [] -> [] - | _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes - | _ -> List.map2 (fun (s,_,_) jt -> match jt with - | TAny -> s, TObject((["java";"lang"],"Object"),[]) - | TType(_,jsig) -> s, jsig) jtypes params + | [], [] -> [] + | _, [] -> List.map (fun (s,_,_) -> s, TObject( (["java";"lang"], "Object"), [] ) ) jtypes + | _ -> List.map2 (fun (s,_,_) jt -> match jt with + | TAny -> s, TObject((["java";"lang"],"Object"),[]) + | TType(_,jsig) -> s, jsig) jtypes params let rec compatible_signature_arg ?arg_test f1 f2 = - let arg_test = match arg_test with - | None -> (fun _ _ -> true) - | Some a -> a - in - if f1 = f2 then - true - else match f1, f2 with - | TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2 - | TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2 - | TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2 - | TTypeParameter t1 , TTypeParameter t2 -> t1 = t2 - | _ -> false + let arg_test = match arg_test with + | None -> (fun _ _ -> true) + | Some a -> a + in + if f1 = f2 then + true + else match f1, f2 with + | TObject(p,a), TObject(p2,a2) -> p = p2 && arg_test a a2 + | TObjectInner(sl, stal), TObjectInner(sl2, stal2) -> sl = sl2 && List.map fst stal = List.map fst stal2 + | TArray(s,_) , TArray(s2,_) -> compatible_signature_arg s s2 + | TTypeParameter t1 , TTypeParameter t2 -> t1 = t2 + | _ -> false let rec compatible_param p1 p2 = match p1, p2 with - | TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2 - | TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true - | TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true - | _ -> false + | TType (_,s1), TType(_,s2) -> compatible_signature_arg ~arg_test:compatible_tparams s1 s2 + | TAny, TType(_, TObject( (["java";"lang"],"Object"), _ )) -> true + | TType(_, TObject( (["java";"lang"],"Object"), _ )), TAny -> true + | _ -> false and compatible_tparams p1 p2 = try match p1, p2 with - | [], [] -> true - | _, [] -> - let p2 = List.map (fun _ -> TAny) p1 in - List.for_all2 compatible_param p1 p2 - | [], _ -> - let p1 = List.map (fun _ -> TAny) p2 in - List.for_all2 compatible_param p1 p2 - | _, _ -> - List.for_all2 compatible_param p1 p2 - with | Invalid_argument("List.for_all2") -> false + | [], [] -> true + | _, [] -> + let p2 = List.map (fun _ -> TAny) p1 in + List.for_all2 compatible_param p1 p2 + | [], _ -> + let p1 = List.map (fun _ -> TAny) p2 in + List.for_all2 compatible_param p1 p2 + | _, _ -> + List.for_all2 compatible_param p1 p2 + with | Invalid_argument("List.for_all2") -> false let get_adapted_sig f f2 = match f.jf_types with - | [] -> - f.jf_signature - | _ -> - let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in - japply_params jparams f.jf_signature + | [] -> + f.jf_signature + | _ -> + let jparams = mk_jparams f.jf_types (List.map (fun (s,_,_) -> TType(WNone, TTypeParameter s)) f2.jf_types) in + japply_params jparams f.jf_signature let compatible_methods f1 f2 = - if List.length f1.jf_types <> List.length f2.jf_types then - false - else match (get_adapted_sig f1 f2), f2.jf_signature with - | TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 -> - List.for_all2 compatible_signature_arg a1 a2 - | _ -> false + if List.length f1.jf_types <> List.length f2.jf_types then + false + else match (get_adapted_sig f1 f2), f2.jf_signature with + | TMethod(a1,_), TMethod(a2,_) when List.length a1 = List.length a2 -> + List.for_all2 compatible_signature_arg a1 a2 + | _ -> false let jcl_from_jsig com jsig = - let path, params = match jsig with - | TObject(path, params) -> - path,params - | TObjectInner(sl, stll) -> - let last_params = ref [] in - let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in - real_path, !last_params - | _ -> raise Not_found - in - match lookup_jclass com path with - | None -> raise Not_found - | Some(c,_,_) -> c,params + let path, params = match jsig with + | TObject(path, params) -> + path,params + | TObjectInner(sl, stll) -> + let last_params = ref [] in + let real_path = sl, String.concat "$" (List.map (fun (s,p) -> last_params := p; s) stll) in + real_path, !last_params + | _ -> raise Not_found + in + match lookup_jclass com path with + | None -> raise Not_found + | Some(c,_,_) -> c,params let jclass_with_params com cls params = try - match cls.ctypes with - | [] -> cls - | _ -> - let jparams = mk_jparams cls.ctypes params in - { cls with - cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields; - cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods; - csuper = japply_params jparams cls.csuper; - cinterfaces = List.map (japply_params jparams) cls.cinterfaces; - } - with Invalid_argument("List.map2") -> - if com.verbose then prerr_endline ("Differing parameters for class: " ^ path_s cls.cpath); - cls + match cls.ctypes with + | [] -> cls + | _ -> + let jparams = mk_jparams cls.ctypes params in + { cls with + cfields = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cfields; + cmethods = List.map (fun f -> { f with jf_signature = japply_params jparams f.jf_signature }) cls.cmethods; + csuper = japply_params jparams cls.csuper; + cinterfaces = List.map (japply_params jparams) cls.cinterfaces; + } + with Invalid_argument("List.map2") -> + if com.verbose then prerr_endline ("Differing parameters for class: " ^ path_s cls.cpath); + cls let is_object = function | TObject( (["java";"lang"], "Object"), [] ) -> true | _ -> false let is_tobject = function | TObject _ | TObjectInner _ -> true | _ -> false let simplify_args args = - if List.for_all (function | TAny -> true | _ -> false) args then [] else args + if List.for_all (function | TAny -> true | _ -> false) args then [] else args let compare_type com s1 s2 = - if s1 = s2 then - 0 - else if not (is_tobject s1) then - if is_tobject s2 then (* Dynamic *) - 1 - else if compatible_signature_arg s1 s2 then - 0 - else - raise Exit - else if not (is_tobject s2) then - -1 - else begin - let rec loop ?(first_error=true) s1 s2 : bool = - if is_object s1 then - s1 = s2 - else if compatible_signature_arg s1 s2 then begin - let p1, p2 = match s1, s2 with - | TObject(_, p1), TObject(_,p2) -> - p1, p2 - | TObjectInner(_, npl1), TObjectInner(_, npl2) -> - snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2)) - | _ -> assert false (* not tobject *) - in - let p1, p2 = simplify_args p1, simplify_args p2 in - let lp1 = List.length p1 in - let lp2 = List.length p2 in - if lp1 > lp2 then - true - else if lp2 > lp1 then - false - else begin - (* if compatible tparams, it's fine *) - if not (compatible_tparams p1 p2) then - raise Exit; (* meaning: found, but incompatible type parameters *) - true - end - end else try - let c, p = jcl_from_jsig com s1 in - let jparams = mk_jparams c.ctypes p in - let super = japply_params jparams c.csuper in - let implements = List.map (japply_params jparams) c.cinterfaces in - loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements - with | Not_found -> - if com.verbose then begin - prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly."); - prerr_endline "Did you forget to include a needed lib?" - end; - if first_error then - not (loop ~first_error:false s2 s1) - else - false - in - if loop s1 s2 then - if loop s2 s1 then - 0 - else - 1 - else - if loop s2 s1 then - -1 - else - -2 - end + if s1 = s2 then + 0 + else if not (is_tobject s1) then + if is_tobject s2 then (* Dynamic *) + 1 + else if compatible_signature_arg s1 s2 then + 0 + else + raise Exit + else if not (is_tobject s2) then + -1 + else begin + let rec loop ?(first_error=true) s1 s2 : bool = + if is_object s1 then + s1 = s2 + else if compatible_signature_arg s1 s2 then begin + let p1, p2 = match s1, s2 with + | TObject(_, p1), TObject(_,p2) -> + p1, p2 + | TObjectInner(_, npl1), TObjectInner(_, npl2) -> + snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2)) + | _ -> assert false (* not tobject *) + in + let p1, p2 = simplify_args p1, simplify_args p2 in + let lp1 = List.length p1 in + let lp2 = List.length p2 in + if lp1 > lp2 then + true + else if lp2 > lp1 then + false + else begin + (* if compatible tparams, it's fine *) + if not (compatible_tparams p1 p2) then + raise Exit; (* meaning: found, but incompatible type parameters *) + true + end + end else try + let c, p = jcl_from_jsig com s1 in + let jparams = mk_jparams c.ctypes p in + let super = japply_params jparams c.csuper in + let implements = List.map (japply_params jparams) c.cinterfaces in + loop ~first_error:first_error super s2 || List.exists (fun super -> loop ~first_error:first_error super s2) implements + with | Not_found -> + prerr_endline ("-java-lib: The type " ^ (s_sig s1) ^ " is referred but was not found. Compilation may not occur correctly."); + prerr_endline "Did you forget to include a needed lib?"; + if first_error then + not (loop ~first_error:false s2 s1) + else + false + in + if loop s1 s2 then + if loop s2 s1 then + 0 + else + 1 + else + if loop s2 s1 then + -1 + else + -2 + end (* given a list of same overload functions, choose the best (or none) *) let select_best com flist = - let rec loop cur_best = function - | [] -> - Some cur_best - | f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with - | TMethod(_,Some r), TMethod(_, Some r2) -> (try - match compare_type com r r2 with - | 0 -> (* same type - select any of them *) - loop cur_best flist - | 1 -> - loop f flist - | -1 -> - loop cur_best flist - | -2 -> (* error - no type is compatible *) - if com.verbose then prerr_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 - with | Exit -> (* incompatible type parameters *) - (* error mode *) - if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2)); - None) - | TMethod _, _ -> (* select the method *) - loop f flist - | _ -> - loop cur_best flist - in - match loop (List.hd flist) (List.tl flist) with - | Some f -> - Some f - | None -> match List.filter (fun f -> not (is_override f)) flist with - (* error mode; take off all override methods *) - | [] -> None - | f :: [] -> Some f - | f :: flist -> Some f (* pick one *) + let rec loop cur_best = function + | [] -> + Some cur_best + | f :: flist -> match get_adapted_sig f cur_best, cur_best.jf_signature with + | TMethod(_,Some r), TMethod(_, Some r2) -> (try + match compare_type com r r2 with + | 0 -> (* same type - select any of them *) + loop cur_best flist + | 1 -> + loop f flist + | -1 -> + loop cur_best flist + | -2 -> (* error - no type is compatible *) + if com.verbose then prerr_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 + with | Exit -> (* incompatible type parameters *) + (* error mode *) + if com.verbose then prerr_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2)); + None) + | TMethod _, _ -> (* select the method *) + loop f flist + | _ -> + loop cur_best flist + in + match loop (List.hd flist) (List.tl flist) with + | Some f -> + Some f + | None -> match List.filter (fun f -> not (is_override f)) flist with + (* error mode; take off all override methods *) + | [] -> None + | f :: [] -> Some f + | f :: flist -> Some f (* pick one *) + +(**** begin normalize_jclass helpers ****) + +let fix_overrides_jclass com cls = + let force_check = Common.defined com Define.ForceLibCheck in + let methods = if force_check then List.map (fun f -> del_override f) cls.cmethods else cls.cmethods in + let cmethods = methods in + let super_fields = [] in + let super_methods = [] in + let nonstatics = List.filter (fun f -> not (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods) in + + let is_pub = fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags in + let cmethods, super_fields = if not (List.mem JInterface cls.cflags) then + List.filter is_pub cmethods, + List.filter is_pub super_fields + else + cmethods,super_fields + in + + let rec loop cls super_methods super_fields cmethods nonstatics = try + match cls.csuper with + | TObject((["java";"lang"],"Object"),_) -> + super_methods,super_fields,cmethods,nonstatics + | _ -> + let cls, params = jcl_from_jsig com cls.csuper in + let cls = jclass_with_params com cls params in + let nonstatics = (List.filter (fun f -> (List.mem JStatic f.jf_flags)) (cls.cfields @ cls.cmethods)) @ nonstatics in + let super_methods = cls.cmethods @ super_methods in + let super_fields = cls.cfields @ super_fields in + let cmethods = if force_check then begin + let overriden = ref [] in + let cmethods = List.map (fun jm -> + (* TODO rewrite/standardize empty spaces *) + if not (is_override jm) && not (List.mem JStatic jm.jf_flags) && List.exists (fun msup -> + let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in + if ret then begin + let f = mk_override msup in + overriden := { f with jf_flags = jm.jf_flags } :: !overriden + end; + ret + ) cls.cmethods then + mk_override jm + else + jm + ) cmethods in + !overriden @ cmethods + end else + cmethods + in + loop cls super_methods super_fields cmethods nonstatics + with | Not_found -> + super_methods,super_fields,cmethods,nonstatics + in + loop cls super_methods super_fields cmethods nonstatics let normalize_jclass com cls = - (* search static / non-static name clash *) - let nonstatics = ref [] in - List.iter (fun f -> - if not(List.mem JStatic f.jf_flags) then nonstatics := f :: !nonstatics - ) (cls.cfields @ cls.cmethods); - (* we won't be able to deal correctly with field's type parameters *) - (* since java sometimes overrides / implements crude (ie no type parameters) versions *) - (* and interchanges between them *) - (* let methods = List.map (fun f -> let f = del_override f in if f.jf_types <> [] then { f with jf_types = []; jf_signature = f.jf_vmsignature } else f ) cls.cmethods in *) - (* let pth = path_s cls.cpath in *) - let methods = List.map (fun f -> del_override f ) cls.cmethods in - (* take off duplicate overload signature class fields from current class *) - let cmethods = ref methods in - let all_methods = ref methods in - let all_fields = ref cls.cfields in - let super_methods = ref [] in - (* fix overrides *) - let rec loop cls = try - match cls.csuper with - | TObject((["java";"lang"],"Object"),_) -> () - | _ -> - let cls, params = jcl_from_jsig com cls.csuper in - let cls = jclass_with_params com cls params in - List.iter (fun f -> if not (List.mem JStatic f.jf_flags) then nonstatics := f :: !nonstatics) (cls.cfields @ cls.cmethods); - super_methods := cls.cmethods @ !super_methods; - all_methods := cls.cmethods @ !all_methods; - all_fields := cls.cfields @ !all_fields; - let overriden = ref [] in - cmethods := List.map (fun jm -> - (* TODO rewrite/standardize empty spaces *) - if not (is_override jm) && not(List.mem JStatic jm.jf_flags) && List.exists (fun msup -> - let ret = msup.jf_name = jm.jf_name && not(List.mem JStatic msup.jf_flags) && compatible_methods msup jm in - if ret then begin - let f = mk_override msup in - overriden := { f with jf_flags = jm.jf_flags } :: !overriden - end; - ret - ) cls.cmethods then - mk_override jm - else - jm - ) !cmethods; - cmethods := !overriden @ !cmethods; - loop cls - with | Not_found -> () - in - if not (List.mem JInterface cls.cflags) then begin - cmethods := List.filter (fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags) !cmethods; - all_fields := List.filter (fun f -> List.exists (function | JPublic | JProtected -> true | _ -> false) f.jf_flags) !all_fields; - end; - loop cls; - (* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *) - let added_interface_fields = ref [] in - let rec loop_interface abstract cls iface = try - match iface with - | TObject ((["java";"lang"],"Object"), _) -> () - | TObject (path,_) when path = cls.cpath -> () - | _ -> - let cif, params = jcl_from_jsig com iface in - let cif = jclass_with_params com cif params in - List.iter (fun jf -> - if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) !all_methods) then begin - let jf = if abstract then del_override jf else jf in - let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *) - - added_interface_fields := jf :: !added_interface_fields; - cmethods := jf :: !cmethods; - all_methods := jf :: !all_methods; - nonstatics := jf :: !nonstatics; - end - ) cif.cmethods; - List.iter (loop_interface abstract cif) cif.cinterfaces; - with Not_found -> () - in - (* another pass: *) - (* if List.mem JAbstract cls.cflags then List.iter loop_interface cls.cinterfaces; *) - (* if not (List.mem JInterface cls.cflags) then *) - List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces; - (* for each added field in the interface, lookup in super_methods possible methods to include *) - (* so we can choose the better method still *) - - List.iter (fun im -> - let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) !super_methods in - let f = List.map mk_override f in - cmethods := f @ !cmethods - ) !added_interface_fields; - (* take off equals, hashCode and toString from interface *) - if List.mem JInterface cls.cflags then cmethods := List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with - | "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_) - | "hashCode", TMethod([], _) - | "toString", TMethod([], _) -> false - | _ -> true - ) !cmethods; - (* change field name to not collide with haxe keywords *) - let map_field f = - let change = match f.jf_name with - | "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true - | _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) !nonstatics -> true - | _ -> false - in - if change then - { f with jf_name = "%" ^ f.jf_name } - else - f - in - (* change static fields that have the same name as methods *) - let cfields = List.map map_field cls.cfields in - let cmethods = List.map map_field !cmethods in - (* take off variable fields that have the same name as methods *) - (* and take off variables that already have been declared *) - let filter_field f f2 = f != f2 && (List.mem JStatic f.jf_flags = List.mem JStatic f2.jf_flags) && f.jf_name = f2.jf_name && f2.jf_kind <> f.jf_kind in - let cfields = List.filter (fun f -> - if List.mem JStatic f.jf_flags then - not (List.exists (filter_field f) cmethods) - else - not (List.exists (filter_field f) !nonstatics) && not (List.exists (fun f2 -> f != f2 && f.jf_name = f2.jf_name && not (List.mem JStatic f2.jf_flags)) !all_fields) ) cfields - in - (* removing duplicate fields. They are there because of return type covariance in Java *) - (* Also, if a method overrides a previous definition, and changes a type parameters' variance, *) - (* we will take it off *) - (* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *) - (* I can't see how this can be any different *) - let rec loop acc = function - | [] -> acc - | f :: cmeths -> - match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with - | [], cmeths -> - loop (f :: acc) cmeths - | flist, cmeths -> match select_best com (f :: flist) with - | None -> - loop acc cmeths - | Some f -> - loop (f :: acc) cmeths - in - (* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *) - let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in - let cmethods = loop [] cmethods in - { cls with cfields = cfields; cmethods = cmethods } - -let rec get_classes_dir pack dir ret = - Array.iter (fun f -> match (Unix.stat (dir ^"/"^ f)).st_kind with - | S_DIR -> - get_classes_dir (pack @ [f]) (dir ^"/"^ f) ret - | _ when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" -> - let path = jpath_to_hx (pack,f) in - ret := path :: !ret; - | _ -> () - ) (Sys.readdir dir) + (* after adding the noCheck metadata, this option will annotate what changes were needed *) + (* and that are now deprecated *) + let force_check = Common.defined com Define.ForceLibCheck in + (* fix overrides *) + let super_methods, super_fields, cmethods, nonstatics = fix_overrides_jclass com cls in + let all_methods = cmethods @ super_methods in + + (* look for interfaces and add missing implementations (may happen on abstracts or by vmsig differences *) + (* (libType): even with libType enabled, we need to add these missing fields - otherwise we won't be able to use them from Haxe *) + let added_interface_fields = ref [] in + let rec loop_interface abstract cls iface = try + match iface with + | TObject ((["java";"lang"],"Object"), _) -> () + | TObject (path,_) when path = cls.cpath -> () + | _ -> + let cif, params = jcl_from_jsig com iface in + let cif = jclass_with_params com cif params in + List.iter (fun jf -> + if not(List.mem JStatic jf.jf_flags) && not (List.exists (fun jf2 -> jf.jf_name = jf2.jf_name && not (List.mem JStatic jf2.jf_flags) && jf.jf_signature = jf2.jf_signature) all_methods) then begin + let jf = if abstract && force_check then del_override jf else jf in + let jf = { jf with jf_flags = JPublic :: jf.jf_flags } in (* interfaces implementations are always public *) + + added_interface_fields := jf :: !added_interface_fields; + end + ) cif.cmethods; + (* we don't need to loop again in the interface unless we are in an abstract class, since these interfaces are already normalized *) + if abstract then List.iter (loop_interface abstract cif) cif.cinterfaces; + with Not_found -> () + in + List.iter (loop_interface (List.mem JAbstract cls.cflags) cls) cls.cinterfaces; + let nonstatics = !added_interface_fields @ nonstatics in + let cmethods = !added_interface_fields @ cmethods in + + (* for each added field in the interface, lookup in super_methods possible methods to include *) + (* so we can choose the better method still *) + let cmethods = if not force_check then + cmethods + else + List.fold_left (fun cmethods im -> + (* see if any of the added_interface_fields need to be declared as override *) + let f = List.find_all (fun jf -> jf.jf_name = im.jf_name && compatible_methods jf im) super_methods in + let f = List.map mk_override f in + f @ cmethods + ) cmethods !added_interface_fields; + in + + (* take off equals, hashCode and toString from interface *) + let cmethods = if List.mem JInterface cls.cflags then List.filter (fun jf -> match jf.jf_name, jf.jf_vmsignature with + | "equals", TMethod([TObject( (["java";"lang"],"Object"), _)],_) + | "hashCode", TMethod([], _) + | "toString", TMethod([], _) -> false + | _ -> true + ) cmethods + else + cmethods + in + + (* change field name to not collide with haxe keywords and with static/non-static members *) + let fold_field acc f = + let change, both = match f.jf_name with + | _ when List.mem JStatic f.jf_flags && List.exists (fun f2 -> f.jf_name = f2.jf_name) nonstatics -> true, true + | _ -> is_haxe_keyword f.jf_name, false + in + let f2 = if change then + { f with jf_name = "%" ^ f.jf_name } + else + f + in + if both then f :: f2 :: acc else f2 :: acc + in + + (* change static fields that have the same name as methods *) + let cfields = List.fold_left fold_field [] cls.cfields in + let cmethods = List.fold_left fold_field [] cmethods in + (* take off variable fields that have the same name as methods *) + (* and take off variables that already have been declared *) + let filter_field f f2 = f != f2 && (List.mem JStatic f.jf_flags = List.mem JStatic f2.jf_flags) && f.jf_name = f2.jf_name && f2.jf_kind <> f.jf_kind in + let cfields = List.filter (fun f -> + if List.mem JStatic f.jf_flags then + not (List.exists (filter_field f) cmethods) + else + not (List.exists (filter_field f) nonstatics) && not (List.exists (fun f2 -> f != f2 && f.jf_name = f2.jf_name && not (List.mem JStatic f2.jf_flags)) super_fields) ) cfields + in + (* now filter any method that clashes with a field - on a superclass *) + let cmethods = if force_check then List.filter (fun f -> + if List.mem JStatic f.jf_flags then + true + else + not (List.exists (filter_field f) super_fields) ) cmethods + else + cmethods + in + (* removing duplicate fields. They are there because of return type covariance in Java *) + (* Also, if a method overrides a previous definition, and changes a type parameters' variance, *) + (* we will take it off *) + (* this means that some rare codes will never compile on Haxe, but unless Haxe adds variance support *) + (* I can't see how this can be any different *) + let rec loop acc = function + | [] -> acc + | f :: cmeths -> + match List.partition (fun f2 -> f.jf_name = f2.jf_name && compatible_methods f f2) cmeths with + | [], cmeths -> + loop (f :: acc) cmeths + | flist, cmeths -> match select_best com (f :: flist) with + | None -> + loop acc cmeths + | Some f -> + loop (f :: acc) cmeths + in + (* last pass: take off all cfields that are internal / private (they won't be accessible anyway) *) + let cfields = List.filter(fun f -> List.exists (fun f -> f = JPublic || f = JProtected) f.jf_flags) cfields in + let cmethods = loop [] cmethods in + { cls with cfields = cfields; cmethods = cmethods } + +(**** end normalize_jclass helpers ****) let get_classes_zip zip = - let ret = ref [] in - List.iter (function - | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" -> - (match List.rev (String.nsplit f "/") with - | clsname :: pack -> - let path = jpath_to_hx (List.rev pack, clsname) in - ret := path :: !ret - | _ -> - ret := ([], jname_to_hx f) :: !ret) - | _ -> () - ) (Zip.entries zip); - !ret + let ret = ref [] in + List.iter (function + | { Zip.is_directory = false; Zip.filename = f } when (String.sub (String.uncapitalize f) (String.length f - 6) 6) = ".class" && not (String.exists f "$") -> + (match List.rev (String.nsplit f "/") with + | clsname :: pack -> + if not (String.contains clsname '$') then begin + let path = jpath_to_hx (List.rev pack, String.sub clsname 0 (String.length clsname - 6)) in + ret := path :: !ret + end + | _ -> + ret := ([], jname_to_hx f) :: !ret) + | _ -> () + ) (Zip.entries zip); + !ret let add_java_lib com file std = - let file = try Common.find_file com file with - | Not_found -> try Common.find_file com (file ^ ".jar") with - | Not_found -> - failwith ("Java lib " ^ file ^ " not found") - in - let get_raw_class, close, list_all_files = - (* check if it is a directory or jar file *) - match (Unix.stat file).st_kind with - | S_DIR -> (* open classes directly from directory *) - (fun (pack, name) -> - let pack, name = hxpath_to_j (pack,name) in - let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in - try - let data = Std.input_file ~bin:true real_path in - - - Some(JReader.parse_class (IO.input_string data), real_path, real_path) - with - | _ -> None), (fun () -> ()), (fun () -> let ret = ref [] in get_classes_dir [] file ret; !ret) - | _ -> (* open zip file *) - let closed = ref false in - let zip = ref (Zip.open_in file) in - let check_open () = - if !closed then begin - prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *) - zip := Zip.open_in file; - closed := false - end - in - (fun (pack, name) -> - let pack, name = hxpath_to_j (pack,name) in - check_open(); - try - let location = (String.concat "/" (pack @ [name]) ^ ".class") in - let entry = Zip.find_entry !zip location in - let data = Zip.read_entry !zip entry in - Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location) - with - | Not_found -> - None), - (fun () -> if not !closed then begin closed := true; Zip.close_in !zip end), - (fun () -> check_open(); get_classes_zip !zip) - in - let cached_types = Hashtbl.create 12 in - let get_raw_class path = - try - Hashtbl.find cached_types path - with | Not_found -> - match get_raw_class path with - | None -> - Hashtbl.add cached_types path None; - None - | Some (i, p1, p2) -> - Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *) - let ret = Some (normalize_jclass com i, p1, p2) in - Hashtbl.replace cached_types path ret; - ret - in - let rec build ctx path p types = - try - if List.mem path !types then - None - else begin - types := path :: !types; - match get_raw_class path, path with - | None, ([], c) -> build ctx (["haxe";"root"], c) p types - | None, _ -> None - | Some (cls, real_path, pos_path), _ -> - if com.verbose then print_endline ("Parsed Java class " ^ (path_s cls.cpath)); - let old_types = ctx.jtparams in - ctx.jtparams <- cls.ctypes :: ctx.jtparams; - - let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in - - let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in - - let ppath = hxpath_to_j path in - let inner = List.fold_left (fun acc (path,out,_,_) -> - let path = jpath_to_hx path in - (if out <> Some ppath then - acc - else match build ctx path p types with - | Some(_,(_, classes)) -> - classes @ acc - | _ -> acc); - ) [] cls.cinner_types in - - (* build anonymous classes also * - let rec loop inner n = - match build ctx (fst path, snd path ^ "$" ^ (string_of_int n)) p types with - | Some(_,(_, classes)) -> - loop (classes @ inner) (n + 1) - | _ -> inner - in - let inner = loop inner 1 in*) - (* add _Statics class *) - let inner = try - if not (List.mem JInterface cls.cflags) then raise Not_found; - let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in - let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in - if not (smethods <> [] || sfields <> []) then raise Not_found; - let obj = TObject( (["java";"lang"],"Object"), []) in - let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in - match ncls with - | EClass c -> - (EClass { c with d_name = c.d_name ^ "_Statics" }, pos) :: inner - | _ -> assert false - with | Not_found -> - inner - in - let ret = Some ( real_path, (pack, (convert_java_class ctx pos cls, pos) :: inner) ) in - ctx.jtparams <- old_types; - ret - end - with - | JReader.Error_message msg -> - if com.verbose then prerr_endline ("Class reader failed: " ^ msg); - None - | e -> - if com.verbose then begin - (* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *) - prerr_endline (Printexc.to_string e) - end; - None - in - let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in - let cached_files = ref None in - let list_all_files () = match !cached_files with - | None -> - let ret = list_all_files () in - cached_files := Some ret; - ret - | Some r -> r - in - - (* TODO: add_dependency m mdep *) - com.load_extern_type <- com.load_extern_type @ [build]; - com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs + let file = if Sys.file_exists file then + file + else try Common.find_file com file with + | Not_found -> try Common.find_file com (file ^ ".jar") with + | Not_found -> + failwith ("Java lib " ^ file ^ " not found") + in + let hxpack_to_jpack = Hashtbl.create 16 in + let get_raw_class, close, list_all_files = + (* check if it is a directory or jar file *) + match (Unix.stat file).st_kind with + | S_DIR -> (* open classes directly from directory *) + let all = ref [] in + let rec iter_files pack dir path = try + let file = Unix.readdir dir in + let filepath = path ^ "/" ^ file in + (if String.ends_with file ".class" && not (String.exists file "$") then + let file = String.sub file 0 (String.length file - 6) in + let path = jpath_to_hx (pack,file) in + all := path :: !all; + Hashtbl.add hxpack_to_jpack path (pack,file) + else if (Unix.stat filepath).st_kind = S_DIR && file <> "." && file <> ".." then + let pack = pack @ [file] in + iter_files (pack) (Unix.opendir filepath) filepath); + iter_files pack dir path + with | End_of_file | Unix.Unix_error _ -> + Unix.closedir dir + in + iter_files [] (Unix.opendir file) file; + let all = !all in + + (fun (pack, name) -> + let real_path = file ^ "/" ^ (String.concat "/" pack) ^ "/" ^ (name ^ ".class") in + try + let data = Std.input_file ~bin:true real_path in + Some(JReader.parse_class (IO.input_string data), real_path, real_path) + with + | _ -> None), (fun () -> ()), (fun () -> all) + | _ -> (* open zip file *) + let closed = ref false in + let zip = ref (Zip.open_in file) in + let check_open () = + if !closed then begin + prerr_endline ("JAR file " ^ file ^ " already closed"); (* if this happens, find when *) + zip := Zip.open_in file; + closed := false + end + in + List.iter (function + | { Zip.is_directory = false; Zip.filename = filename } when String.ends_with filename ".class" -> + let pack = String.nsplit filename "/" in + (match List.rev pack with + | [] -> () + | name :: pack -> + let name = String.sub name 0 (String.length name - 6) in + let pack = List.rev pack in + Hashtbl.add hxpack_to_jpack (jpath_to_hx (pack,name)) (pack,name)) + | _ -> () + ) (Zip.entries !zip); + (fun (pack, name) -> + check_open(); + try + let location = (String.concat "/" (pack @ [name]) ^ ".class") in + let entry = Zip.find_entry !zip location in + let data = Zip.read_entry !zip entry in + Some(JReader.parse_class (IO.input_string data), file, file ^ "@" ^ location) + with + | Not_found -> + None), + (fun () -> if not !closed then begin closed := true; Zip.close_in !zip end), + (fun () -> check_open(); get_classes_zip !zip) + in + let cached_types = Hashtbl.create 12 in + let get_raw_class path = + try + Hashtbl.find cached_types path + with | Not_found -> try + let pack, name = Hashtbl.find hxpack_to_jpack path in + let try_file (pack,name) = + match get_raw_class (pack,name) with + | None -> + Hashtbl.add cached_types path None; + None + | Some (i, p1, p2) -> + Hashtbl.add cached_types path (Some(i,p1,p2)); (* type loop normalization *) + let ret = Some (normalize_jclass com i, p1, p2) in + Hashtbl.replace cached_types path ret; + ret + in + try_file (pack,name) + with Not_found -> + None + in + let replace_canonical_name p pack name_original name_replace decl = + let mk_meta name = (Meta.JavaCanonical, [EConst (String (String.concat "." pack)), p; EConst(String name), p], p) in + let add_meta name metas = + if Meta.has Meta.JavaCanonical metas then + List.map (function + | (Meta.JavaCanonical,[EConst (String cpack), _; EConst(String cname), _],_) -> + let did_replace,name = String.replace cname name_original name_replace in + if not did_replace then print_endline (cname ^ " -> " ^ name_original ^ " -> " ^ name_replace); + mk_meta name + | m -> m + ) metas + else + mk_meta name :: metas + in + match decl with + | EClass c -> + EClass { c with d_meta = add_meta c.d_name c.d_meta } + | EEnum e -> + EEnum { e with d_meta = add_meta e.d_name e.d_meta } + | EAbstract a -> + EAbstract { a with d_meta = add_meta a.d_name a.d_meta } + | d -> d + in + let rec build ctx path p types = + try + if List.mem path !types then + None + else begin + let first = match !types with + | [ ["java";"lang"], "String" ] | [] -> true + | p :: _ -> + false + in + types := path :: !types; + match get_raw_class path, path with + | None, ([], c) -> build ctx (["haxe";"root"], c) p types + | None, _ -> None + | Some (cls, real_path, pos_path), _ -> + let is_disallowed_inner = first && String.exists (snd cls.cpath) "$" in + let is_disallowed_inner = if is_disallowed_inner then begin + let outer, inner = String.split (snd cls.cpath) "$" in + match get_raw_class (fst path, outer) with + | None -> false + | _ -> true + end else + false + in + if is_disallowed_inner then + None + else begin + if com.verbose then print_endline ("Parsed Java class " ^ (path_s cls.cpath)); + let old_types = ctx.jtparams in + ctx.jtparams <- cls.ctypes :: ctx.jtparams; + + let pos = { pfile = pos_path; pmin = 0; pmax = 0; } in + + let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in + + let ppath = Hashtbl.find hxpack_to_jpack path in + let inner = List.fold_left (fun acc (path,out,_,_) -> + let path = jpath_to_hx path in + (if out <> Some ppath then + acc + else match build ctx path p types with + | Some(_,(_, classes)) -> + let base = snd ppath ^ "$" in + (List.map (fun (def,p) -> + replace_canonical_name p (fst ppath) base (snd ppath ^ ".") def, p) classes) @ acc + | _ -> acc); + ) [] cls.cinner_types in + + (* add _Statics class *) + let inner = try + if not (List.mem JInterface cls.cflags) then raise Not_found; + let smethods = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cmethods in + let sfields = List.filter (fun f -> List.mem JStatic f.jf_flags) cls.cfields in + if not (smethods <> [] || sfields <> []) then raise Not_found; + let obj = TObject( (["java";"lang"],"Object"), []) in + let ncls = convert_java_class ctx pos { cls with cmethods = smethods; cfields = sfields; cflags = []; csuper = obj; cinterfaces = []; cinner_types = []; ctypes = [] } in + match ncls with + | EClass c :: imports -> + (EClass { c with d_name = c.d_name ^ "_Statics" }, pos) :: inner @ List.map (fun i -> i,pos) imports + | _ -> assert false + with | Not_found -> + inner + in + let inner_alias = ref SS.empty in + List.iter (fun x -> + match fst x with + | EClass c -> + inner_alias := SS.add c.d_name !inner_alias; + | _ -> () + ) inner; + let alias_list = ref [] in + List.iter (fun x -> + match x with + | (EClass c, pos) -> begin + let parts = String.nsplit c.d_name "_24" in + match parts with + | _ :: _ -> + let alias_name = String.concat "_" parts in + if (not (SS.mem alias_name !inner_alias)) && (not (String.exists (snd path) "_24")) then begin + let alias_def = ETypedef { + d_name = alias_name; + d_doc = None; + d_params = c.d_params; + d_meta = []; + d_flags = []; + d_data = CTPath { + tpackage = pack; + tname = snd path; + tparams = List.map (fun tp -> + TPType (CTPath { + tpackage = []; + tname = tp.tp_name; + tparams = []; + tsub = None; + }) + ) c.d_params; + tsub = Some(c.d_name); + }; + } in + inner_alias := SS.add alias_name !inner_alias; + alias_list := (alias_def, pos) :: !alias_list; + end + | _ -> () + end + | _ -> () + ) inner; + let inner = List.concat [!alias_list ; inner] in + let classes = List.map (fun t -> t,pos) (convert_java_class ctx pos cls) in + let imports, defs = List.partition (function | (EImport(_),_) -> true | _ -> false) (classes @ inner) in + let ret = Some ( real_path, (pack, imports @ defs) ) in + ctx.jtparams <- old_types; + ret + end + end + with + | JReader.Error_message msg -> + prerr_endline ("Class reader failed: " ^ msg); + None + | e -> + if com.verbose then begin + (* prerr_endline (Printexc.get_backtrace ()); requires ocaml 3.11 *) + prerr_endline (Printexc.to_string e) + end; + None + in + let build path p = build (create_ctx com) path p (ref [["java";"lang"], "String"]) in + let cached_files = ref None in + let list_all_files () = match !cached_files with + | None -> + let ret = list_all_files () in + cached_files := Some ret; + ret + | Some r -> r + in + + (* TODO: add_dependency m mdep *) + com.load_extern_type <- com.load_extern_type @ [build]; + com.java_libs <- (file, std, close, list_all_files, get_raw_class) :: com.java_libs diff --git a/genjs.ml b/genjs.ml index 734eb65c9f362cf1ea7ac111f598365528aec1d4..fdcdcba431263ab4ef1fe16194af06b5081fd9c7 100644 --- a/genjs.ml +++ b/genjs.ml @@ -29,7 +29,7 @@ type pos = Ast.pos type sourcemap = { sources : (string) DynArray.t; sources_hash : (string, int) Hashtbl.t; - mappings : Buffer.t; + mappings : Rbuffer.t; mutable source_last_line : int; mutable source_last_col : int; @@ -41,10 +41,11 @@ type sourcemap = { type ctx = { com : Common.context; - buf : Buffer.t; + buf : Rbuffer.t; packages : (string list,unit) Hashtbl.t; smap : sourcemap; js_modern : bool; + js_flatten : bool; mutable current : tclass; mutable statics : (tclass * string * texpr) list; mutable inits : texpr list; @@ -58,7 +59,32 @@ type ctx = { mutable found_expose : bool; } -let s_path ctx = Ast.s_type_path +type object_store = { + os_name : string; + mutable os_fields : object_store list; +} + +let get_exposed ctx path meta = + if not ctx.js_modern then [] + else try + let (_, args, pos) = Meta.get Meta.Expose meta in + (match args with + | [ EConst (String s), _ ] -> [s] + | [] -> [path] + | _ -> error "Invalid @:expose parameters" pos) + with Not_found -> [] + +let dot_path = Ast.s_type_path + +let flat_path (p,s) = + (* Replace _ with _$ in paths to prevent name collisions. *) + let escape str = String.concat "_$" (ExtString.String.nsplit str "_") in + + match p with + | [] -> escape s + | _ -> String.concat "_" (List.map escape p) ^ "_" ^ (escape s) + +let s_path ctx = if ctx.js_flatten then flat_path else dot_path let kwds = let h = Hashtbl.create 0 in @@ -66,14 +92,27 @@ let kwds = "abstract"; "as"; "boolean"; "break"; "byte"; "case"; "catch"; "char"; "class"; "continue"; "const"; "debugger"; "default"; "delete"; "do"; "double"; "else"; "enum"; "export"; "extends"; "false"; "final"; "finally"; "float"; "for"; "function"; "goto"; "if"; "implements"; "import"; "in"; "instanceof"; "int"; - "interface"; "is"; "long"; "namespace"; "native"; "new"; "null"; "package"; "private"; "protected"; + "interface"; "is"; "let"; "long"; "namespace"; "native"; "new"; "null"; "package"; "private"; "protected"; "public"; "return"; "short"; "static"; "super"; "switch"; "synchronized"; "this"; "throw"; "throws"; - "transient"; "true"; "try"; "typeof"; "use"; "var"; "void"; "volatile"; "while"; "with" + "transient"; "true"; "try"; "typeof"; "use"; "var"; "void"; "volatile"; "while"; "with"; "yield" + ]; + h + +(* Identifiers Haxe reserves to make the JS output cleaner. These can still be used in untyped code (TLocal), + but are escaped upon declaration. *) +let kwds2 = + let h = Hashtbl.create 0 in + List.iter (fun s -> Hashtbl.add h s ()) [ + (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects *) + "Infinity"; "NaN"; "decodeURI"; "decodeURIComponent"; "encodeURI"; "encodeURIComponent"; + "escape"; "eval"; "isFinite"; "isNaN"; "parseFloat"; "parseInt"; "undefined"; "unescape"; + + "JSON"; "Number"; "Object"; "console"; "window"; "require"; ]; h let valid_js_ident s = - try + String.length s > 0 && try for i = 0 to String.length s - 1 do match String.unsafe_get s i with | 'a'..'z' | 'A'..'Z' | '$' | '_' -> () @@ -84,8 +123,10 @@ let valid_js_ident s = with Exit -> false -let field s = if Hashtbl.mem kwds s then "[\"" ^ s ^ "\"]" else "." ^ s +let field s = if Hashtbl.mem kwds s || not (valid_js_ident s) then "[\"" ^ s ^ "\"]" else "." ^ s 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 s = match s with @@ -100,7 +141,7 @@ let handle_newlines ctx str = let rec loop from = try begin let next = String.index_from str from '\n' + 1 in - Buffer.add_char ctx.smap.mappings ';'; + Rbuffer.add_char ctx.smap.mappings ';'; ctx.smap.output_last_col <- 0; ctx.smap.print_comma <- false; loop next @@ -113,13 +154,13 @@ let handle_newlines ctx str = let spr ctx s = ctx.separator <- false; handle_newlines ctx s; - Buffer.add_string ctx.buf s + Rbuffer.add_string ctx.buf s let print ctx = ctx.separator <- false; Printf.kprintf (fun s -> begin handle_newlines ctx s; - Buffer.add_string ctx.buf s + Rbuffer.add_string ctx.buf s end) let unsupported p = error "This expression cannot be compiled to Javascript" p @@ -141,7 +182,7 @@ let add_mapping ctx e = let col = col - 1 in if smap.source_last_file != file || smap.source_last_line != line || smap.source_last_col != col then begin if smap.print_comma then - Buffer.add_char smap.mappings ',' + Rbuffer.add_char smap.mappings ',' else smap.print_comma <- true; @@ -168,7 +209,7 @@ let add_mapping ctx e = let continuation_bit = base in let digit = vlq land mask in let next = vlq asr shift in - Buffer.add_char smap.mappings (encode_digit ( + Rbuffer.add_char smap.mappings (encode_digit ( if next > 0 then digit lor continuation_bit else digit)); if next > 0 then loop next else () in @@ -186,15 +227,9 @@ let add_mapping ctx e = smap.output_last_col <- smap.output_current_col end -let basename path = - try - let idx = String.rindex path '/' in - String.sub path (idx + 1) (String.length path - idx - 1) - with Not_found -> path - let write_mappings ctx = - let basefile = basename ctx.com.file in - print ctx "\n//@ sourceMappingURL=%s.map" basefile; + let basefile = Filename.basename ctx.com.file in + print ctx "\n//# sourceMappingURL=%s.map" basefile; let channel = open_out_bin (ctx.com.file ^ ".map") in let sources = DynArray.to_list ctx.smap.sources in let to_url file = @@ -202,30 +237,35 @@ let write_mappings ctx = in output_string channel "{\n"; output_string channel "\"version\":3,\n"; - output_string channel ("\"file\":\"" ^ basefile ^ "\",\n"); - output_string channel ("\"sourceRoot\":\"file://\",\n"); + output_string channel ("\"file\":\"" ^ (String.concat "\\\\" (ExtString.String.nsplit basefile "\\")) ^ "\",\n"); + output_string channel ("\"sourceRoot\":\"file:///\",\n"); output_string channel ("\"sources\":[" ^ (String.concat "," (List.map (fun s -> "\"" ^ to_url s ^ "\"") sources)) ^ "],\n"); + if Common.defined ctx.com Define.SourceMapContent then begin + output_string channel ("\"sourcesContent\":[" ^ + (String.concat "," (List.map (fun s -> try "\"" ^ Ast.s_escape (Std.input_file ~bin:true s) ^ "\"" with _ -> "null") sources)) ^ + "],\n"); + end; output_string channel "\"names\":[],\n"; output_string channel "\"mappings\":\""; - Buffer.output_buffer channel ctx.smap.mappings; + Rbuffer.output_buffer channel ctx.smap.mappings; output_string channel "\"\n"; output_string channel "}"; close_out channel let newline ctx = - match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with + match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with | '}' | '{' | ':' when not ctx.separator -> print ctx "\n%s" ctx.tabs | _ -> print ctx ";\n%s" ctx.tabs let newprop ctx = - match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with + match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with | '{' -> print ctx "\n%s" ctx.tabs | _ -> print ctx "\n%s," ctx.tabs let semicolon ctx = - match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with + match Rbuffer.nth ctx.buf (Rbuffer.length ctx.buf - 1) with | '}' when not ctx.separator -> () | _ -> spr ctx ";" @@ -241,7 +281,7 @@ let fun_block ctx f p = let e = List.fold_left (fun e (a,c) -> match c with | None | Some TNull -> e - | Some c -> Codegen.concat (Codegen.set_default ctx.com a c p) e + | Some c -> Type.concat (Codegen.set_default ctx.com a c p) e ) f.tf_expr f.tf_args in e @@ -260,7 +300,7 @@ let rec has_return e = let rec iter_switch_break in_switch e = match e.eexpr with | TFunction _ | TWhile _ | TFor _ -> () - | TSwitch _ | TMatch _ when not in_switch -> iter_switch_break true e + | TSwitch _ when not in_switch -> iter_switch_break true e | TBreak when in_switch -> raise Exit | _ -> iter (iter_switch_break in_switch) e @@ -288,27 +328,19 @@ let handle_break ctx e = spr ctx "} catch( e ) { if( e != \"__break__\" ) throw e; }"; ) -let handle_expose ctx path meta = - let rec loop = function - | (Meta.Expose, args, pos) :: l when ctx.js_modern -> - ctx.found_expose <- true; - let exposed_path = (match args with - | [EConst (String s), _] -> s - | [] -> path - | _ -> error "Invalid @:expose parameters" pos - ) in - print ctx "$hxExpose(%s, \"%s\")" path exposed_path; - newline ctx - | _ :: l -> loop l - | [] -> () - in - loop meta - let this ctx = match ctx.in_value with None -> "this" | Some _ -> "$this" let is_dynamic_iterator ctx e = let check x = - has_feature ctx "HxOverrides.iter" && (match follow x.etype with TInst ({ cl_path = [],"Array" },_) | TAnon _ | TDynamic _ | TMono _ -> true | _ -> false) + has_feature ctx "HxOverrides.iter" && (match follow x.etype with + | TInst ({ cl_path = [],"Array" },_) + | TInst ({ cl_kind = KTypeParameter _}, _) + | TAnon _ + | TDynamic _ + | TMono _ -> + true + | _ -> false + ) in match e.eexpr with | TField (x,f) when field_name f = "iterator" -> check x @@ -318,9 +350,7 @@ let is_dynamic_iterator ctx e = let gen_constant ctx p = function | TInt i -> print ctx "%ld" i | TFloat s -> spr ctx s - | TString s -> - if String.contains s '\000' then error "A String cannot contain \\0 characters" p; - print ctx "\"%s\"" (Ast.s_escape s) + | TString s -> print ctx "\"%s\"" (Ast.s_escape s) | TBool b -> spr ctx (if b then "true" else "false") | TNull -> spr ctx "null" | TThis -> spr ctx (this ctx) @@ -362,14 +392,36 @@ let rec gen_call ctx e el in_value = spr ctx "("; concat ctx "," (gen_value ctx) params; spr ctx ")"; + | TLocal { v_name = "__js__" }, [{ eexpr = TConst (TString "this") }] -> + spr ctx (this ctx) | TLocal { v_name = "__js__" }, [{ eexpr = TConst (TString code) }] -> spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n")) + | TLocal { v_name = "__js__" }, { eexpr = TConst (TString code); epos = p } :: tl -> + Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p | TLocal { v_name = "__instanceof__" }, [o;t] -> spr ctx "("; gen_value ctx o; print ctx " instanceof "; gen_value ctx t; spr ctx ")"; + | TLocal { v_name = "__typeof__" }, [o] -> + spr ctx "typeof("; + gen_value ctx o; + spr ctx ")"; + | TLocal { v_name = "__strict_eq__" } , [x;y] -> + (* add extra parenthesis here because of operator precedence *) + spr ctx "(("; + gen_value ctx x; + spr ctx ") === "; + gen_value ctx y; + spr ctx ")"; + | TLocal { v_name = "__strict_neq__" } , [x;y] -> + (* add extra parenthesis here because of operator precedence *) + spr ctx "(("; + gen_value ctx x; + spr ctx ") !== "; + gen_value ctx y; + spr ctx ")"; | TLocal ({v_name = "__define_feature__"}), [_;e] -> gen_expr ctx e | TLocal { v_name = "__feature__" }, { eexpr = TConst (TString f) } :: eif :: eelse -> @@ -414,7 +466,7 @@ and gen_expr ctx e = match e.eexpr with | TConst c -> gen_constant ctx e.epos c | TLocal v -> spr ctx (ident v.v_name) - | TArray (e1,{ eexpr = TConst (TString s) }) when valid_js_ident s -> + | TArray (e1,{ eexpr = TConst (TString s) }) when valid_js_ident s && (match e1.eexpr with TConst (TInt _|TFloat _) -> false | _ -> true) -> gen_value ctx e1; spr ctx (field s) | TArray (e1,e2) -> @@ -436,6 +488,12 @@ and gen_expr ctx e = print ctx "$iterator("; gen_value ctx x; print ctx ")"; + | TField (x,FClosure (Some ({cl_path=[],"Array"},_), {cf_name="push"})) -> + (* see https://github.com/HaxeFoundation/haxe/issues/1997 *) + add_feature ctx "use.$arrayPushClosure"; + print ctx "$arrayPushClosure("; + gen_value ctx x; + print ctx ")" | TField (x,FClosure (_,f)) -> add_feature ctx "use.$bind"; (match x.eexpr with @@ -449,16 +507,25 @@ and gen_expr ctx e = print ctx "($_="; gen_value ctx x; print ctx ",$bind($_,$_%s))" (field f.cf_name)) + | TEnumParameter (x,_,i) -> + gen_value ctx x; + print ctx "[%i]" (i + 2) + | TField ({ eexpr = TConst (TInt _ | TFloat _) } as x,f) -> + gen_expr ctx { e with eexpr = TField(mk (TParenthesis x) x.etype x.epos,f) } + | TField (x, (FInstance(_,_,f) | FStatic(_,f) | FAnon(f))) when Meta.has Meta.SelfCall f.cf_meta -> + gen_value ctx x; | TField (x,f) -> gen_value ctx x; let name = field_name f in - spr ctx (match f with FStatic _ | FEnum _ -> static_field name | FInstance _ | FAnon _ | FDynamic _ | FClosure _ -> field name) + spr ctx (match f with FStatic _ -> static_field name | FEnum _ | FInstance _ | FAnon _ | FDynamic _ | FClosure _ -> field name) | TTypeExpr t -> spr ctx (ctx.type_accessor t) | 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 @@ -476,7 +543,7 @@ and gen_expr ctx e = | TBlock el -> print ctx "{"; let bend = open_block ctx in - List.iter (gen_block ctx) el; + List.iter (gen_block_element ctx) el; bend(); newline ctx; print ctx "}"; @@ -498,20 +565,23 @@ and gen_expr ctx e = | TThrow e -> spr ctx "throw "; gen_value ctx e; - | TVars [] -> - () - | TVars vl -> + | TVar (v,eo) -> spr ctx "var "; - concat ctx ", " (fun (v,e) -> - spr ctx (ident v.v_name); - match e with + check_var_declaration v; + spr ctx (ident v.v_name); + begin match eo with | None -> () | Some e -> spr ctx " = "; gen_value ctx e - ) vl; + end + | TNew ({ cl_path = [],"Array" },_,[]) -> + print ctx "[]" | TNew (c,_,el) -> - print ctx "new %s(" (ctx.type_accessor (TClassDecl c)); + (match c.cl_constructor with + | Some cf when Meta.has Meta.SelfCall cf.cf_meta -> () + | _ -> print ctx "new "); + print ctx "%s(" (ctx.type_accessor (TClassDecl c)); concat ctx "," (gen_value ctx) el; spr ctx ")" | TIf (cond,e,eelse) -> @@ -551,10 +621,15 @@ and gen_expr ctx e = handle_break(); | TObjectDecl fields -> spr ctx "{ "; - concat ctx ", " (fun (f,e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields; + concat ctx ", " (fun (f,e) -> (match e.eexpr with + | TMeta((Meta.QuotedField,_,_),e) -> print ctx "'%s' : " f; + | _ -> print ctx "%s : " (anon_field f)); + gen_value ctx e + ) fields; spr ctx "}"; ctx.separator <- true | TFor (v,it,e) -> + check_var_declaration v; let handle_break = handle_break ctx e in let it = ident (match it.eexpr with | TLocal v -> v.v_name @@ -571,7 +646,7 @@ and gen_expr ctx e = let bend = open_block ctx in newline ctx; print ctx "var %s = %s.next()" (ident v.v_name) it; - gen_block ctx e; + gen_block_element ctx e; bend(); newline ctx; spr ctx "}"; @@ -579,7 +654,7 @@ and gen_expr ctx e = | TTry (e,catchs) -> spr ctx "try "; gen_expr ctx e; - let vname = (match catchs with [(v,_)] -> v.v_name | _ -> + let vname = (match catchs with [(v,_)] -> check_var_declaration v; v.v_name | _ -> let id = ctx.id_counter in ctx.id_counter <- ctx.id_counter + 1; "$e" ^ string_of_int id @@ -588,6 +663,17 @@ and gen_expr ctx e = let bend = open_block ctx in let last = ref false in let else_block = ref false in + + if (has_feature ctx "haxe.CallStack.exceptionStack") then begin + newline ctx; + print ctx "%s.lastException = %s" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["haxe"],"CallStack" })) vname + end; + + if (has_feature ctx "js.Boot.HaxeError") then begin + newline ctx; + print ctx "if (%s instanceof %s) %s = %s.val" vname (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js";"_Boot"],"HaxeError" })) vname vname; + end; + List.iter (fun (v,e) -> if !last then () else let t = (match follow v.v_type with @@ -611,7 +697,7 @@ and gen_expr ctx e = newline ctx; print ctx "var %s = %s" v.v_name vname; end; - gen_block ctx e; + gen_block_element ctx e; if !else_block then begin newline ctx; print ctx "}"; @@ -626,7 +712,7 @@ and gen_expr ctx e = newline ctx; print ctx "var %s = %s" v.v_name vname; end; - gen_block ctx e; + gen_block_element ctx e; bend(); newline ctx; spr ctx "} else "; @@ -636,58 +722,6 @@ and gen_expr ctx e = bend(); newline ctx; spr ctx "}"; - | TMatch (e,(estruct,_),cases,def) -> - let evar = (if List.for_all (fun (_,pl,_) -> pl = None) cases then begin - spr ctx "switch( "; - gen_value ctx (if Optimizer.need_parent e then Codegen.mk_parent e else e); - spr ctx "[1] ) {"; - "???" - end else begin - let v = (match e.eexpr with - | TLocal v -> v.v_name - | _ -> - spr ctx "var $e = "; - gen_value ctx e; - newline ctx; - "$e" - ) in - print ctx "switch( %s[1] ) {" v; - v - end) in - List.iter (fun (cl,params,e) -> - List.iter (fun c -> - newline ctx; - print ctx "case %d:" c; - ) cl; - let bend = open_block ctx in - (match params with - | None -> () - | Some l -> - let n = ref 1 in - let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,!n) :: acc) [] l in - newline ctx; - spr ctx "var "; - concat ctx ", " (fun (v,n) -> - print ctx "%s = %s[%d]" (ident v) evar n; - ) l); - gen_block ctx e; - if not (has_return e) then begin - newline ctx; - print ctx "break"; - end; - bend(); - ) cases; - (match def with - | None -> () - | Some e -> - newline ctx; - spr ctx "default:"; - let bend = open_block ctx in - gen_block ctx e; - bend(); - ); - newline ctx; - spr ctx "}" | TSwitch (e,cases,def) -> spr ctx "switch"; gen_value ctx e; @@ -704,7 +738,7 @@ and gen_expr ctx e = spr ctx ":" ) el; let bend = open_block ctx in - gen_block ctx e2; + gen_block_element ctx e2; if not (has_return e2) then begin newline ctx; print ctx "break"; @@ -717,7 +751,7 @@ and gen_expr ctx e = | Some e -> spr ctx "default:"; let bend = open_block ctx in - gen_block ctx e; + gen_block_element ctx e; bend(); newline ctx; ); @@ -725,24 +759,28 @@ and gen_expr ctx e = | TCast (e,None) -> gen_expr ctx e | TCast (e1,Some t) -> - spr ctx "js.Boot.__cast("; + print ctx "%s.__cast(" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js"],"Boot" })); gen_expr ctx e1; spr ctx " , "; spr ctx (ctx.type_accessor t); spr ctx ")" -and gen_block ?(after=false) ctx e = +and gen_block_element ?(after=false) ctx e = match e.eexpr with | TBlock el -> - List.iter (gen_block ~after ctx) el + List.iter (gen_block_element ~after ctx) el | TCall ({ eexpr = TLocal { v_name = "__feature__" } }, { eexpr = TConst (TString f) } :: eif :: eelse) -> if has_feature ctx f then - gen_block ~after ctx eif + gen_block_element ~after ctx eif else (match eelse with | [] -> () - | [e] -> gen_block ~after ctx e + | [e] -> gen_block_element ~after ctx e | _ -> assert false) + | TFunction _ -> + gen_block_element ~after ctx (mk (TParenthesis e) e.etype e.epos) + | TObjectDecl fl -> + List.iter (fun (_,e) -> gen_block_element ~after ctx e) fl | _ -> if not after then newline ctx; gen_expr ctx e; @@ -784,6 +822,7 @@ and gen_value ctx e = | TArray _ | TBinop _ | TField _ + | TEnumParameter _ | TTypeExpr _ | TParenthesis _ | TObjectDecl _ @@ -792,6 +831,8 @@ and gen_value ctx e = | TUnop _ | TFunction _ -> gen_expr ctx e + | TMeta (_,e1) -> + gen_value ctx e1 | TCall (e,el) -> gen_call ctx e el true | TReturn _ @@ -801,12 +842,12 @@ and gen_value ctx e = | TCast (e1, None) -> gen_value ctx e1 | TCast (e1, Some t) -> - spr ctx "js.Boot.__cast("; + print ctx "%s.__cast(" (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js"],"Boot" })); gen_value ctx e1; spr ctx " , "; spr ctx (ctx.type_accessor t); spr ctx ")" - | TVars _ + | TVar _ | TFor _ | TWhile _ | TThrow _ -> @@ -833,7 +874,7 @@ and gen_value ctx e = | TIf (cond,e,eo) -> (* remove parenthesis unless it's an operation with higher precedence than ?: *) let cond = (match cond.eexpr with - | TParenthesis { eexpr = TBinop ((Ast.OpAssign | Ast.OpAssignOp _),_,_) } -> cond + | TParenthesis { eexpr = TBinop ((Ast.OpAssign | Ast.OpAssignOp _),_,_) | TIf _ } -> cond | TParenthesis e -> e | _ -> cond ) in @@ -851,13 +892,6 @@ and gen_value ctx e = match def with None -> None | Some e -> Some (assign e) )) e.etype e.epos); v() - | TMatch (cond,enum,cases,def) -> - let v = value() in - gen_expr ctx (mk (TMatch (cond,enum, - List.map (fun (constr,params,e) -> (constr,params,assign e)) cases, - match def with None -> None | Some e -> Some (assign e) - )) e.etype e.epos); - v() | TTry (b,catchs) -> let v = value() in let block e = mk (TBlock [e]) e.etype e.epos in @@ -885,6 +919,7 @@ let generate_package_create ctx (p,_) = else print ctx "if(!%s) %s = {}" p p ); + ctx.separator <- true; newline ctx; loop (p :: acc) l in @@ -911,12 +946,12 @@ let gen_class_static_field ctx c f = match e.eexpr with | TFunction _ -> let path = (s_path ctx c.cl_path) ^ (static_field f.cf_name) in + let dot_path = (dot_path c.cl_path) ^ (static_field f.cf_name) 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 = " s | _ -> ()); gen_value ctx e; - ctx.separator <- false; newline ctx; - handle_expose ctx path f.cf_meta | _ -> ctx.statics <- (c,f.cf_name,e) :: ctx.statics @@ -940,6 +975,17 @@ let gen_class_field ctx c f = gen_value ctx e; ctx.separator <- false +let generate_class___name__ ctx c = + if has_feature ctx "js.Boot.isClass" then begin + let p = s_path ctx c.cl_path in + print ctx "%s.__name__ = " p; + if has_feature ctx "Type.getClassName" then + print ctx "[%s]" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path]))) + else + print ctx "true"; + newline ctx; + end + let generate_class ctx c = ctx.current <- c; ctx.id_counter <- 0; @@ -947,33 +993,35 @@ let generate_class ctx c = | [],"Function" -> error "This class redefine a native one" c.cl_pos | _ -> ()); let p = s_path ctx c.cl_path in - generate_package_create ctx c.cl_path; let hxClasses = has_feature ctx "Type.resolveClass" in + if ctx.js_flatten then + print ctx "var " + else + generate_package_create ctx c.cl_path; if ctx.js_modern || not hxClasses then print ctx "%s = " p else - print ctx "%s = $hxClasses[\"%s\"] = " p p; - (match c.cl_constructor with - | Some { cf_expr = Some e } -> gen_expr ctx e - | _ -> print ctx "function() { }"); + 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 = " 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) + ); newline ctx; if ctx.js_modern && hxClasses then begin - print ctx "$hxClasses[\"%s\"] = %s" p p; - newline ctx; - end; - handle_expose ctx p c.cl_meta; - if has_feature ctx "js.Boot.isClass" then begin - print ctx "%s.__name__ = " p; - if has_feature ctx "Type.getClassName" then - print ctx "[%s]" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst c.cl_path @ [snd c.cl_path]))) - else - print ctx "true"; + print ctx "$hxClasses[\"%s\"] = %s" (dot_path c.cl_path) p; newline ctx; end; + generate_class___name__ ctx c; (match c.cl_implements with | [] -> () | l -> - print ctx "%s.__interfaces__ = [%s]" p (String.concat "," (List.map (fun (i,_) -> s_path ctx i.cl_path) l)); + print ctx "%s.__interfaces__ = [%s]" p (String.concat "," (List.map (fun (i,_) -> ctx.type_accessor (TClassDecl i)) l)); newline ctx; ); @@ -998,7 +1046,7 @@ let generate_class ctx c = (match c.cl_super with | None -> print ctx "%s.prototype = {" p; | Some (csup,_) -> - let psup = s_path ctx csup.cl_path in + let psup = ctx.type_accessor (TClassDecl csup) in print ctx "%s.__super__ = %s" p psup; newline ctx; print ctx "%s.prototype = $extend(%s.prototype,{" p psup; @@ -1026,19 +1074,23 @@ let generate_class ctx c = bend(); print ctx "\n}"; - (match c.cl_super with None -> () | _ -> print ctx ")"); + (match c.cl_super with None -> ctx.separator <- true | _ -> print ctx ")"); newline ctx end let generate_enum ctx e = let p = s_path ctx e.e_path in - generate_package_create ctx e.e_path; let ename = List.map (fun s -> Printf.sprintf "\"%s\"" (Ast.s_escape s)) (fst e.e_path @ [snd e.e_path]) in + if ctx.js_flatten then + print ctx "var " + else + generate_package_create ctx e.e_path; print ctx "%s = " p; - if has_feature ctx "Type.resolveEnum" then print ctx "$hxClasses[\"%s\"] = " p; + if has_feature ctx "Type.resolveEnum" then print ctx "$hxClasses[\"%s\"] = " (dot_path e.e_path); print ctx "{"; if has_feature ctx "js.Boot.isEnum" then print ctx " __ename__ : %s," (if has_feature ctx "Type.getEnumName" then "[" ^ String.concat "," ename ^ "]" else "true"); print ctx " __constructs__ : [%s] }" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names)); + ctx.separator <- true; newline ctx; List.iter (fun n -> let f = PMap.find n e.e_constrs in @@ -1046,16 +1098,32 @@ let generate_enum ctx e = (match f.ef_type with | TFun (args,_) -> let sargs = String.concat "," (List.map (fun (n,_,_) -> ident n) args) in - print ctx "function(%s) { var $x = [\"%s\",%d,%s]; $x.__enum__ = %s; $x.toString = $estr; return $x; }" sargs f.ef_name f.ef_index sargs p; + print ctx "function(%s) { var $x = [\"%s\",%d,%s]; $x.__enum__ = %s;" sargs f.ef_name f.ef_index sargs p; + if has_feature ctx "has_enum" then + spr ctx " $x.toString = $estr;"; + spr ctx " return $x; }"; + ctx.separator <- true; | _ -> print ctx "[\"%s\",%d]" f.ef_name f.ef_index; newline ctx; - print ctx "%s%s.toString = $estr" p (field f.ef_name); - newline ctx; + if has_feature ctx "has_enum" then begin + print ctx "%s%s.toString = $estr" p (field f.ef_name); + newline ctx; + end; print ctx "%s%s.__enum__ = %s" p (field f.ef_name) p; ); newline ctx ) e.e_names; + if has_feature ctx "Type.allEnums" then begin + let ctors_without_args = List.filter (fun s -> + let ef = PMap.find s e.e_constrs in + match follow ef.ef_type with + | TFun _ -> false + | _ -> true + ) e.e_names in + print ctx "%s.__empty_constructs__ = [%s]" p (String.concat "," (List.map (fun s -> Printf.sprintf "%s.%s" p s) ctors_without_args)); + newline ctx + end; match Codegen.build_metadata ctx.com (TEnumDecl e) with | None -> () | Some e -> @@ -1068,15 +1136,48 @@ let generate_static ctx (c,f,e) = gen_value ctx e; newline ctx +let generate_require ctx path meta = + let _, args, mp = Meta.get Meta.JsRequire meta in + let p = (s_path ctx path) in + + if ctx.js_flatten then + spr ctx "var " + else + generate_package_create ctx path; + + (match args with + | [(EConst(String(module_name)),_)] -> + print ctx "%s = require(\"%s\")" p module_name + | [(EConst(String(module_name)),_) ; (EConst(String(object_path)),_)] -> + print ctx "%s = require(\"%s\").%s" p module_name object_path + | _ -> + error "Unsupported @:jsRequire format" mp); + + newline ctx + let generate_type ctx = function | TClassDecl c -> (match c.cl_init with | None -> () | Some e -> ctx.inits <- e :: ctx.inits); - if not c.cl_extern then generate_class ctx c else if Meta.has Meta.InitPackage c.cl_meta then generate_package_create ctx c.cl_path + (* 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; + (* 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 + () + else if not c.cl_extern then + generate_class ctx c + 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 + else if not ctx.js_flatten && Meta.has Meta.InitPackage c.cl_meta then + (match c.cl_path with + | ([],_) -> () + | _ -> generate_package_create ctx c.cl_path) | TEnumDecl e when e.e_extern -> - () + if Meta.has Meta.JsRequire e.e_meta && is_directly_used ctx.com e.e_meta then + generate_require ctx e.e_path e.e_meta | TEnumDecl e -> generate_enum ctx e | TTypeDecl _ | TAbstractDecl _ -> () @@ -1086,7 +1187,7 @@ let set_current_class ctx c = let alloc_ctx com = let ctx = { com = com; - buf = Buffer.create 16000; + buf = Rbuffer.create 16000; packages = Hashtbl.create 0; smap = { source_last_line = 0; @@ -1097,9 +1198,10 @@ let alloc_ctx com = output_current_col = 0; sources = DynArray.create(); sources_hash = Hashtbl.create 0; - mappings = Buffer.create 16; + mappings = Rbuffer.create 16; }; js_modern = not (Common.defined com Define.JsClassic); + js_flatten = not (Common.defined com Define.JsUnflatten); statics = []; inits = []; current = null_class; @@ -1112,13 +1214,20 @@ let alloc_ctx com = separator = false; found_expose = false; } in - ctx.type_accessor <- (fun t -> s_path ctx (t_path t)); + 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); ctx let gen_single_expr ctx e expr = if expr then gen_expr ctx e else gen_value ctx e; - let str = Buffer.contents ctx.buf in - Buffer.reset ctx.buf; + let str = Rbuffer.unsafe_contents ctx.buf in + Rbuffer.reset ctx.buf; ctx.id_counter <- 0; str @@ -1132,18 +1241,97 @@ let generate com = if has_feature ctx "Class" || has_feature ctx "Type.getClassName" then add_feature ctx "js.Boot.isClass"; if has_feature ctx "Enum" || has_feature ctx "Type.getEnumName" then add_feature ctx "js.Boot.isEnum"; + let exposed = List.concat (List.map (fun t -> + match t with + | 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 f.cf_name) f.cf_meta + ) c.cl_ordered_statics in + List.concat (class_exposed :: static_exposed) + | _ -> [] + ) com.types) 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; + + + let closureArgs = [] in + let closureArgs = if (anyExposed && not (Common.defined com Define.ShallowExpose)) then + ( + "$hx_exports", + (* TODO(bruno): Remove runtime branching when standard node haxelib is available *) + "typeof window != \"undefined\" ? window : exports" + ) :: closureArgs + else + closureArgs + in + (* Provide console for environments that may not have it. *) + let closureArgs = if (not (Common.defined com Define.JsEs5)) then + ( + "console", + "typeof console != \"undefined\" ? console : {log:function(){}}" + ) :: closureArgs + else + closureArgs + in + + if Common.raw_defined com "nodejs" then + (* Add node globals to pseudo-keywords, so they are not shadowed by local vars *) + List.iter (fun s -> Hashtbl.replace kwds2 s ()) [ "global"; "process"; "__filename"; "__dirname"; "module" ]; + if ctx.js_modern then begin (* Additional ES5 strict mode keywords. *) List.iter (fun s -> Hashtbl.replace kwds s ()) [ "arguments"; "eval" ]; - (* Wrap output in a closure. *) - print ctx "(function () { \"use strict\""; + (* Wrap output in a closure *) + if (anyExposed && (Common.defined com Define.ShallowExpose)) then ( + print ctx "var $hx_exports = $hx_exports || {}"; + ctx.separator <- true; + newline ctx + ); + print ctx "(function (%s) { \"use strict\"" (String.concat ", " (List.map fst closureArgs)); newline ctx; + let rec print_obj f root = ( + let path = root ^ "." ^ f.os_name in + print ctx "%s = %s || {}" path path; + ctx.separator <- true; + newline ctx; + concat ctx ";" (fun g -> print_obj g path) f.os_fields + ) + in + List.iter (fun f -> print_obj f "$hx_exports") exposedObject.os_fields; end; + (* If ctx.js_modern, console is defined in closureArgs. *) + if (not ctx.js_modern) && (not (Common.defined com Define.JsEs5)) then + spr ctx "var console = Function(\"return typeof console != 'undefined' ? console : {log:function(){}}\")();\n"; + + (* TODO: fix $estr *) let vars = [] in let vars = (if has_feature ctx "Type.resolveClass" || has_feature ctx "Type.resolveEnum" then ("$hxClasses = " ^ (if ctx.js_modern then "{}" else "$hxClasses || {}")) :: vars else vars) in - let vars = (if List.exists (function TEnumDecl { e_extern = false } -> true | _ -> false) com.types then "$estr = function() { return js.Boot.__string_rec(this,''); }" :: vars else vars) in + let vars = if has_feature ctx "has_enum" + then ("$estr = function() { return " ^ (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js"],"Boot" })) ^ ".__string_rec(this,''); }") :: vars + else vars in (match List.rev vars with | [] -> () | vl -> @@ -1153,7 +1341,7 @@ let generate com = ); if List.exists (function TClassDecl { cl_extern = false; cl_super = Some _ } -> true | _ -> false) com.types then begin print ctx "function $extend(from, fields) { - function inherit() {}; inherit.prototype = from; var proto = new inherit(); + function Inherit() {} Inherit.prototype = from; var proto = new Inherit(); for (var name in fields) proto[name] = fields[name]; if( fields.toString !== Object.prototype.toString ) proto.toString = fields.toString; return proto; @@ -1174,43 +1362,44 @@ let generate com = 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; }"; - ctx.separator <- true; newline ctx; end; if has_feature ctx "use.$bind" then begin print ctx "var $_, $fid = 0"; newline ctx; print ctx "function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }"; - ctx.separator <- true; newline ctx; end; - List.iter (gen_block ~after:true ctx) (List.rev ctx.inits); + if has_feature ctx "use.$arrayPushClosure" then begin + print ctx "function $arrayPushClosure(a) {"; + print ctx " return function(x) { a.push(x); }; "; + print ctx "}"; + newline ctx + end; + List.iter (gen_block_element ~after:true ctx) (List.rev ctx.inits); List.iter (generate_static ctx) (List.rev ctx.statics); (match com.main with | None -> () | Some e -> gen_expr ctx e; newline ctx); - if ctx.found_expose then begin - (* TODO(bruno): Remove runtime branching when standard node haxelib is available *) - print ctx -"function $hxExpose(src, path) { - var o = typeof window != \"undefined\" ? window : exports; - var parts = path.split(\".\"); - for(var ii = 0; ii < parts.length-1; ++ii) { - var p = parts[ii]; - if(typeof o[p] == \"undefined\") o[p] = {}; - o = o[p]; - } - o[parts[parts.length-1]] = src; -}"; - newline ctx; - end; if ctx.js_modern then begin - print ctx "})()"; + print ctx "})(%s)" (String.concat ", " (List.map snd closureArgs)); newline ctx; + if (anyExposed && (Common.defined com Define.ShallowExpose)) then ( + List.iter (fun f -> + print ctx "var %s = $hx_exports.%s" f.os_name f.os_name; + ctx.separator <- true; + newline ctx + ) exposedObject.os_fields; + List.iter (fun f -> + print ctx "var %s = $hx_exports.%s" f f; + ctx.separator <- true; + newline ctx + ) !toplevelExposed + ); end; if com.debug then write_mappings ctx else (try Sys.remove (com.file ^ ".map") with _ -> ()); let ch = open_out_bin com.file in - output_string ch (Buffer.contents ctx.buf); + Rbuffer.output_buffer ch ctx.buf; close_out ch); t() diff --git a/genneko.ml b/genneko.ml index e1f6b51ce9a27a2e0d4ffba73f3ed69b7eb312b6..d64ec87956c4ab721a6125761fabe84f6b8fae77 100644 --- a/genneko.ml +++ b/genneko.ml @@ -35,6 +35,7 @@ type context = { mutable curclass : string; mutable curmethod : string; mutable inits : (tclass * texpr) list; + mutable label_count : int; } let files = Hashtbl.create 0 @@ -50,20 +51,25 @@ let pos ctx p = | false -> try Hashtbl.find files p.pfile - with Not_found -> try - (* lookup relative path *) - let len = String.length p.pfile in - let base = List.find (fun path -> - let l = String.length path in - len > l && String.sub p.pfile 0 l = path - ) ctx.com.Common.class_path in - let l = String.length base in - let path = String.sub p.pfile l (len - l) in + with Not_found -> + let path = (match Common.defined ctx.com Common.Define.AbsolutePath with + | true -> if (Filename.is_relative p.pfile) + then Filename.concat (Sys.getcwd()) p.pfile + else p.pfile + | false -> try + (* lookup relative path *) + let len = String.length p.pfile in + let base = List.find (fun path -> + let l = String.length path in + len > l && String.sub p.pfile 0 l = path + ) ctx.com.Common.class_path in + let l = String.length base in + String.sub p.pfile l (len - l) + + with Not_found -> p.pfile + ) in Hashtbl.add files p.pfile path; path - with Not_found -> - Hashtbl.add files p.pfile p.pfile; - p.pfile ) in { psource = file; @@ -242,12 +248,16 @@ and gen_expr ctx e = call p (ident p ("@closure" ^ string_of_int n)) [tmp;ident p "@fun"] ] , p | _ -> assert false) + | TEnumParameter (e,_,i) -> + EArray (field p (gen_expr ctx e) "args",int p i),p | TField (e,f) -> field p (gen_expr ctx e) (field_name f) | TTypeExpr t -> gen_type_path p (t_path t) | TParenthesis e -> (EParenthesis (gen_expr ctx e),p) + | TMeta (_,e) -> + gen_expr ctx e | TObjectDecl fl -> let hasToString = ref false in let fl = List.map (fun (f,e) -> if f = "toString" then hasToString := (match follow e.etype with TFun ([],_) -> true | _ -> false); f , gen_expr ctx e) fl in @@ -260,9 +270,9 @@ and gen_expr ctx e = call p (field p (gen_type_path p c.cl_path) "new") (List.map (gen_expr ctx) params) | TUnop (op,flag,e) -> gen_unop ctx p op flag e - | TVars vl -> - (EVars (List.map (fun (v,e) -> - let e = (match e with + | TVar (v,eo) -> + (EVars ( + let e = (match eo with | None -> if v.v_capture then Some (call p (builtin p "array") [null p]) @@ -275,8 +285,8 @@ and gen_expr ctx e = else Some e ) in - v.v_name , e - ) vl),p) + [v.v_name, e] + ),p) | TFunction f -> let inits = List.fold_left (fun acc (a,c) -> let acc = if a.v_capture then @@ -322,6 +332,7 @@ and gen_expr ctx e = let path = (match follow v.v_type with | TInst (c,_) -> Some c.cl_path | TEnum (e,_) -> Some e.e_path + | TAbstract (a,_) -> Some a.a_path | TDynamic _ -> None | _ -> assert false ) in @@ -359,64 +370,6 @@ and gen_expr ctx e = gen_expr ctx e | TCast (e1,Some t) -> gen_expr ctx (Codegen.default_cast ~vtmp:"@tmp" ctx.com e1 t e.etype e.epos) - | TMatch (e,_,cases,eo) -> - let p = pos ctx e.epos in - let etmp = (EVars ["@tmp",Some (gen_expr ctx e)],p) in - let eindex = field p (ident p "@tmp") "index" in - let gen_params params e = - match params with - | None -> - gen_expr ctx e - | Some el -> - let count = ref (-1) in - let vars = List.fold_left (fun acc v -> - incr count; - match v with - | None -> - acc - | Some v -> - let e = (EArray (ident p "@tmp",int p (!count)),p) in - let e = (if v.v_capture then call p (builtin p "array") [e] else e) in - (v.v_name , Some e) :: acc - ) [] el in - let e = gen_expr ctx e in - (EBlock [ - (EVars ["@tmp",Some (field p (ident p "@tmp") "args")],p); - (match vars with [] -> null p | _ -> EVars vars,p); - e - ],p) - in - (try - (EBlock [ - etmp; - (ESwitch ( - eindex, - List.map (fun (cl,params,e2) -> - let cond = match cl with - | [s] -> int p s - | _ -> raise Exit - in - cond , gen_params params e2 - ) cases, - (match eo with None -> None | Some e -> Some (gen_expr ctx e)) - ),p) - ],p) - with - Exit -> - (EBlock [ - etmp; - (EVars ["@index",Some eindex],p); - List.fold_left (fun acc (cl,params,e2) -> - let cond = (match cl with - | [] -> assert false - | c :: l -> - let eq c = (EBinop ("==",ident p "@index",int p c),p) in - List.fold_left (fun acc c -> (EBinop ("||",acc,eq c),p)) (eq c) l - ) in - EIf (cond,gen_params params e2,Some acc),p - ) (match eo with None -> null p | Some e -> (gen_expr ctx e)) (List.rev cases) - ],p) - ) | TSwitch (e,cases,eo) -> let e = gen_expr ctx e in let eo = (match eo with None -> None | Some e -> Some (gen_expr ctx e)) in @@ -470,9 +423,9 @@ let gen_class ctx c = let stpath = gen_type_path p c.cl_path in let fnew = (match c.cl_constructor with | Some f -> - (match follow f.cf_type with - | TFun (args,_) -> - let params = List.map (fun (n,_,_) -> n) args in + (match f.cf_expr with + | Some {eexpr = TFunction tf} -> + let params = List.map (fun (v,_) -> v.v_name) tf.tf_args in gen_method ctx p f ["new",(EFunction (params,(EBlock [ (EVars ["@o",Some (call p (builtin p "new") [null p])],p); (call p (builtin p "objsetproto") [ident p "@o"; clpath]); @@ -686,7 +639,7 @@ let gen_name ctx acc t = in setname :: setconstrs :: meta @ acc | TClassDecl c -> - if c.cl_extern then + if c.cl_extern || (match c.cl_kind with KTypeParameter _ -> true | _ -> false) then acc else let p = pos ctx c.cl_pos in @@ -710,9 +663,17 @@ let generate_libs_init = function var @b = if( @s == "Windows" ) @env("HAXEPATH") + "\\lib\\" else try $loader.loadprim("std@file_contents",1)(@env("HOME")+"/.haxelib") + "/" - catch e if( @s == "Linux" ) "/usr/lib/haxe/lib/" else "/usr/local/lib/haxe/lib/"; + catch e + if( @s == "Linux" ) + if( $loader(loadprim("std@sys_exists",1))("/usr/lib/haxe/lib") ) + "/usr/lib/haxe/lib" + else + "/usr/share/haxe/lib/" + else + "/usr/local/lib/haxe/lib/"; + if( try $loader.loadprim("std@sys_file_type",1)(".haxelib") == "dir" catch e false ) @b = $loader.loadprim("std@file_full_path",1)(".haxelib") + "/"; if( $loader.loadprim("std@sys_is64",0)() ) @s = @s + 64; - @s = @s + "/" + @b = @b + "/" *) let p = null_pos in let es = ident p "@s" in @@ -729,15 +690,18 @@ let generate_libs_init = function "@b", Some (EIf (op "==" es (str p "Windows"), op "+" (call p (ident p "@env") [str p "HAXEPATH"]) (str p "\\lib\\"), Some (ETry ( - op "+" (call p (loadp "file_contents" 1) [op "+" (call p (ident p "@env") [str p "HOME"]) (str p "./haxelib")]) (str p "/"), + op "+" (call p (loadp "file_contents" 1) [op "+" (call p (ident p "@env") [str p "HOME"]) (str p "/.haxelib")]) (str p "/"), "e", (EIf (op "==" es (str p "Linux"), - str p "/usr/lib/haxe/lib/", + (EIf (call p (loadp "sys_exists" 1) [ str p "/usr/lib/haxe/lib" ], + str p "/usr/lib/haxe/lib/", + Some (str p "/usr/share/haxe/lib/")),p), Some (str p "/usr/local/lib/haxe/lib/") ),p) ),p) ),p); ],p); + (EIf ((ETry (op "==" (call p (loadp "sys_file_type" 1) [str p ".haxelib"]) (str p "dir"),"e",(EConst False,p)),p),op "=" (ident p "@b") (op "+" (call p (loadp "file_full_path" 1) [str p ".haxelib"]) (str p "/")), None),p); (EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p); op "=" es (op "+" es (str p "/")); ] in @@ -747,7 +711,7 @@ let generate_libs_init = function let dstr = str p dir in (* // for each lib dir - $loader.path = $array($loader.path,dir+@s); + $loader.path = $array($loader.path,@b+dir+@s); *) op "=" lpath (call p (builtin p "array") [op "+" (if full_path then dstr else op "+" (ident p "@b") dstr) (ident p "@s"); lpath]) ) libs @@ -763,6 +727,7 @@ let new_context com ver macros = curclass = "$boot"; curmethod = "$init"; inits = []; + label_count = 0; } let header() = @@ -827,12 +792,14 @@ let generate com = let use_nekoc = Common.defined com Define.UseNekoc in if not use_nekoc then begin try + mkdir_from_path com.file; let ch = IO.output_channel (open_out_bin com.file) in Nbytecode.write ch (Ncompile.compile ctx.version e); IO.close_out ch; with Ncompile.Error (msg,pos) -> + let pfile = Common.find_file com pos.psource in let rec loop p = - let pp = { pfile = pos.psource; pmin = p; pmax = p; } in + let pp = { pfile = pfile; pmin = p; pmax = p; } in if Lexer.get_error_line pp >= pos.pline then pp else diff --git a/genphp.ml b/genphp.ml index 367e2fb1e395b9a1561e34c2e58a74ee97bbd010..7f7e3404dbb701e59897c2a983425770f341cb28 100644 --- a/genphp.ml +++ b/genphp.ml @@ -111,10 +111,6 @@ and type_string_suff suffix haxe_type = | TAbstract ({ a_path = [],"Float" },[]) -> "double" | TAbstract ({ a_path = [],"Bool" },[]) -> "bool" | TAbstract ({ a_path = [],"Void" },[]) -> "Void" - | TEnum ({ e_path = ([],"Void") },[]) -> "Void" - | TEnum ({ e_path = ([],"Bool") },[]) -> "bool" - | TInst ({ cl_path = ([],"Float") },[]) -> "double" - | TInst ({ cl_path = ([],"Int") },[]) -> "int" | TEnum (enum,params) -> (join_class_path enum.e_path "::") ^ suffix | TInst (klass,params) -> (class_string klass suffix params) | TAbstract (abs,params) -> (join_class_path abs.a_path "::") ^ suffix @@ -133,7 +129,7 @@ and type_string_suff suffix haxe_type = (match params with | [t] -> "Array<" ^ (type_string (follow t) ) ^ " >" | _ -> assert false) - | _ -> type_string_suff suffix (apply_params type_def.t_types params type_def.t_type) + | _ -> type_string_suff suffix (apply_params type_def.t_params params type_def.t_type) ) | TFun (args,haxe_type) -> "Dynamic" | TAnon anon -> "Dynamic" @@ -208,7 +204,7 @@ let rec is_string_type t = (match !(a.a_status) with | Statics ({cl_path = ([], "String")}) -> true | _ -> false) - | TAbstract (a,pl) -> is_string_type (Codegen.Abstract.get_underlying_type a pl) + | TAbstract (a,pl) -> is_string_type (Abstract.get_underlying_type a pl) | _ -> false let is_string_expr e = is_string_type e.etype @@ -288,7 +284,7 @@ let escape_bin s = let b = Buffer.create 0 in for i = 0 to String.length s - 1 do match Char.code (String.unsafe_get s i) with - | c when c = Char.code('\\') or c = Char.code('"') or c = Char.code('$') -> + | c when c = Char.code('\\') || c = Char.code('"') || c = Char.code('$') -> Buffer.add_string b "\\"; Buffer.add_char b (Char.chr c) | c when c < 32 -> @@ -312,6 +308,7 @@ let is_keyword n = | "unset" | "use" | "__function__" | "__class__" | "__method__" | "final" | "php_user_filter" | "protected" | "abstract" | "__set" | "__get" | "__call" | "clone" | "instanceof" | "break" | "case" | "class" | "continue" | "default" | "do" | "else" | "extends" | "for" | "function" | "if" | "new" | "return" | "static" | "switch" | "var" | "while" | "interface" | "implements" | "public" | "private" | "try" | "catch" | "throw" -> true + | "goto" | _ -> false let s_ident n = @@ -335,14 +332,10 @@ let create_directory com ldir = (List.iter (fun p -> atm_path := !atm_path ^ "/" ^ p; if not (Sys.file_exists !atm_path) then (Unix.mkdir !atm_path 0o755);) ldir) let write_resource dir name data = - let i = ref 0 in - String.iter (fun c -> - if c = '\\' || c = '/' || c = ':' || c = '*' || c = '?' || c = '"' || c = '<' || c = '>' || c = '|' then String.blit "_" 0 name !i 1; - incr i - ) name; let rdir = dir ^ "/res" in if not (Sys.file_exists dir) then Unix.mkdir dir 0o755; if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755; + let name = Codegen.escape_res_name name false in let ch = open_out_bin (rdir ^ "/" ^ name) in output_string ch data; close_out ch @@ -508,7 +501,7 @@ let fun_block ctx f p = let e = List.fold_left (fun e (v,c) -> match c with | None | Some TNull -> e - | Some c -> Codegen.concat (Codegen.set_default ctx.com v c p) e + | Some c -> Type.concat (Codegen.set_default ctx.com v c p) e ) e f.tf_args in if ctx.com.debug then begin Codegen.stack_block ctx.stack ctx.curclass ctx.curmethod e @@ -596,6 +589,8 @@ and gen_call ctx e el = | TLocal { v_name = "__php__" }, [{ eexpr = TConst (TString code) }] -> (*--php-prefix*) spr ctx (prefix_init_replace ctx.com code) + | TLocal { v_name = "__php__" }, { eexpr = TConst (TString code); epos = p } :: tl -> + Codegen.interpolate_code ctx.com code tl (spr ctx) (gen_expr ctx) p | TLocal { v_name = "__instanceof__" }, [e1;{ eexpr = TConst (TString t) }] -> gen_value ctx e1; print ctx " instanceof %s" t; @@ -609,6 +604,7 @@ and gen_call ctx e el = | TFunction _, [] | TCall _, [] | TParenthesis _, [] + | TMeta _, [] | TBlock _, [] -> ctx.is_call <- true; spr ctx "call_user_func("; @@ -619,6 +615,7 @@ and gen_call ctx e el = | TFunction _, el | TCall _, el | TParenthesis _, el + | TMeta _, el | TBlock _, el -> ctx.is_call <- true; spr ctx "call_user_func_array("; @@ -801,6 +798,7 @@ and gen_field_access ctx isvar e s = gen_member_access ctx isvar e s | TBlock _ | TParenthesis _ + | TMeta _ | TObjectDecl _ | TArrayDecl _ | TNew _ -> @@ -1001,6 +999,7 @@ and gen_expr ctx e = | TCall _ | TBlock _ | TParenthesis _ + | TMeta _ | TArrayDecl _ -> spr ctx "_hx_array_get("; gen_value ctx e1; @@ -1154,7 +1153,7 @@ and gen_expr ctx e = let se1 = s_expr_name e1 in let se2 = s_expr_name e2 in if - e1.eexpr = TConst (TNull) + e1.eexpr = TConst (TNull) || e2.eexpr = TConst (TNull) then begin (match e1.eexpr with @@ -1175,8 +1174,8 @@ and gen_expr ctx e = | _ -> gen_field_op ctx e2); end else if - ((se1 = "Int" || se1 = "Null") && (se2 = "Int" || se2 = "Null")) - || ((se1 = "Float" || se1 = "Null") && (se2 = "Float" || se2 = "Null")) + ((se1 = "Int" || se1 = "Null") && (se2 = "Int" || se2 = "Null")) + || ((se1 = "Float" || se1 = "Null") && (se2 = "Float" || se2 = "Null")) then begin gen_field_op ctx e1; spr ctx s_phop; @@ -1213,15 +1212,39 @@ and gen_expr ctx e = spr ctx s_phop; gen_field_op ctx e2; end else begin + let tmp = define_local ctx "_t" in + print ctx "(is_object($%s = " tmp; gen_field_op ctx e1; - spr ctx s_op; + print ctx ") && !($%s instanceof Enum) ? $%s%s" tmp tmp s_phop; gen_field_op ctx e2; + print ctx " : $%s%s" tmp s_op; + gen_field_op ctx e2; + spr ctx ")"; end + | Ast.OpGt | Ast.OpGte | Ast.OpLt | Ast.OpLte when is_string_expr e1 -> + spr ctx "(strcmp("; + gen_field_op ctx e1; + spr ctx ", "; + gen_field_op ctx e2; + spr ctx ")"; + let op_str = match op with + | Ast.OpGt -> ">" + | Ast.OpGte -> ">=" + | Ast.OpLt -> "<" + | Ast.OpLte -> "<=" + | _ -> assert false + in + print ctx "%s 0)" op_str | _ -> leftside e1; print ctx " %s " (Ast.s_binop op); gen_value_op ctx e2; )); + | TEnumParameter(e1,_,i) -> + spr ctx "_hx_deref("; + gen_value ctx e1; + spr ctx ")"; + print ctx "->params[%d]" i; | TField (e1,s) -> gen_tfield ctx e e1 (field_name s) | TTypeExpr t -> @@ -1236,6 +1259,8 @@ and gen_expr ctx e = gen_value ctx e; spr ctx ")" ); + | TMeta (_,e) -> + gen_expr ctx e | TReturn eo -> (match eo with | None -> @@ -1255,7 +1280,7 @@ and gen_expr ctx e = | TContinue -> if ctx.in_loop then spr ctx "continue" else print ctx "continue %d" ctx.nested_loops | TBlock [] -> - spr ctx "" + spr ctx "{}" | TBlock el -> let old_l = ctx.inv_locals in let b = save_locals ctx in @@ -1284,9 +1309,7 @@ and gen_expr ctx e = end) in let remaining = ref (List.length el) in let build e = - (match e.eexpr with - | TBlock [] -> () - | _ -> newline ctx); + newline ctx; if (in_block && !remaining = 1) then begin (match e.eexpr with | TIf _ @@ -1294,7 +1317,6 @@ and gen_expr ctx e = | TThrow _ | TWhile _ | TFor _ - | TMatch _ | TTry _ | TBreak | TBlock _ -> @@ -1308,7 +1330,6 @@ and gen_expr ctx e = | TThrow _ | TWhile _ | TFor _ - | TMatch _ | TTry _ | TBlock _ -> () | _ -> @@ -1362,30 +1383,26 @@ and gen_expr ctx e = | _ -> gen_call ctx ec el); | TArrayDecl el -> - spr ctx "new _hx_array(array("; + spr ctx "(new _hx_array(array("; concat ctx ", " (gen_value ctx) el; - spr ctx "))"; + spr ctx ")))"; | TThrow e -> spr ctx "throw new HException("; gen_value ctx e; spr ctx ")"; - | TVars [] -> - () - | TVars vl -> + | TVar (v,eo) -> spr ctx "$"; - concat ctx ("; $") (fun (v,e) -> - let restore = save_locals ctx in - let n = define_local ctx v.v_name in - let restore2 = save_locals ctx in - restore(); - (match e with - | None -> - print ctx "%s = null" (s_ident_local n) - | Some e -> - print ctx "%s = " (s_ident_local n); - gen_value ctx e); - restore2() - ) vl; + let restore = save_locals ctx in + let n = define_local ctx v.v_name in + let restore2 = save_locals ctx in + restore(); + (match eo with + | None -> + print ctx "%s = null" (s_ident_local n) + | Some e -> + print ctx "%s = " (s_ident_local n); + gen_value ctx e); + restore2() | TNew (c,_,el) -> (match c.cl_path, el with | ([], "String"), _ -> @@ -1443,7 +1460,7 @@ and gen_expr ctx e = ); | TField (e1,s) -> spr ctx (Ast.s_unop op); - gen_field_access ctx true e1 (field_name s) + gen_tfield ctx e e1 (field_name s) | _ -> spr ctx (Ast.s_unop op); gen_value ctx e) @@ -1506,6 +1523,9 @@ and gen_expr ctx e = print ctx "while($%s->hasNext()) {" tmp; let bend = open_block ctx in newline ctx; + (* unset loop variable (issue #2900) *) + print ctx "unset($%s)" v; + newline ctx; print ctx "$%s = $%s->next()" v tmp; gen_while_expr ctx e; bend(); @@ -1576,55 +1596,6 @@ and gen_expr ctx e = bend(); newline ctx; spr ctx "}" - | TMatch (e,_,cases,def) -> - let b = save_locals ctx in - let tmp = define_local ctx "__hx__t" in - print ctx "$%s = " tmp; - gen_value ctx e; - newline ctx; - print ctx "switch($%s->index) {" tmp; - let old_loop = ctx.in_loop in - ctx.in_loop <- false; - ctx.nested_loops <- ctx.nested_loops + 1; - newline ctx; - List.iter (fun (cl,params,e) -> - List.iter (fun c -> - print ctx "case %d:" c; - newline ctx; - ) cl; - let b = save_locals ctx in - (match params with - | None | Some [] -> () - | Some l -> - let n = ref (-1) in - let l = List.fold_left (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,v.v_type,!n) :: acc) [] l in - match l with - | [] -> () - | l -> - concat ctx "; " (fun (v,t,n) -> - let v = define_local ctx v in - print ctx "$%s = $%s->params[%d]" v tmp n; - ) l; - newline ctx); - restore_in_block ctx in_block; - gen_expr ctx (mk_block e); - print ctx "break"; - newline ctx; - b() - ) cases; - (match def with - | None -> () - | Some e -> - spr ctx "default:"; - restore_in_block ctx in_block; - gen_expr ctx (mk_block e); - print ctx "break"; - newline ctx; - ); - ctx.nested_loops <- ctx.nested_loops - 1; - ctx.in_loop <- old_loop; - spr ctx "}"; - b() | TSwitch (e,cases,def) -> let old_loop = ctx.in_loop in ctx.in_loop <- false; @@ -1733,6 +1704,7 @@ and canbe_ternary_param e = | TLocal _ | TField (_,FEnum _) | TParenthesis _ + | TMeta _ | TObjectDecl _ | TArrayDecl _ | TCall _ @@ -1760,6 +1732,7 @@ and gen_value ctx e = | TLocal _ | TArray _ | TBinop _ + | TEnumParameter _ | TField _ | TParenthesis _ | TObjectDecl _ @@ -1769,6 +1742,8 @@ and gen_value ctx e = | TNew _ | TFunction _ -> gen_expr ctx e + | TMeta (_,e1) -> + gen_value ctx e1 | TBlock [] -> () | TCast (e, _) @@ -1805,13 +1780,12 @@ and gen_value ctx e = | TBlock _ | TBreak | TContinue - | TVars _ + | TVar _ | TReturn _ | TWhile _ | TThrow _ | TSwitch _ | TFor _ - | TMatch _ | TIf _ | TTry _ -> inline_block ctx e @@ -2023,7 +1997,7 @@ let generate_inline_method ctx c m = let generate_class ctx c = let requires_constructor = ref true in ctx.curclass <- c; - ctx.local_types <- List.map snd c.cl_types; + ctx.local_types <- List.map snd c.cl_params; print ctx "%s %s " (if c.cl_interface then "interface" else "class") (s_path ctx c.cl_path c.cl_extern c.cl_pos); (match c.cl_super with @@ -2166,7 +2140,7 @@ let generate_main ctx c = newline ctx let generate_enum ctx e = - ctx.local_types <- List.map snd e.e_types; + ctx.local_types <- List.map snd e.e_params; let pack = open_block ctx in let ename = s_path ctx e.e_path e.e_extern e.e_pos in @@ -2254,7 +2228,7 @@ let generate com = if static then (n = (prefixed_name false)) else - ((n = (prefixed_name false)) or (n = (prefixed_name true))) + ((n = (prefixed_name false)) || (n = (prefixed_name true))) ) !lc_names in unsupported ("method '" ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name ^ "' already exists here '" ^ (fst lc) ^ "' (different case?)") c.cl_pos with Not_found -> @@ -2333,7 +2307,7 @@ let generate com = newline ctx; gen_expr ctx e); List.iter (generate_static_field_assign ctx c.cl_path) c.cl_ordered_statics; - if c.cl_path = (["php"], "Boot") & com.debug then begin + if c.cl_path = (["php"], "Boot") && com.debug then begin newline ctx; print ctx "$%s = new _hx_array(array())" ctx.stack.Codegen.stack_var; newline ctx; diff --git a/genpy.ml b/genpy.ml new file mode 100644 index 0000000000000000000000000000000000000000..f9d7c85bf16a9d9d958efc0e0701faf7118a6b5a --- /dev/null +++ b/genpy.ml @@ -0,0 +1,2411 @@ +(* + * Copyright (C)2005-2014 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. + *) + +open Ast +open Type +open Common + +module Utils = struct + let class_of_module_type mt = match mt with + | TClassDecl c -> c + | _ -> failwith ("Not a class: " ^ (s_type_path (t_infos mt).mt_path)) + + let find_type com path = + try + List.find (fun mt -> match mt with + | TAbstractDecl _ -> false + | _ -> (t_infos mt).mt_path = path + ) com.types + with Not_found -> + error (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 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 + + let mk_static_call c cf el p = + let ef = mk_static_field c cf p in + let tr = match follow ef.etype with + | TFun(args,tr) -> tr + | _ -> assert false + in + mk (TCall(ef,el)) tr p + + let resolve_static_field c n = + try + PMap.find n c.cl_statics + with Not_found -> + failwith (Printf.sprintf "Class %s has no field %s" (s_type_path c.cl_path) n) + + let mk_static_field_2 c n p = + mk_static_field c (resolve_static_field c n) p + + let mk_static_call_2 c n el p = + mk_static_call c (resolve_static_field c n) el p +end + +module KeywordHandler = struct + let kwds = + let h = Hashtbl.create 0 in + List.iter (fun s -> Hashtbl.add h s ()) [ + "and"; "as"; "assert"; "break"; "class"; "continue"; "def"; "del"; "elif"; "else"; "except"; "exec"; "finally"; "for"; + "from"; "global"; "if"; "import"; "in"; "is"; "lambda"; "not"; "or"; "pass"; " raise"; "return"; "try"; "while"; + "with"; "yield"; "None"; "True"; "False"; + ]; + h + + let kwds2 = + let h = Hashtbl.create 0 in + List.iter (fun s -> Hashtbl.add h s ()) [ + "len"; "int"; "float"; "list"; "bool"; "str"; "isinstance"; "print"; "min"; "max"; + "hasattr"; "getattr"; "setattr"; "delattr"; "callable"; "type"; "ord"; "chr"; "iter"; "map"; "filter"; + "tuple"; "dict"; "set"; "bytes"; "bytearray" + ]; + h + + let handle_keywords s = + let l = String.length s in + if Hashtbl.mem kwds s then + "_hx_" ^ s + (* + handle special __ underscore behaviour (creates private fields for objects) for fields but only if the field doesn't + end with at least one underscores like __iter__ because these are special fields + *) + else if l > 2 && String.sub s 0 2 = "__" && String.sub s (l - 1) 1 <> "_" then + "_hx_" ^ s + else s + + let check_var_declaration v = + if Hashtbl.mem kwds2 v.v_name then v.v_name <- "_hx_" ^ v.v_name +end + +module Transformer = struct + type adjusted_expr = { + a_expr : texpr; + a_blocks : texpr list; + a_next_id : unit -> string; + a_is_value : bool; + } + + let como = ref None + let t_bool = ref t_dynamic + let t_void = ref t_dynamic + let t_string = ref t_dynamic + let t_int = ref t_dynamic + let c_reflect = ref (fun () -> null_class) + + let init com = + como := Some com; + t_bool := com.basic.tbool; + t_void := com.basic.tvoid; + t_string := com.basic.tstring; + t_int := com.basic.tint; + c_reflect := fun () -> Utils.class_of_module_type (Utils.find_type com ([],"Reflect")) + + and debug_expr e = + let s_type = Type.s_type (print_context()) in + let s = Type.s_expr_pretty "\t" s_type e in + Printf.printf "%s\n" s + + and debug_expr_with_type e = + let s_type = Type.s_type (print_context()) in + let es = Type.s_expr_pretty "\t" s_type e in + let t = s_type e.etype in + Printf.printf "%s : %s\n" es t + + and debug_type t = + let s_type = Type.s_type (print_context()) in + let t = s_type t in + Printf.printf "%s\n" t + + let new_counter () = + let n = ref (-1) in + (fun () -> + incr n; + Printf.sprintf "_hx_local_%i" !n + ) + + let to_expr ae = + match ae.a_blocks with + | [] -> + ae.a_expr + | el -> + match ae.a_expr.eexpr with + | TBlock el2 -> + { ae.a_expr with eexpr = TBlock (el @ el2) } + | _ -> + { ae.a_expr with eexpr = TBlock (el @ [ae.a_expr])} + + let lift_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) e = + let next_id = match next_id with + | None -> + new_counter() + | Some f -> + f + in + { + a_expr = e; + a_blocks = blocks; + a_next_id = next_id; + a_is_value = is_value + } + + let lift_expr1 is_value next_id blocks e = + lift_expr ~is_value:is_value ~next_id:(Some next_id) ~blocks:blocks e + + let to_tvar ?(capture = false) n t = + alloc_var n t + (* { v_name = n; v_type = t; v_id = 0; v_capture = capture; v_extra = None; v_meta = [] } *) + + let create_non_local n pos = + let s = "nonlocal " ^ (KeywordHandler.handle_keywords n) in + (* TODO: this is a hack... *) + let id = mk (TLocal (to_tvar "python_Syntax._pythonCode" t_dynamic ) ) !t_void pos in + let id2 = mk (TLocal( to_tvar s t_dynamic )) !t_void pos in + mk (TCall(id, [id2])) t_dynamic pos + + let to_tlocal_expr ?(capture = false) n t p = + mk (TLocal (to_tvar ~capture:capture n t)) t p + + let check_unification e t = match follow e.etype,follow t with + | TAnon an1, TAnon an2 -> + PMap.iter (fun s cf -> + if not (PMap.mem s an1.a_fields) then an1.a_fields <- PMap.add s cf an1.a_fields + ) an2.a_fields; + e + | _ -> + e + + let dynamic_field_read e s = + Utils.mk_static_call_2 ((!c_reflect)()) "field" [e;mk (TConst (TString s)) !t_string e.epos] e.epos + + let dynamic_field_write e1 s e2 = + Utils.mk_static_call_2 ((!c_reflect)()) "setField" [e1;mk (TConst (TString s)) !t_string e1.epos;e2] e1.epos + + let dynamic_field_read_write next_id e1 s op e2 = + let id = next_id() in + let temp_var = to_tvar id e1.etype in + let temp_var_def = mk (TVar(temp_var,Some e1)) e1.etype e1.epos in + let temp_local = mk (TLocal temp_var) e1.etype e1.epos in + let e_field = dynamic_field_read temp_local s in + let e_op = mk (TBinop(op,e_field,e2)) e_field.etype e_field.epos in + let e_set_field = dynamic_field_write temp_local s e_op in + mk (TBlock [ + temp_var_def; + e_set_field; + ]) e_set_field.etype e_set_field.epos + + let add_non_locals_to_func e = match e.eexpr with + | TFunction tf -> + let cur = ref PMap.empty in + let save () = + let prev = !cur in + (fun () -> + cur := prev + ) + in + let declare v = + cur := PMap.add v.v_id v !cur; + in + List.iter (fun (v,_) -> declare v) tf.tf_args; + let non_locals = Hashtbl.create 0 in + let rec it e = match e.eexpr with + | TVar(v,e1) -> + begin match e1 with + | Some e -> + maybe_continue e + | None -> + () + end; + declare v; + | TTry(e1,catches) -> + it e1; + List.iter (fun (v,e) -> + let restore = save() in + declare v; + it e; + restore() + ) catches; + | TBinop( (OpAssign | OpAssignOp(_)), { eexpr = TLocal v }, e2) -> + if not (PMap.mem v.v_id !cur) then + Hashtbl.add non_locals v.v_id v; + maybe_continue e2; + | TFunction _ -> + () + | _ -> + Type.iter it e + and maybe_continue e = match e.eexpr with + | TFunction _ -> + () + | _ -> + it e + in + it tf.tf_expr; + let el = Hashtbl.fold (fun k v acc -> + (create_non_local v.v_name e.epos) :: acc + ) non_locals [] in + let el = tf.tf_expr :: el in + let tf = { tf with tf_expr = { tf.tf_expr with eexpr = TBlock(List.rev el)}} in + {e with eexpr = TFunction tf} + | _ -> + assert false + + let rec transform_function tf ae is_value = + let p = tf.tf_expr.epos in + let assigns = List.fold_left (fun acc (v,value) -> match value with + | None | Some TNull -> + acc + | Some ct -> + let a_local = mk (TLocal v) v.v_type p in + let a_null = mk (TConst TNull) v.v_type p in + let a_cmp = mk (TBinop(OpEq,a_local,a_null)) !t_bool p in + let a_value = mk (TConst(ct)) v.v_type p in + let a_assign = mk (TBinop(OpAssign,a_local,a_value)) v.v_type p in + let a_if = mk (TIf(a_cmp,a_assign,None)) !t_void p in + a_if :: acc + ) [] tf.tf_args in + let body = match assigns with + | [] -> + tf.tf_expr + | _ -> + let eb = mk (TBlock (List.rev assigns)) t_dynamic p in + Type.concat eb tf.tf_expr + in + let e1 = to_expr (transform_expr ~next_id:(Some ae.a_next_id) body) in + let fn = mk (TFunction({ + tf_expr = e1; + tf_args = tf.tf_args; + tf_type = tf.tf_type; + })) ae.a_expr.etype p in + let fn = add_non_locals_to_func fn in + if is_value then begin + let new_name = ae.a_next_id() in + let new_var = alloc_var new_name tf.tf_type in + let new_local = mk (TLocal new_var) fn.etype p in + let def = mk (TVar(new_var,Some fn)) fn.etype p in + lift_expr1 false ae.a_next_id [def] new_local + end else + lift_expr fn + + and transform_var_expr ae eo v = + let b,new_expr = match eo with + | None -> + [],None + | Some e1 -> + let f = transform_expr1 true ae.a_next_id [] e1 in + let b = f.a_blocks in + b,Some(f.a_expr) + in + let e = mk (TVar(v,new_expr)) ae.a_expr.etype ae.a_expr.epos in + lift_expr ~next_id:(Some ae.a_next_id) ~blocks:b e + + and transform_expr ?(is_value = false) ?(next_id = None) ?(blocks = []) (e : texpr) : adjusted_expr = + transform1 (lift_expr ~is_value ~next_id ~blocks e) + + and transform_expr1 is_value next_id blocks e = + transform_expr ~is_value ~next_id:(Some next_id) ~blocks e + + and transform_exprs_to_block el tb is_value p next_id = + match el with + | [e] -> + transform_expr ~is_value ~next_id:(Some next_id) e + | _ -> + let size = List.length el in + let res = DynArray.create () in + ExtList.List.iteri (fun i e -> + (* this removes len(x) calls which are reproduced by the inlined return + of Array.push even if the value is not used *) + let is_removable_statement e = (not is_value || i < size-1) && + match e.eexpr with + | TField(_, FInstance({cl_path = [],"list"},_,{ cf_name = "length" })) -> true + | _ -> false + in + if not (is_removable_statement e) then + let ae = transform_expr ~is_value ~next_id:(Some next_id) e in + List.iter (DynArray.add res) ae.a_blocks; + DynArray.add res ae.a_expr + else + () + ) el; + lift_expr (mk (TBlock (DynArray.to_list res)) tb p) + + and transform_switch ae is_value e1 cases edef = + let case_functions = ref [] in + let case_to_if (el,e) eelse = + let val_reversed = List.rev el in + 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 + | [e] -> + mk_eq e + | e :: el -> + List.fold_left (fun eelse e -> mk (TBinop(OpBoolOr,eelse,mk_eq e)) !t_bool (punion eelse.epos e.epos)) (mk_eq e) el + in + let eif = if is_value then begin + let name = ae.a_next_id() in + let func = exprs_to_func [e] name ae in + case_functions := !case_functions @ func.a_blocks; + let call = func.a_expr in + mk (TIf(cond,call,eelse)) ae.a_expr.etype ae.a_expr.epos + end else + mk (TIf(cond,e,eelse)) ae.a_expr.etype e.epos + in + eif + in + let rev_cases = List.rev cases in + let edef = Some (match edef with + | None -> + mk (TBlock []) ae.a_expr.etype ae.a_expr.epos + | Some e -> + e) + in + let res = match rev_cases,edef with + | [],Some edef -> + edef + | [],None -> + (* I don't think that can happen? *) + assert false + | [case],_ -> + case_to_if case edef + | case :: cases,_ -> + List.fold_left (fun acc case -> case_to_if case (Some acc)) (case_to_if case edef) cases + in + let res = if is_value then + mk (TBlock ((List.rev (res :: !case_functions)))) res.etype res.epos + else + res + in + forward_transform res ae + + and transform_string_switch ae is_value e1 cases edef = + let length_map = Hashtbl.create 0 in + List.iter (fun (el,e) -> + List.iter (fun es -> + match es.eexpr with + | TConst (TString s) -> + let l = String.length s in + let sl = try + Hashtbl.find length_map l + with Not_found -> + let sl = ref [] in + Hashtbl.replace length_map l sl; + sl + in + sl := ([es],e) :: !sl; + | _ -> + () + ) el + ) cases; + if Hashtbl.length length_map < 2 then + transform_switch ae is_value e1 cases edef + else + let mk_eq e1 e2 = mk (TBinop(OpEq,e1,e2)) !t_bool (punion e1.epos e2.epos) in + let mk_or e1 e2 = mk (TBinop(OpOr,e1,e2)) !t_bool (punion e1.epos e2.epos) in + let mk_if (el,e) eo = + let eif = List.fold_left (fun eacc e -> mk_or eacc (mk_eq e1 e)) (mk_eq e1 (List.hd el)) (List.tl el) in + mk (TIf(Codegen.mk_parent eif,e,eo)) e.etype e.epos + 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 + ([eint],fs) :: acc + ) length_map [] in + let c_string = match !t_string with TInst(c,_) -> c | _ -> assert false 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 in + let res_local = {ef with eexpr = TLocal res_var} in + let var_expr = {ef with eexpr = TVar(res_var,Some ef)} in + let e = mk (TBlock [ + var_expr; + mk (TSwitch(res_local,cases,edef)) ae.a_expr.etype e1.epos + ]) ae.a_expr.etype e1.epos in + forward_transform e ae + + and transform_op_assign_op ae e1 op one is_value post = + let e1_ = transform_expr e1 ~is_value:true ~next_id:(Some ae.a_next_id) in + let handle_as_local temp_local = + let ex = ae.a_expr in + let res_var = alloc_var (ae.a_next_id()) ex.etype in + let res_local = {ex with eexpr = TLocal res_var} in + let plus = {ex with eexpr = TBinop(op,temp_local,one)} in + let var_expr = {ex with eexpr = TVar(res_var,Some temp_local)} in + let assign_expr = {ex with eexpr = TBinop(OpAssign,e1_.a_expr,plus)} in + let blocks = if post then + [var_expr;assign_expr;res_local] + else + [assign_expr;temp_local] + in + (* TODO: block is ignored in the else case? *) + let block = e1_.a_blocks @ blocks in + if is_value then begin + let f = exprs_to_func block (ae.a_next_id()) ae in + lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks + end else begin + let block = e1_.a_blocks @ [assign_expr] in + transform_exprs_to_block block ex.etype false ex.epos ae.a_next_id + end + in + match e1_.a_expr.eexpr with + | TArray({eexpr = TLocal _},{eexpr = TLocal _}) + | TField({eexpr = TLocal _},_) + | TLocal _ -> + handle_as_local e1_.a_expr + | TArray(e1,e2) -> + let id = ae.a_next_id() in + let temp_var_l = alloc_var id e1.etype in + let temp_local_l = {e1 with eexpr = TLocal temp_var_l} in + let temp_var_l = {e1 with eexpr = TVar(temp_var_l,Some e1)} in + + let id = ae.a_next_id() in + let temp_var_r = alloc_var id e2.etype in + let temp_local_r = {e2 with eexpr = TLocal temp_var_r} in + let temp_var_r = {e2 with eexpr = TVar(temp_var_r,Some e2)} in + + let id = ae.a_next_id() in + let temp_var = alloc_var id e1_.a_expr.etype in + let temp_local = {e1_.a_expr with eexpr = TLocal temp_var} in + let temp_var_expr = {e1_.a_expr with eexpr = TArray(temp_local_l,temp_local_r)} in + let temp_var = {e1_.a_expr with eexpr = TVar(temp_var,Some temp_var_expr)} in + + let plus = {ae.a_expr with eexpr = TBinop(op,temp_local,one)} in + let assign_expr = {ae.a_expr with eexpr = TBinop(OpAssign,temp_var_expr,plus)} in + let block = e1_.a_blocks @ [temp_var_l;temp_var_r;temp_var;assign_expr;if post then temp_local else temp_var_expr] in + if is_value then begin + let f = exprs_to_func block (ae.a_next_id()) ae in + lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks + end else + transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id + | TField(e1,fa) -> + let temp_var_l = alloc_var (ae.a_next_id()) e1.etype in + let temp_local_l = {e1 with eexpr = TLocal temp_var_l} in + let temp_var_l = {e1 with eexpr = TVar(temp_var_l,Some e1)} in + + let temp_var = alloc_var (ae.a_next_id()) e1_.a_expr.etype in + let temp_local = {e1_.a_expr with eexpr = TLocal temp_var} in + let temp_var_expr = {e1_.a_expr with eexpr = TField(temp_local_l,fa)} in + let temp_var = {e1_.a_expr with eexpr = TVar(temp_var,Some temp_var_expr)} in + + let plus = {ae.a_expr with eexpr = TBinop(op,temp_local,one)} in + let assign_expr = {ae.a_expr with eexpr = TBinop(OpAssign,temp_var_expr,plus)} in + let block = e1_.a_blocks @ [temp_var_l;temp_var;assign_expr;if post then temp_local else temp_var_expr] in + if is_value then begin + let f = exprs_to_func block (ae.a_next_id()) ae in + lift_expr f.a_expr ~is_value:true ~next_id:(Some ae.a_next_id) ~blocks:f.a_blocks + end else + 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 + + and var_to_treturn_expr ?(capture = false) n t p = + let x = mk (TLocal (to_tvar ~capture:capture n t)) t p in + mk (TReturn (Some x)) t p + + and exprs_to_func exprs name base = + let convert_return_expr (expr:texpr) = + match expr.eexpr with + | TWhile(_,_,_) -> + let ret = { expr with eexpr = TReturn (None) } in + [expr; ret] + | TFunction(f) -> + let ret = var_to_treturn_expr name f.tf_type f.tf_expr.epos in + [expr;ret] + | TBinop(OpAssign, l, r) -> + let r = { l with eexpr = TReturn(Some l) } in + [expr; r] + | x -> + let ret_expr = { expr with eexpr = TReturn( Some(expr) )} in + [ret_expr] + in + let def = + (let ex = match exprs with + | [] -> assert false + | [x] -> + (let exs = convert_return_expr x in + match exs with + | [] -> assert false + | [x] -> x + | x -> + match List.rev x with + | x::xs -> + mk (TBlock exs) x.etype base.a_expr.epos + | _ -> assert false) + + | x -> + match List.rev x with + | x::xs -> + (let ret = x in + let tail = List.rev xs in + let block = tail @ (convert_return_expr ret) in + match List.rev block with + | x::_ -> + mk (TBlock block) x.etype base.a_expr.epos + | _ -> assert false) + | _ -> assert false + in + let f1 = { tf_args = []; tf_type = TFun([],ex.etype); tf_expr = ex} in + let fexpr = mk (TFunction f1) ex.etype ex.epos in + let fvar = to_tvar name fexpr.etype in + let f = add_non_locals_to_func fexpr in + let assign = { ex with eexpr = TVar(fvar, Some(f))} in + let call_expr = (mk (TLocal fvar) fexpr.etype ex.epos ) in + let substitute = mk (TCall(call_expr, [])) ex.etype ex.epos in + lift_expr ~blocks:[assign] substitute) + in + match exprs with + | [{ eexpr = TFunction({ tf_args = []} as f) } as x] -> + let l = to_tlocal_expr name f.tf_type f.tf_expr.epos in + let substitute = mk (TCall(l, [])) f.tf_type f.tf_expr.epos in + lift_expr ~blocks:[x] substitute + | _ -> def + + and transform_call is_value e params ae = + let trans is_value blocks e = transform_expr1 is_value ae.a_next_id blocks e in + let trans1 e params = + let e = trans true [] e in + let blocks = e.a_blocks @ (List.flatten (List.map (fun (p) -> p.a_blocks) params)) in + let params = List.map (fun (p) -> p.a_expr) params in + let e = { ae.a_expr with eexpr = TCall(e.a_expr, params) } in + lift_expr ~blocks:blocks e + in + match e, params with + (* the foreach block should not be handled as a value *) + | ({ eexpr = TField(_, FStatic({cl_path = ["python";],"Syntax"},{ cf_name = "_foreach" }))} as e, [e1;e2;e3]) -> + trans1 e [trans true [] e1; trans true [] e2; trans false [] e3] + | (e, params) -> + trans1 e (List.map (trans true []) params) + + + and transform1 ae : adjusted_expr = + + let trans is_value blocks e = transform_expr1 is_value ae.a_next_id blocks e in + let lift is_value blocks e = lift_expr1 is_value ae.a_next_id blocks e in + let a_expr = ae.a_expr in + match ae.a_is_value,ae.a_expr.eexpr with + | (is_value,TBlock [x]) -> + trans is_value [] x + | (false,TBlock []) -> + lift_expr a_expr + | (true,TBlock []) -> + lift_expr (mk (TConst TNull) ae.a_expr.etype ae.a_expr.epos) + | (false,TBlock el) -> + transform_exprs_to_block el ae.a_expr.etype false ae.a_expr.epos ae.a_next_id + | (true,TBlock el) -> + let name = ae.a_next_id() in + let block,tr = match List.rev el with + | e :: el -> + List.rev ((mk (TReturn (Some e)) t_dynamic e.epos) :: el),e.etype + | [] -> + assert false + in + let my_block = transform_exprs_to_block block tr false ae.a_expr.epos ae.a_next_id in + let fn = mk (TFunction { + tf_args = []; + tf_type = tr; + tf_expr = my_block.a_expr; + }) ae.a_expr.etype ae.a_expr.epos in + let t_var = alloc_var name ae.a_expr.etype in + let f = add_non_locals_to_func fn in + let fn_assign = mk (TVar (t_var,Some f)) ae.a_expr.etype ae.a_expr.epos in + let ev = mk (TLocal t_var) ae.a_expr.etype ae.a_expr.epos in + let substitute = mk (TCall(ev,[])) ae.a_expr.etype ae.a_expr.epos in + lift_expr ~blocks:[fn_assign] substitute + | (is_value,TFunction(f)) -> + transform_function f ae is_value + | (_,TVar(v,None)) -> + + transform_var_expr ae None v + + | (false, TVar(v,Some({ eexpr = TUnop((Increment | Decrement as unop),post_fix,({eexpr = TLocal _ | TField({eexpr = TConst TThis},_)} as ve))} as e1))) -> + let one = {e1 with eexpr = TConst (TInt (Int32.of_int 1))} in + let op = if unop = Increment then OpAdd else OpSub in + let inc = {e1 with eexpr = TBinop(op,ve,one)} in + let inc_assign = {e1 with eexpr = TBinop(OpAssign,ve,inc)} in + let var_assign = {e1 with eexpr = TVar(v,Some ve)} in + if post_fix = Postfix then + lift true [var_assign] inc_assign + else + lift true [inc_assign] var_assign + | (_,TVar(v,eo)) -> + transform_var_expr ae eo v + | (_,TFor(v,e1,e2)) -> + let a1 = trans true [] e1 in + let a2 = to_expr (trans false [] e2) in + + let name = (ae.a_next_id ()) in + let t_var = alloc_var name e1.etype in + + let mk_local v p = { eexpr = TLocal v; etype = v.v_type; epos = p } in + + let ev = mk_local t_var e1.epos in + let ehasnext = mk (TField(ev,quick_field e1.etype "hasNext")) (tfun [] (!t_bool) ) e1.epos in + let ehasnext = mk (TCall(ehasnext,[])) ehasnext.etype ehasnext.epos in + + let enext = mk (TField(ev,quick_field e1.etype "next")) (tfun [] v.v_type) e1.epos in + let enext = mk (TCall(enext,[])) v.v_type e1.epos in + + let var_assign = mk (TVar (v,Some enext)) v.v_type a_expr.epos in + + let ebody = Type.concat var_assign (a2) in + + let var_decl = mk (TVar (t_var,Some a1.a_expr)) (!t_void) e1.epos in + let twhile = mk (TWhile((mk (TParenthesis ehasnext) ehasnext.etype ehasnext.epos),ebody,NormalWhile)) (!t_void) e1.epos in + + let blocks = a1.a_blocks @ [var_decl] in + + lift_expr ~blocks: blocks twhile + | (_,TReturn None) -> + ae + | (_,TReturn (Some ({eexpr = TFunction f} as ef))) -> + let n = ae.a_next_id() in + let e1 = to_expr (trans false [] f.tf_expr) in + let f = mk (TFunction { + tf_args = f.tf_args; + tf_type = f.tf_type; + tf_expr = e1; + }) ef.etype ef.epos in + let f1 = add_non_locals_to_func f in + let var_n = alloc_var n ef.etype in + let f1_assign = mk (TVar(var_n,Some f1)) !t_void f1.epos in + let var_local = mk (TLocal var_n) ef.etype f1.epos in + let er = mk (TReturn (Some var_local)) t_dynamic ae.a_expr.epos in + lift true [f1_assign] er + + | (_,TReturn Some(x)) -> + let x1 = trans true [] x in + (match x1.a_blocks with + | [] -> + lift true [] { ae.a_expr with eexpr = TReturn(Some x1.a_expr) } + | blocks -> + let f = exprs_to_func (blocks @ [x1.a_expr]) (ae.a_next_id()) ae in + lift true f.a_blocks {a_expr with eexpr = TReturn (Some f.a_expr)}) + | (_, TParenthesis(e1)) -> + let e1 = trans true [] e1 in + let p = { ae.a_expr with eexpr = TParenthesis(e1.a_expr)} in + lift true e1.a_blocks p + | (_, TEnumParameter(e1,ef,i)) -> + let e1 = trans true [] e1 in + let p = { ae.a_expr with eexpr = TEnumParameter(e1.a_expr,ef,i)} in + lift true e1.a_blocks p + | (true, TIf(econd, eif, eelse)) -> + (let econd1 = trans true [] econd in + let eif1 = trans true [] eif in + let eelse1 = match eelse with + | Some x -> Some(trans true [] x) + | None -> None + in + let blocks = [] in + let eif2, blocks = + match eif1.a_blocks with + | [] -> eif1.a_expr, blocks + | x -> + let regular = + let fname = eif1.a_next_id () in + let f = exprs_to_func (List.append eif1.a_blocks [eif1.a_expr]) fname ae in + f.a_expr, List.append blocks f.a_blocks + in + match eif1.a_blocks with + | [{ eexpr = TVar(_, Some({ eexpr = TFunction(_)}))} as b] -> + eif1.a_expr, List.append blocks [b] + | _ -> regular + in + let eelse2, blocks = + match eelse1 with + | None -> None, blocks + | Some({ a_blocks = []} as x) -> Some(x.a_expr), blocks + | Some({ a_blocks = b} as eelse1) -> + let regular = + let fname = eelse1.a_next_id () in + let f = exprs_to_func (List.append eelse1.a_blocks [eelse1.a_expr]) fname ae in + Some(f.a_expr), List.append blocks f.a_blocks + in + match b with + | [{ eexpr = TVar(_, Some({ eexpr = TFunction(f)}))} as b] -> + Some(eelse1.a_expr), List.append blocks [b] + | _ -> regular + in + let blocks = List.append econd1.a_blocks blocks in + let new_if = { ae.a_expr with eexpr = TIf(econd1.a_expr, eif2, eelse2) } in + match blocks with + | [] -> + let meta = Meta.Custom(":ternaryIf"), [], ae.a_expr.epos in + let ternary = { ae.a_expr with eexpr = TMeta(meta, new_if) } in + lift_expr ~blocks:blocks ternary + | b -> + let f = exprs_to_func (List.append blocks [new_if]) (ae.a_next_id ()) ae in + lift_expr ~blocks:f.a_blocks f.a_expr) + | (false, TIf(econd, eif, eelse)) -> + let econd = trans true [] econd in + let eif = to_expr (trans false [] eif) in + let eelse = match eelse with + | Some(x) -> Some(to_expr (trans false [] x)) + | None -> None + in + let new_if = { ae.a_expr with eexpr = TIf(econd.a_expr, eif, eelse) } in + lift false econd.a_blocks new_if + | (false, TWhile(econd, e1, NormalWhile)) -> + let econd1 = trans true [] econd in + let e11 = to_expr (trans false [] e1) in + let new_while = mk (TWhile(econd1.a_expr,e11,NormalWhile)) a_expr.etype a_expr.epos in + lift false econd1.a_blocks new_while + | (true, TWhile(econd, ebody, NormalWhile)) -> + let econd = trans true [] econd in + let ebody = to_expr (trans false [] ebody) in + let ewhile = { ae.a_expr with eexpr = TWhile(econd.a_expr, ebody, NormalWhile) } in + let eval = { ae.a_expr with eexpr = TConst(TNull) } in + let f = exprs_to_func (List.append econd.a_blocks [ewhile; eval]) (ae.a_next_id ()) ae in + lift true f.a_blocks f.a_expr + | (false, TWhile(econd, ebody, DoWhile)) -> + let not_expr = { econd with eexpr = TUnop(Not, Prefix, econd) } in + let break_expr = mk TBreak !t_void econd.epos in + let if_expr = mk (TIf(not_expr, break_expr, None)) (!t_void) econd.epos in + let new_e = match ebody.eexpr with + | TBlock(exprs) -> { econd with eexpr = TBlock( List.append exprs [if_expr]) } + | _ -> { econd with eexpr = TBlock( List.append [ebody] [if_expr]) } + in + let true_expr = mk (TConst(TBool(true))) econd.etype ae.a_expr.epos in + let new_expr = { ae.a_expr with eexpr = TWhile( true_expr, new_e, NormalWhile) } in + forward_transform new_expr ae + + | (is_value, TSwitch(e, cases, edef)) -> + begin match follow e.etype with + | TInst({cl_path = [],"str"},_) -> + transform_string_switch ae is_value e cases edef + | _ -> + transform_switch ae is_value e cases edef + end + (* anon field access on optional params *) + | (is_value, TField(e,FAnon cf)) when Meta.has Meta.Optional cf.cf_meta -> + let e = dynamic_field_read e cf.cf_name in + transform_expr ~is_value:is_value e + | (is_value, TBinop(OpAssign,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta -> + let e = dynamic_field_write e1 cf.cf_name e2 in + transform_expr ~is_value:is_value e + | (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FAnon cf)},e2)) when Meta.has Meta.Optional cf.cf_meta -> + let e = dynamic_field_read_write ae.a_next_id e1 cf.cf_name op e2 in + transform_expr ~is_value:is_value e + (* TODO we need to deal with Increment, Decrement too! + + | (_, TUnop( (Increment | Decrement) as unop, op,{eexpr = TField(e1,FAnon cf)})) when Meta.has Meta.Optional cf.cf_meta -> + let = dynamic_field_read e cf.cf_name in + + let e = dynamic_field_read_write_unop ae.a_next_id e1 cf.cf_name unop op in + Printf.printf "dyn read write\n"; + transform_expr e + *) + (* + anon field access with non optional members like iterator, length, split must be handled too, we need to Reflect on them too when it's a runtime method + *) + | (is_value, TUnop( (Increment | Decrement) as unop, op, e)) -> + let one = { ae.a_expr with eexpr = TConst(TInt(Int32.of_int(1)))} in + let is_postfix = match op with + | Postfix -> true + | Prefix -> false in + let op = match unop with + | Increment -> OpAdd + | Decrement -> OpSub + | _ -> assert false in + transform_op_assign_op ae e op one is_value is_postfix + | (_, TUnop(op, Prefix, e)) -> + let e1 = trans true [] e in + let r = { a_expr with eexpr = TUnop(op, Prefix, e1.a_expr) } in + lift_expr ~blocks:e1.a_blocks r + + | (is_value, TField(e,FDynamic s)) -> + let e = dynamic_field_read e s in + transform_expr ~is_value:is_value e + | (is_value, TBinop(OpAssign,{eexpr = TField(e1,FDynamic s)},e2)) -> + let e = dynamic_field_write e1 s e2 in + transform_expr ~is_value:is_value e + | (is_value, TBinop(OpAssignOp op,{eexpr = TField(e1,FDynamic s)},e2)) -> + let e = dynamic_field_read_write ae.a_next_id e1 s op e2 in + transform_expr ~is_value:is_value e + | (is_value, TField(e1, FClosure(Some ({cl_path = [],("str" | "list")},_),cf))) -> + let e = dynamic_field_read e1 cf.cf_name in + transform_expr ~is_value:is_value e + | (is_value, TBinop(OpAssign, left, right))-> + (let left = trans true [] left in + let right = trans true [] right in + let r = { a_expr with eexpr = TBinop(OpAssign, left.a_expr, right.a_expr)} in + if is_value then + (let blocks = List.concat [left.a_blocks; right.a_blocks; [r]] in + let f = exprs_to_func blocks (ae.a_next_id ()) ae in + lift true f.a_blocks f.a_expr) + else + lift false (List.append left.a_blocks right.a_blocks) r) + | (is_value, TBinop(OpAssignOp(x), left, right)) -> + let right = trans true [] right in + let v = right.a_expr in + let res = transform_op_assign_op ae left x v is_value false in + lift true (List.append right.a_blocks res.a_blocks) res.a_expr + | (_, TBinop(op, left, right))-> + (let left = trans true [] left in + let right = trans true [] right in + let r = { a_expr with eexpr = TBinop(op, left.a_expr, right.a_expr)} in + lift false (List.append left.a_blocks right.a_blocks) r) + + | (true, TThrow(x)) -> + let block = TBlock([a_expr; { a_expr with eexpr = TConst(TNull) }]) in + let r = { a_expr with eexpr = block } in + forward_transform r ae + | (false, TThrow(x)) -> + let x = trans true [] x in + let r = { a_expr with eexpr = TThrow(x.a_expr)} in + lift false x.a_blocks r + | (_, TNew(c, tp, params)) -> + let params = List.map (trans true []) params in + let blocks = List.flatten (List.map (fun (p) -> p.a_blocks) params) in + let params = List.map (fun (p) -> p.a_expr) params in + let e = { a_expr with eexpr = TNew(c, tp, params) } in + lift false blocks e + | (is_value, TCall(e,params)) -> + transform_call is_value e params ae + | (_, TArray(e1, e2)) -> + let e1 = trans true [] e1 in + let e2 = trans true [] e2 in + let r = { a_expr with eexpr = TArray(e1.a_expr, e2.a_expr)} in + let blocks = List.append e1.a_blocks e2.a_blocks in + lift_expr ~blocks:blocks r + | (false, TTry(etry, catches)) -> + let etry = trans false [] etry in + let catches = List.map (fun(v,e) -> v, trans false [] e) catches in + let blocks = List.flatten (List.map (fun (_,e) -> e.a_blocks) catches) in + let catches = List.map (fun(v,e) -> v, e.a_expr) catches in + let r = { a_expr with eexpr = TTry(etry.a_expr, catches)} in + let blocks = List.append etry.a_blocks blocks in + lift false blocks r + | (true, TTry(etry, catches)) -> + + let id = ae.a_next_id () in + let temp_var = to_tvar id a_expr.etype in + let temp_var_def = { a_expr with eexpr = TVar(temp_var, None) } in + let temp_local = { a_expr with eexpr = TLocal(temp_var)} in + let mk_temp_assign right = { a_expr with eexpr = TBinop(OpAssign, temp_local, right)} in + let etry = mk_temp_assign etry in + let catches = List.map (fun (v,e)-> v, mk_temp_assign e) catches in + let new_try = { a_expr with eexpr = TTry(etry, catches)} in + let block = [temp_var_def; new_try; temp_local] in + let new_block = { a_expr with eexpr = TBlock(block)} in + forward_transform new_block ae + | (_, TObjectDecl(fields)) -> + let fields = List.map (fun (name,ex) -> name, trans true [] ex) fields in + let blocks = List.flatten (List.map (fun (_,ex) -> ex.a_blocks) fields) in + let fields = List.map (fun (name,ex) -> name, ex.a_expr) fields in + let r = { a_expr with eexpr = (TObjectDecl(fields) )} in + lift_expr ~blocks r + | (_, TArrayDecl(values)) -> + let values = List.map (trans true []) values in + let blocks = List.flatten (List.map (fun (v) -> v.a_blocks) values) in + let exprs = List.map (fun (v) -> v.a_expr) values in + let r = { a_expr with eexpr = TArrayDecl exprs } in + lift_expr ~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 + transform_expr ~is_value:is_value e + | (is_value, TCast(e,None)) -> + let e = trans is_value [] e in + let r = { a_expr with eexpr = TCast(e.a_expr, None)} in + lift_expr ~blocks:e.a_blocks r + | (_, TField(e,f)) -> + let e = trans true [] e in + let r = { a_expr with eexpr = TField(e.a_expr, f) } in + lift_expr ~blocks:e.a_blocks r + | (is_value, TMeta(m, e)) -> + let e = trans is_value [] e in + let r = { a_expr with eexpr = TMeta(m, e.a_expr); etype = e.a_expr.etype } in + lift_expr ~blocks:e.a_blocks r + | ( _, TLocal _ ) -> lift_expr a_expr + + | ( _, TConst _ ) -> lift_expr a_expr + | ( _, TTypeExpr _ ) -> lift_expr a_expr + | ( _, TUnop _ ) -> assert false + | ( 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 + lift_expr ~is_value:true ~blocks:f.a_blocks f.a_expr + + | ( _, TBreak ) | ( _, TContinue ) -> + lift_expr a_expr + + and transform e = + to_expr (transform1 (lift_expr e)) + + and forward_transform e base = + transform1 (lift_expr1 base.a_is_value base.a_next_id base.a_blocks e) + + let transform_to_value e = + to_expr (transform1 (lift_expr e ~is_value:true)) + +end + +module Printer = struct + + type print_context = { + pc_indent : string; + pc_next_anon_func : unit -> string; + pc_debug : bool; + pc_com : Common.context; + } + + let has_feature pctx = Common.has_feature pctx.pc_com + + let add_feature pctx = Common.add_feature pctx.pc_com + + let create_context = + let n = ref (-1) in + (fun indent com debug -> { + pc_indent = indent; + pc_next_anon_func = (fun () -> incr n; Printf.sprintf "anon_%i" !n); + pc_debug = debug; + pc_com = com; + } + ) + + let tabs = ref "" + + let opt o f s = match o with + | None -> "" + | Some v -> s ^ (f v) + + (* TODO: both of these are crazy *) + + let is_type p t = + (fun r -> + let x = t_infos r in + (String.concat "." (fst x.mt_path)) = p && (snd x.mt_path) = t + ) + + let is_type1 p s = + (fun t -> match follow t with + | TInst(c,_) -> (is_type p s)(TClassDecl c) + | TAbstract(a,_) -> (is_type p s)(TAbstractDecl a) + | TEnum(en,_) -> (is_type p s)(TEnumDecl en) + | _ -> false + ) + + let is_underlying_string t = match follow t with + | TAbstract(a,tl) -> (is_type1 "" "str")(Abstract.get_underlying_type a tl) + | _ -> false + let is_underlying_array t = match follow t with + | TAbstract(a,tl) -> (is_type1 "" "list")(Abstract.get_underlying_type a tl) + | _ -> false + + let rec is_anon_or_dynamic t = match follow t with + | TAbstract(a,tl) -> + is_anon_or_dynamic (Abstract.get_underlying_type a tl) + | TAnon _ | TDynamic _ -> true + | _ -> false + + let handle_keywords s = + KeywordHandler.handle_keywords s + + let print_unop = function + | Increment | Decrement -> assert false + | Not -> "not " + | Neg -> "-"; + | NegBits -> "~" + + let print_binop = function + | OpAdd -> "+" + | OpSub -> "-" + | OpMult -> "*" + | OpDiv -> "/" + | OpAssign -> "=" + | OpEq -> "==" + | OpNotEq -> "!=" + | OpGt -> ">" + | OpGte -> ">=" + | OpLt -> "<" + | OpLte -> "<=" + | OpAnd -> "&" + | OpOr -> "|" + | OpXor -> "^" + | OpBoolAnd -> "and" + | OpBoolOr -> "or" + | OpShl -> "<<" + | OpShr -> ">>" + | OpUShr -> ">>" + | OpMod -> "%" + | OpInterval | OpArrow | OpAssignOp _ -> assert false + + let print_string s = + Printf.sprintf "\"%s\"" (Ast.s_escape s) + + let print_constant = function + | TThis -> "self" + | TNull -> "None" + | TBool(true) -> "True" + | TBool(false) -> "False" + | TString(s) -> print_string s + | TInt(i) -> Int32.to_string i + | TFloat s -> s + | TSuper -> "super" + + let print_base_type tp = + try + begin match Meta.get Meta.Native tp.mt_meta with + | _,[EConst(String s),_],_ -> s + | _ -> raise Not_found + end + with Not_found -> + let pack,name = tp.mt_path in + (String.concat "_" pack) ^ (if pack = [] then name else "_" ^ name) + + let print_module_type mt = print_base_type (t_infos mt) + + let print_metadata (name,_,_) = + Printf.sprintf "@%s" name + + let rec remove_outer_parens e = match e.eexpr with + | TParenthesis(e) -> remove_outer_parens e + | TMeta((Meta.Custom ":ternaryIf",_,_),_) -> e + | TMeta(_,e) -> remove_outer_parens e + | _ -> e + + let print_args args p = + let had_value = ref false in + let had_var_args = ref false in + let had_kw_args = ref false in + let sl = List.map (fun (v,cto) -> + let check_err () = if !had_var_args || !had_kw_args then error "Arguments after KwArgs/VarArgs are not allowed" p in + KeywordHandler.check_var_declaration v; + let name = handle_keywords v.v_name in + match follow v.v_type with + | TAbstract({a_path = ["python"],"KwArgs"},_) -> + if !had_kw_args then error "Arguments after KwArgs are not allowed" p; + had_kw_args := true; + "**" ^ name + | TAbstract({a_path = ["python"],"VarArgs"},_) -> + check_err (); + had_var_args := true; + "*" ^ name + | _ -> + check_err (); + name ^ match cto with + | None when !had_value -> " = None" + | None -> "" + | Some ct -> + had_value := true; + Printf.sprintf " = %s" (print_constant ct) + ) args in + String.concat "," sl + + let rec print_op_assign_right pctx e = + match e.eexpr with + | TIf({eexpr = TParenthesis econd},eif,Some eelse) + | TIf(econd,eif,Some eelse) -> + Printf.sprintf "%s if %s else %s" (print_expr pctx eif) (print_expr pctx econd) (print_expr pctx eelse) + | _ -> + print_expr pctx (remove_outer_parens e) + + and print_var pctx v eo = + match eo with + | Some ({eexpr = TFunction tf} as e) -> + print_function pctx tf (Some v.v_name) e.epos + | _ -> + let s_init = match eo with + | None -> "None" + | Some e -> print_op_assign_right pctx e + in + Printf.sprintf "%s = %s" (handle_keywords v.v_name) s_init + + and print_function pctx tf name p = + let s_name = match name with + | None -> pctx.pc_next_anon_func() + | Some s -> handle_keywords s + in + let s_args = print_args tf.tf_args p in + let s_expr = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} tf.tf_expr in + Printf.sprintf "def %s(%s):\n%s\t%s" s_name s_args pctx.pc_indent s_expr + + and print_tarray_list pctx e1 e2 = + let s1 = (print_expr pctx e1) in + let s2 = (print_expr pctx e2) in + let default = Printf.sprintf "python_internal_ArrayImpl._get(%s, %s)" s1 s2 in + + let handle_index = + match e2.eexpr with + | TConst TInt index -> + if Int32.to_int index >= 0 then + Printf.sprintf "(%s[%s] if %s < len(%s) else None)" s1 s2 s2 s1 + else + "None" + | TLocal _ -> + Printf.sprintf "(%s[%s] if %s >= 0 and %s < len(%s) else None)" s1 s2 s2 s2 s1 + | _ -> + default + in + match e1.eexpr with + | TLocal _ -> handle_index + | TField ({eexpr=(TConst TThis | TLocal _)},_) -> handle_index + | _ -> default + + and is_safe_string pctx x = + let follow_parens e = match e.eexpr with + | TParenthesis e -> e + | _ -> e + in + match (follow_parens x).eexpr with + | TBinop(OpAdd, e1, e2) -> is_safe_string pctx e1 && is_safe_string pctx e2 + | TCall (e1,_) -> + let id = print_expr pctx (follow_parens e1) in + (match id with + | "Std.string" -> true + | _ -> false) + | TConst (TString s) -> true + | _ -> false + + and print_expr pctx e = + let indent = pctx.pc_indent in + let print_expr_indented e = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e in + match e.eexpr with + | TConst ct -> + print_constant ct + | TTypeExpr mt -> + print_module_type mt + | (TLocal v | TParenthesis({ eexpr = (TLocal v) })) -> + handle_keywords v.v_name + | TEnumParameter(e1,_,index) -> + Printf.sprintf "%s.params[%i]" (print_expr pctx e1) index + | TArray(e1,e2) when (is_type1 "" "list")(e1.etype) || is_underlying_array e1.etype -> + print_tarray_list pctx e1 e2 + | TArray({etype = t} as e1,e2) when is_anon_or_dynamic t -> + Printf.sprintf "HxOverrides.arrayGet(%s, %s)" (print_expr pctx e1) (print_expr pctx e2) + | TArray(e1,e2) -> + Printf.sprintf "%s[%s]" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(OpAssign, {eexpr = TArray(e1,e2)}, e3) when (is_type1 "" "list")(e1.etype) || is_underlying_array e1.etype -> + Printf.sprintf "python_internal_ArrayImpl._set(%s, %s, %s)" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3) + | TBinop(OpAssign,{eexpr = TArray({etype = t} as e1,e2)},e3) when is_anon_or_dynamic t -> + Printf.sprintf "HxOverrides.arraySet(%s,%s,%s)" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3) + | TBinop(OpAssign,{eexpr = TArray(e1,e2)},e3) -> + Printf.sprintf "%s[%s] = %s" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx (remove_outer_parens e3) ) + | TBinop(OpAssign,{eexpr = TField(ef1,fa)},e2) -> + Printf.sprintf "%s = %s" (print_field pctx ef1 fa true) (print_op_assign_right pctx e2) + | TBinop(OpAssign,e1,e2) -> + Printf.sprintf "%s = %s" (print_expr pctx e1) (print_expr pctx (remove_outer_parens e2)) + | TBinop(op,e1,({eexpr = TBinop(_,_,_)} as e2)) -> + print_expr pctx { e with eexpr = TBinop(op, e1, { e2 with eexpr = TParenthesis(e2) })} + | TBinop(OpEq,{eexpr = TCall({eexpr = TLocal {v_name = "__typeof__"}},[e1])},e2) -> + begin match e2.eexpr with + | TConst(TString s) -> + begin match s with + | "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 + end + | _ -> + assert false + end + | TBinop(OpEq,e1,({eexpr = TConst TNull} as e2)) -> + Printf.sprintf "(%s is %s)" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(OpNotEq,e1,({eexpr = TConst TNull} as e2)) -> + Printf.sprintf "(%s is not %s)" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(OpEq|OpNotEq as op,e1, e2) -> + let ops = match op with + | OpEq -> "is", "==", "HxOverrides.eq" + | OpNotEq -> "is not", "!=", "not HxOverrides.eq" + | _ -> assert false + in + let third (_,_,x) = x in + let fst (x,_,_) = x in + let snd (_,x,_) = x in + let is_list_or_anon x = begin match x with + | TInst({cl_path = [],("list")},_) -> true + | TAnon _ -> true + | _ -> false + end in + let is_const_byte x = + match x.eexpr with + | TConst TInt x -> + let x = Int32.to_int x in + x >= 0 && x <= 256 + | _ -> false + in + (match follow e1.etype, follow e2.etype with + | TAbstract({a_path = [],("Int")}, _),TAbstract({a_path = [],("Int")}, _) when is_const_byte e2 || is_const_byte e1 -> + Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2) + (* the following optimization causes a problem with polygonal unit tests + see: https://github.com/HaxeFoundation/haxe/issues/2952 + *) + (* Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (fst ops) (print_expr pctx e2) *) + | TInst({cl_path = [],("list")},_), _ -> + Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (fst ops) (print_expr pctx e2) + | TDynamic _, TDynamic _ -> + Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2) + | TDynamic _, x | x, TDynamic _ when is_list_or_anon x -> + Printf.sprintf "%s(%s,%s)" (third ops) (print_expr pctx e1) (print_expr pctx e2) + | _,_ -> Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (snd ops) (print_expr pctx e2)) + | TBinop(OpMod,e1,e2) when (is_type1 "" "Int")(e1.etype) && (is_type1 "" "Int")(e2.etype) -> + (match e1.eexpr with + | TConst(TInt(x)) when (Int32.to_int x) >= 0 -> + (* constant optimization *) + Printf.sprintf "%s %% %s" (print_expr pctx e1) (print_expr pctx e2) + | _ -> + Printf.sprintf "HxOverrides.mod(%s, %s)" (print_expr pctx e1) (print_expr pctx e2)) + | TBinop(OpMod,e1,e2) -> + Printf.sprintf "HxOverrides.modf(%s, %s)" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(OpUShr,e1,e2) -> + Printf.sprintf "HxOverrides.rshift(%s, %s)" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(OpAdd,e1,e2) when (is_type1 "" "str")(e.etype) || is_underlying_string e.etype -> + let rec safe_string ex = + match ex.eexpr, ex.etype with + | e, _ when is_safe_string pctx ex -> print_expr pctx ex + | TBinop(OpAdd, e1, e2), x when (is_type1 "" "str")(x) -> Printf.sprintf "(%s + %s)" (safe_string e1) (safe_string e2) + | (TLocal(_)),x when (is_type1 "" "str")(x) -> + (* + we could add this pattern too, but is it sideeffect free?? + | TField({ eexpr = TLocal(_)},_) + *) + let s = (print_expr pctx ex) in + Printf.sprintf "(\"null\" if %s is None else %s)" s s + | _,x when (is_type1 "" "str")(x) -> Printf.sprintf "HxOverrides.stringOrNull(%s)" (print_expr pctx ex) + | _,_ -> + if has_feature pctx "Std.string" then + Printf.sprintf "Std.string(%s)" (print_expr pctx ex) + else + Printf.sprintf "str(%s)" (print_expr pctx ex) + in + let e1_str = safe_string e1 in + let e2_str = safe_string e2 in + Printf.sprintf "(%s + %s)" e1_str e2_str + | TBinop(OpAdd,e1,e2) when (match follow e.etype with TDynamic _ -> true | _ -> false) -> + Printf.sprintf "python_Boot._add_dynamic(%s,%s)" (print_expr pctx e1) (print_expr pctx e2) + | TBinop(op,e1,e2) -> + Printf.sprintf "(%s %s %s)" (print_expr pctx e1) (print_binop op) (print_expr pctx e2) + | TField(e1,fa) -> + print_field pctx e1 fa false + | TParenthesis e1 -> + Printf.sprintf "(%s)" (print_expr pctx e1) + | TObjectDecl fl -> + let fl2 = ref fl in + begin match follow e.etype with + | TAnon an -> + PMap.iter (fun s cf -> + if not (List.mem_assoc s fl) then fl2 := (s,null cf.cf_type cf.cf_pos) :: !fl2 + ) an.a_fields + | _ -> + () + end; + Printf.sprintf "_hx_AnonObject(%s)" (print_exprs_named pctx ", " !fl2) + | TArrayDecl el -> + Printf.sprintf "[%s]" (print_exprs pctx ", " el) + | TCall(e1,el) -> + print_call pctx e1 el e + | TNew(c,_,el) -> + let id = print_base_type (t_infos (TClassDecl c)) in + Printf.sprintf "%s(%s)" id (print_exprs pctx ", " el) + | TUnop(Not,Prefix,e1) -> + Printf.sprintf "(%s%s)" (print_unop Not) (print_expr pctx e1) + | TUnop(op,Prefix,e1) -> + Printf.sprintf "%s%s" (print_unop op) (print_expr pctx e1) + | TFunction tf -> + print_function pctx tf None e.epos + | TVar (v,eo) -> + KeywordHandler.check_var_declaration v; + print_var pctx v eo + | TBlock [] -> + Printf.sprintf "pass" + | TBlock [{ eexpr = TBlock _} as b] -> + print_expr pctx b + | TBlock el -> + let old = !tabs in + tabs := pctx.pc_indent; + let s = print_block_exprs pctx ("\n" ^ !tabs) pctx.pc_debug el in + tabs := old; + Printf.sprintf "%s" s + | TIf(econd,eif,(Some {eexpr = TIf _} as eelse)) -> + print_if_else pctx econd eif eelse true + | TIf(econd,eif,eelse) -> + print_if_else pctx econd eif eelse false + | TWhile(econd,e1,NormalWhile) -> + Printf.sprintf "while %s:\n%s\t%s" (print_expr pctx (remove_outer_parens econd)) indent (print_expr_indented e1) + | TWhile(econd,e1,DoWhile) -> + error "Currently not supported" e.epos + | TTry(e1,catches) -> + print_try pctx e1 catches + | TReturn eo -> + Printf.sprintf "return%s" (opt eo (print_op_assign_right pctx) " ") + | TBreak -> + "break" + | 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) + | TCast(e1,None) -> + print_expr pctx e1 + | TMeta((Meta.Custom ":ternaryIf",_,_),{eexpr = TIf(econd,eif,Some eelse)}) -> + Printf.sprintf "(%s if %s else %s)" (print_expr pctx eif) (print_expr pctx econd) (print_expr pctx eelse) + | TMeta(_,e1) -> + print_expr pctx e1 + | TSwitch _ | TCast(_, Some _) | TFor _ | TUnop(_,Postfix,_) -> + assert false + + and print_if_else pctx econd eif eelse as_elif = + let econd1 = match econd.eexpr with + | TParenthesis e -> e + | _ -> econd + in + let if_str = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} eif in + let indent = pctx.pc_indent in + let else_str = if as_elif then + opt eelse (print_expr pctx) "el" + else + opt eelse (print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent}) (Printf.sprintf "else:\n%s\t" indent) + in + let else_str = if else_str = "" then "" else "\n" ^ indent ^ else_str in + Printf.sprintf "if %s:\n%s\t%s%s" (print_expr pctx (remove_outer_parens econd1)) indent if_str else_str + + and print_field pctx e1 fa is_assign = + let obj = match e1.eexpr with + | TConst TSuper -> "super()" + | _ -> print_expr pctx e1 + in + let name = field_name fa in + let is_extern = (match fa with + | FInstance(c,_,_) -> c.cl_extern + | FStatic(c,_) -> c.cl_extern + | _ -> false) + in + let do_default () = + Printf.sprintf "%s.%s" obj (if is_extern then name else (handle_keywords name)) + in + let call_override s = + match s with + | "iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift" | "join" | "push" | "map" | "filter" -> true + | _ -> false + in + match fa with + (* we need to get rid of these cases in the transformer, how is this handled in js *) + | FInstance(c,_,{cf_name = "length"}) when (is_type "" "list")(TClassDecl c) -> + Printf.sprintf "len(%s)" (print_expr pctx e1) + | FInstance(c,_,{cf_name = "length"}) when (is_type "" "str")(TClassDecl c) -> + Printf.sprintf "len(%s)" (print_expr pctx e1) + | FStatic(c,{cf_name = "fromCharCode"}) when (is_type "" "str")(TClassDecl c) -> + Printf.sprintf "HxString.fromCharCode" + | FStatic({cl_path = ["python";"internal"],"UBuiltins"},{cf_name = s}) -> + s + | FInstance _ | FStatic _ -> + do_default () + | FAnon cf when is_assign && call_override(name) -> + begin match follow cf.cf_type with + | TFun([],_) -> + Printf.sprintf "python_lib_FuncTools.partial(HxOverrides.%s, %s)" name obj + | _ -> + do_default() + end + | _ -> + do_default() + + and print_try pctx e1 catches = + let has_catch_all = List.exists (fun (v,_) -> match 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) = + KeywordHandler.check_var_declaration v; + 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_type_check t_str = + Printf.sprintf "if isinstance(_hx_e1, %s):\n%s\t%s\t%s" t_str indent assign (print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e) + in + let res = match t with + | "str" -> print_type_check "str" + | "Bool" -> print_type_check "bool" + | "Int" -> print_type_check "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\t%s%s\t%s" indent indent assign (print_expr {pctx with pc_indent = "\t" ^ 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 + in + let indent = pctx.pc_indent in + let print_expr_indented e = print_expr {pctx with pc_indent = "\t" ^ pctx.pc_indent} e in + let try_str = Printf.sprintf "try:\n%s\t%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\t_hx_e1 = _hx_e.val if isinstance(_hx_e, _HxException) else _hx_e\n%s\t" indent indent + else + Printf.sprintf "except Exception as _hx_e:\n%s\t_hx_e1 = _hx_e\n%s\t" indent indent + in + let catch_str = String.concat (Printf.sprintf "\n") (ExtList.List.mapi (fun i catch -> print_catch {pctx with pc_indent = "\t" ^ pctx.pc_indent} i catch) catches) in + let except_end = if not has_catch_all then Printf.sprintf "\n%s\telse:\n%s\t\traise _hx_e" indent indent else "" in + Printf.sprintf "%s%s%s%s" try_str except catch_str except_end + + and print_call2 pctx e1 el = + let id = print_expr pctx e1 in + match id,el with + | "__define_feature__",[_;e] -> + print_expr pctx e + | "super",_ -> + let s_el = (print_call_args pctx e1 el) in + Printf.sprintf "super().__init__(%s)" s_el + | ("python_Syntax._pythonCode"),[({ eexpr = TConst (TString code) } as ecode); {eexpr = TArrayDecl tl}] -> + let exprs = Array.of_list tl in + let i = ref 0 in + let err msg = + let pos = { ecode.epos with pmin = ecode.epos.pmin + !i } in + error msg pos + in + let regex = Str.regexp "[{}]" in + let rec loop m = match m with + | [] -> "" + | Str.Text txt :: tl -> + i := !i + String.length txt; + txt ^ (loop tl) + | Str.Delim a :: Str.Delim b :: tl when a = b -> + i := !i + 2; + a ^ (loop tl) + | Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl -> + (try + let expr = Array.get exprs (int_of_string n) in + let txt = print_expr pctx expr in + i := !i + 2 + String.length n; + txt ^ (loop tl) + with | Failure "int_of_string" -> + err ("Index expected. Got " ^ n) + | Invalid_argument _ -> + err ("Out-of-bounds pythonCode special parameter: " ^ n)) + | Str.Delim x :: _ -> + err ("Unexpected " ^ x) + in + loop (Str.full_split regex code) + | ("python_Syntax._pythonCode"), [e] -> + print_expr pctx e + | "python_Syntax._callNamedUntyped",el -> + let res,fields = match List.rev el with + | {eexpr = TObjectDecl fields} :: el -> + List.rev el,fields + | _ -> + assert false + in + begin match res with + | e1 :: [] -> + Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_params_named pctx ", " fields) + | e1 :: el -> + Printf.sprintf "%s(%s, %s)" (print_expr pctx e1) (print_exprs pctx ", " el) (print_params_named pctx ", " fields) + | [] -> + Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_params_named pctx ", " fields) + end + | "python_Syntax.varArgs",[e1] -> + "*" ^ (print_expr pctx e1) + | "python_Syntax.call" ,e1 :: [{eexpr = TArrayDecl el}]-> + Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_exprs pctx ", " el) + | "python_Syntax.field",[e1;{eexpr = TConst(TString id)}] -> + Printf.sprintf "%s.%s" (print_expr pctx e1) id + | "python_Syntax._tuple", [{eexpr = TArrayDecl el}] -> + (match el with + | [e] -> + Printf.sprintf "(%s,)" (print_expr pctx e) + | _ -> + Printf.sprintf "(%s)" (print_exprs pctx ", " el)) + | "python_Syntax._arrayAccess", e1 :: {eexpr = TArrayDecl el} :: etrail -> + let trailing_colon = match etrail with + | [{eexpr = TConst(TBool(true))}] -> true + | _ -> false + in + Printf.sprintf "%s[%s%s]" (print_expr pctx e1) (print_exprs pctx ":" el) (if trailing_colon then ":" else "") + | "python_Syntax.isIn",[e1;e2] -> + Printf.sprintf "%s in %s" (print_expr pctx e1) (print_expr pctx e2) + | "python_Syntax.delete",[e1] -> + Printf.sprintf "del %s" (print_expr pctx e1) + | "python_Syntax.binop",[e0;{eexpr = TConst(TString id)};e2] -> + Printf.sprintf "(%s %s %s)" (print_expr pctx e0) id (print_expr pctx e2) + | "python_Syntax.assign",[e0;e1] -> + Printf.sprintf "%s = %s" (print_expr pctx e0) (print_expr pctx e1) + | "python_Syntax.arraySet",[e1;e2;e3] -> + Printf.sprintf "%s[%s] = %s" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3) + | "python_Syntax._newInstance", e1 :: [{eexpr = TArrayDecl el}] -> + Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_exprs pctx ", " el) + | "python_Syntax.opPow", [e1;e2] -> + Printf.sprintf "(%s ** %s)" (print_expr pctx e1) (print_expr pctx e2) + | "python_Syntax._foreach",[e1;e2;e3] -> + let pctx = {pctx with pc_indent = "\t" ^ pctx.pc_indent} in + let i = pctx.pc_indent in + Printf.sprintf "for %s in %s:\n%s%s" (print_expr pctx e1) (print_expr pctx e2) i (print_expr pctx e3) + | _,el -> + Printf.sprintf "%s(%s)" id (print_call_args pctx e1 el) + + and print_call pctx e1 el call_expr = + let get_native_fields t = match follow t with + | TAnon(a) -> + let fold f cf acc = + if Meta.has Meta.Native cf.cf_meta then begin + let _, args, mp = Meta.get Meta.Native cf.cf_meta in + match args with + | [( EConst(String s),_)] -> PMap.add f s acc + | _ -> acc + end else acc + in + let mapping = PMap.foldi fold a.a_fields PMap.empty in + mapping + | _ -> PMap.empty + in + let native_fields_str native_fields = + let fold_dict k v acc = + let prefix = if acc = "" then "" else "," in + Printf.sprintf "%s%s\"%s\":\"%s\"" acc prefix (handle_keywords k) v + in + PMap.foldi fold_dict native_fields "" + in + match e1.eexpr, el with + | TLocal { v_name = "`trace" }, [e;infos] -> + if has_feature pctx "haxe.Log.trace" then begin + "haxe_Log.trace(" ^ (print_expr pctx e) ^ "," ^ (print_expr pctx infos) ^ ")" + end else if is_safe_string pctx e then + "print(" ^ (print_expr pctx e) ^ ")" + else + "print(str(" ^ (print_expr pctx e) ^ "))" + | TField(e1,((FAnon {cf_name = (("join" | "push" | "map" | "filter") as s)}) | FDynamic (("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))), [] -> + 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 + in + let native_fields = get_native_fields t in + if PMap.is_empty native_fields then + print_call2 pctx e1 el + else + let s1 = native_fields_str native_fields in + Printf.sprintf "python__KwArgs_KwArgs_Impl_.fromT(HxOverrides.mapKwArgs(%s, {%s}))" (print_expr pctx e2) s1 + | TField(_, (FStatic({cl_path = ["python"; "_KwArgs"], "KwArgs_Impl_"},{ cf_name="toDictHelper" }))), [e2; et] -> + let native_fields = get_native_fields et.etype in + if PMap.is_empty native_fields then + print_call2 pctx e1 el + else + let s1 = native_fields_str native_fields in + Printf.sprintf "python__KwArgs_KwArgs_Impl_.toDictHelper(HxOverrides.reverseMapKwArgs(%s, {%s}), None)" (print_expr pctx e2) s1 + | _,_ -> + print_call2 pctx e1 el + + and print_call_args pctx e1 el = + let print_arg pctx i x = + let e = match x.eexpr, follow x.etype with + | TConst TNull, TAbstract({a_path = ["python"],"KwArgs"},_) -> "{}" + | TConst TNull, TAbstract({a_path = ["python"],"VarArgs"},_) -> "[]" + | _ -> (print_expr pctx x) + in + let prefix = match e1.eexpr, follow x.etype with + (* the should not apply for the instance methods of the abstract itself *) + | TField(_, FStatic({cl_path = ["python"; "_KwArgs"],"KwArgs_Impl_"},f)), _ when i == 0 && Meta.has Meta.Impl f.cf_meta -> "" + | TField(_, FStatic({cl_path = ["python"; "_VarArgs"],"VarArgs_Impl_"},f)), _ when i == 0 && Meta.has Meta.Impl f.cf_meta -> "" + | _, TAbstract({a_path = ["python"],"KwArgs"},_) -> "**" + | _, TAbstract({a_path = ["python"],"VarArgs"},_) -> "*" + | _, _ -> "" + in + prefix ^ e + in + String.concat "," (ExtList.List.mapi (print_arg pctx) el) + + and print_exprs pctx sep el = + String.concat sep (List.map (print_expr pctx) el) + + and last_debug_comment = ref ("") + + and print_block_exprs pctx sep print_debug_comment el = + if print_debug_comment then begin + let el = List.fold_left (fun acc e -> + let line = Lexer.get_error_line e.epos in + let debug_line = (Printf.sprintf "# %s:%i" e.epos.pfile line) in + let res = if (!last_debug_comment) <> debug_line then + (print_expr pctx e) :: debug_line :: acc + else + (print_expr pctx e) :: acc + in + last_debug_comment := debug_line; + res + ) [] el in + String.concat sep (List.rev el) + end else + print_exprs pctx sep el + + and print_exprs_named pctx sep fl = + let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "'%s': %s" (handle_keywords s) (print_expr pctx e)) fl) in + Printf.sprintf "{%s}" args + and print_params_named pctx sep fl = + let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "%s= %s" (handle_keywords s) (print_expr pctx e)) fl) in + Printf.sprintf "%s" args + let handle_keywords s = + KeywordHandler.handle_keywords s +end + +module Generator = struct + type context = { + com : Common.context; + buf : Buffer.t; + packages : (string,int) Hashtbl.t; + mutable static_inits : (unit -> unit) list; + mutable class_inits : (unit -> unit) list; + mutable indent_count : int; + transform_time : float; + print_time : float; + } + + let has_feature ctx = Common.has_feature ctx.com + let add_feature ctx = Common.add_feature ctx.com + + type class_field_infos = { + cfd_fields : string list; + cfd_props : string list; + cfd_methods : string list; + } + + type import_type = + | IModule of string + | IObject of string * string + + let mk_context com = { + com = com; + buf = Buffer.create 16000; + packages = Hashtbl.create 0; + static_inits = []; + class_inits = []; + indent_count = 0; + transform_time = 0.; + print_time = 0.; + } + + (* Transformer interface *) + + let transform_expr e = + (* let e = Codegen.UnificationCallback.run Transformer.check_unification e in *) + Transformer.transform e + + let transform_to_value e = + (* let e = Codegen.UnificationCallback.run Transformer.check_unification e in *) + Transformer.transform_to_value e + + (* Printer interface *) + + let get_path mt = + Printer.print_base_type mt + + let tfunc_str f pctx name p = + Printer.print_function pctx f name p + + let texpr_str e pctx = + Printer.print_expr pctx e + + let handle_keywords s = + Printer.handle_keywords s + + (* Helper *) + + let get_full_name mt = + (* TODO: haxe source is crazy *) + s_type_path mt.mt_path + + let collect_class_field_data cfl = + let fields = DynArray.create () in + let props = DynArray.create () in + let methods = DynArray.create () in + List.iter (fun cf -> + match cf.cf_kind with + | Var({v_read = AccResolve}) -> + () + | Var _ when is_extern_field cf -> + () + | Var({v_read = AccCall}) -> + if Meta.has Meta.IsVar cf.cf_meta then + DynArray.add fields cf.cf_name + else + DynArray.add props cf.cf_name + | Var _ -> + DynArray.add fields cf.cf_name + | _ -> + DynArray.add methods cf.cf_name + ) cfl; + { + cfd_fields = DynArray.to_list fields; + cfd_props = DynArray.to_list props; + cfd_methods = DynArray.to_list methods; + } + + let collect_class_statics_data cfl = + let fields = DynArray.create () in + List.iter (fun cf -> + if not (is_extern_field cf) then + DynArray.add fields cf.cf_name + ) cfl; + DynArray.to_list fields + + let filter_py_metas metas = + List.filter (fun (n,_,_) -> match n with Meta.Custom ":python" -> true | _ -> false) metas + + let get_members_with_init_expr c = + List.filter (fun cf -> match cf.cf_kind with + | Var _ when is_extern_field cf -> false + | Var _ when cf.cf_expr = None -> true + | _ -> false + ) c.cl_ordered_fields + + (* Printing *) + + let spr ctx s = + Buffer.add_string ctx.buf s + + let spr_line ctx s = + Buffer.add_string ctx.buf s; + Buffer.add_string ctx.buf "\n" + + let print ctx = + Printf.kprintf (fun s -> begin + Buffer.add_string ctx.buf s + end) + + let newline ctx = + if not (Buffer.length ctx.buf = 0) then spr ctx "\n" + + + (* Generating functions *) + + let gen_py_metas ctx metas indent = + List.iter (fun (n,el,_) -> + match el with + | [EConst(String s),_] -> + print ctx "%s@%s\n" indent s + | _ -> + assert false + ) metas + + let gen_expr ctx e field indent = + let pctx = Printer.create_context ("\t" ^ indent) ctx.com ctx.com.debug in + let e = match e.eexpr with + | TFunction(f) -> + {e with eexpr = TBlock [e]} + | _ -> + e + in + let expr2 = transform_to_value e in + let name = "_hx_init_" ^ (String.concat "_" (ExtString.String.nsplit field ".")) in + let maybe_split_expr expr2 = match expr2.eexpr with + | TBlock es when es <> [] && field <> "" -> + begin match List.rev es with + | e_last :: el -> + let new_last = {e_last with eexpr = TReturn (Some e_last)} in + let new_block = {expr2 with eexpr = TBlock (List.rev (new_last :: el))} in + let v_name = alloc_var name (tfun [] e_last.etype) in + let f_name = mk (TLocal v_name) v_name.v_type e_last.epos in + let call_f = mk (TCall(f_name,[])) e_last.etype e_last.epos in + Some new_block,call_f + | _ -> + assert false + end + | _ -> + None,expr2 + in + let r = maybe_split_expr expr2 in + match r with + | Some e1,e2 -> + let expr_string_1 = texpr_str e1 pctx in + let expr_string_2 = texpr_str e2 pctx in + print ctx "%sdef %s():\n\t%s" indent name expr_string_1; + newline ctx; + print ctx "%s%s = %s" indent field expr_string_2; + | None,e2 -> + let expr_string_2 = texpr_str e2 pctx in + if field = "" then + spr ctx expr_string_2 + else + print ctx "%s%s = %s" indent field expr_string_2 + + let gen_func_expr ctx e c name metas extra_args indent stat p = + let pctx = Printer.create_context indent ctx.com ctx.com.debug in + let e = match e.eexpr with + | TFunction(f) -> + let args = List.map (fun s -> + alloc_var s t_dynamic,None + ) extra_args in + {e with eexpr = TFunction {f with tf_args = args @ f.tf_args}} + | _ -> + e + in + if stat then begin + newline ctx; + spr ctx indent; + spr ctx "@staticmethod\n" + end; + let expr1 = transform_expr e in + let expr_string = match expr1.eexpr with + | TFunction f -> + tfunc_str f pctx (Some name) p + | _ -> + Printf.sprintf "%s = %s" name (texpr_str expr1 pctx) + in + gen_py_metas ctx metas indent; + spr ctx indent; + spr ctx expr_string + + let gen_class_constructor ctx c cf = + let member_inits = get_members_with_init_expr c in + let py_metas = filter_py_metas cf.cf_meta in + begin match cf.cf_expr with + | Some ({eexpr = TFunction f} as ef) -> + let ethis = mk (TConst TThis) (TInst(c,List.map snd c.cl_params)) cf.cf_pos in + let member_data = List.map (fun cf -> + let ef = mk (TField(ethis,FInstance(c,[],cf))) cf.cf_type cf.cf_pos in (* TODO *) + mk (TBinop(OpAssign,ef,null ef.etype ef.epos)) ef.etype ef.epos + ) member_inits in + let e = concat (mk (TBlock member_data) ctx.com.basic.tvoid cf.cf_pos) f.tf_expr in + let ef = {ef with eexpr = TFunction {f with tf_expr = e}} in + cf.cf_expr <- Some ef; + + newline ctx; + newline ctx; + gen_func_expr ctx ef c "__init__" py_metas ["self"] "\t" false cf.cf_pos + | _ -> + assert false + end + + let gen_class_field ctx c p cf = + let field = handle_keywords cf.cf_name in + begin match cf.cf_expr with + | None -> + ()(* print ctx "\t# var %s" field *) + | Some e -> + newline ctx; + newline ctx; + begin match cf.cf_kind with + | Method _ -> + let py_metas = filter_py_metas cf.cf_meta in + gen_func_expr ctx e c field py_metas ["self"] "\t" false cf.cf_pos; + + | _ -> + gen_expr ctx e (Printf.sprintf "# var %s" field) "\t"; + end + end + + let gen_class_empty_constructor ctx p cfl = + if has_feature ctx "Type.createEmptyInstance" then begin + newline ctx; + newline ctx; + print ctx "\t@staticmethod\n\tdef _hx_empty_init(_hx_o):"; + let found_fields = ref false in + List.iter (fun cf -> match cf.cf_kind with + | Var ({v_read = AccResolve | AccCall}) -> + () + | Var _ -> + found_fields := true; + newline ctx; + print ctx "\t\t_hx_o.%s = None" (handle_keywords cf.cf_name) + | _ -> + () + ) cfl; + if not !found_fields then + spr ctx "\t\tpass" + end else begin + newline ctx + end + + let gen_class_statics ctx c p = + let methods, other = List.partition (fun cf -> + match cf.cf_kind with + | Method _ -> (match cf.cf_expr with Some _ -> true | _ -> false) + | _ -> false + ) c.cl_ordered_statics in + + (* generate non methods *) + let has_empty_static_vars = ref false in + List.iter (fun cf -> + let p = get_path (t_infos (TClassDecl c)) in + let field = handle_keywords cf.cf_name in + match cf.cf_expr with + | None -> + has_empty_static_vars := true; + newline ctx; + print ctx "\t%s = None" field + | Some e -> + (let f = fun () -> + newline ctx; + gen_expr ctx e (Printf.sprintf "%s.%s" p field) ""; + in + ctx.static_inits <- f :: ctx.static_inits) + ) other; + + (* generate static methods *) + let has_static_methods = ref false in + List.iter (fun cf -> + 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 + newline ctx; + gen_func_expr ctx e c field py_metas [] "\t" true cf.cf_pos; + ) methods; + + !has_static_methods || !has_empty_static_vars + + let gen_class_init ctx c = + match c.cl_init with + | None -> + () + | Some e -> + let is_math = c.cl_path = ([], "Math") in + let math_feature = has_feature ctx "Math" in + let f = if is_math && not math_feature then + fun () -> () + else fun () -> + let e = transform_expr e in + newline ctx; + spr ctx (texpr_str e (Printer.create_context "" ctx.com ctx.com.debug)); + in + ctx.class_inits <- f :: ctx.class_inits + + let gen_class ctx c = + if not c.cl_extern then begin + let is_nativegen = Meta.has Meta.NativeGen c.cl_meta in + let mt = (t_infos (TClassDecl c)) in + let p = get_path mt in + let p_name = get_full_name mt in + let x = collect_class_field_data c.cl_ordered_fields in + let p_super = match c.cl_super with + | None -> + None + | Some (csup,_) -> + Some (get_path (t_infos (TClassDecl csup))) + in + let p_interfaces = List.map (fun (c,tl) -> + get_path (t_infos (TClassDecl c)) + ) c.cl_implements in + + newline ctx; + newline ctx; + newline ctx; + print ctx "class %s" p; + (match p_super with Some p -> print ctx "(%s)" p | _ -> ()); + spr ctx ":"; + + let use_pass = ref true in + + if not is_nativegen then begin + if has_feature ctx "python._hx_class_name" then begin + use_pass := false; + print ctx "\n\t_hx_class_name = \"%s\"" p_name + end; + + let print_field names field quote = + if has_feature ctx ("python." ^ field) then try + let q s = if quote then "\"" ^ s ^ "\"" else s in + let s = match names with + | [] when (match c.cl_super with Some _ -> false | _ -> true) -> + (* always overwrite parent's class fields *) + raise Exit + | _ -> + "[" ^ (String.concat ", " (List.map q names)) ^ "]" + in + use_pass := false; + print ctx "\n\t%s = %s" field s + with Exit -> () + in + + print_field x.cfd_fields "_hx_fields" true; + print_field x.cfd_methods "_hx_methods" true; + (* TODO: It seems strange to have a separation for member fields but a plain _hx_statics for static ones *) + print_field (collect_class_statics_data c.cl_ordered_statics) "_hx_statics" true; + print_field (p_interfaces) "_hx_interfaces" false; + + if has_feature ctx "python._hx_super" then (match p_super with + | None -> () + | Some ps -> + use_pass := false; + print ctx "\n\t_hx_super = %s\n" ps + ); + + end; + + begin match c.cl_constructor with + | Some cf -> gen_class_constructor ctx c cf; + | None -> () + end; + List.iter (fun cf -> gen_class_field ctx c p cf) c.cl_ordered_fields; + + let has_inner_static = gen_class_statics ctx c p in + + let has_empty_constructor = match ((Meta.has Meta.NativeGen c.cl_meta) || c.cl_interface), c.cl_ordered_fields with + | true,_ + | _, [] -> + false + | _ -> + gen_class_empty_constructor ctx p c.cl_ordered_fields; + has_feature ctx "Type.createEmptyInstance" + in + + let use_pass = !use_pass && (not has_inner_static) && (not has_empty_constructor) && match x.cfd_methods with + | [] -> c.cl_constructor = None + | _ -> c.cl_interface + in + if use_pass then spr ctx "\n\tpass"; + + if not is_nativegen then begin + if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p; + if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p; + end + end; + gen_class_init ctx c + + let gen_enum_metadata ctx en p = + let meta = Codegen.build_metadata ctx.com (TEnumDecl en) in + match meta with + | None -> + () + | Some e -> + newline ctx; + print ctx "%s.__meta__ = " p; + gen_expr ctx e "" "" + + let gen_enum ctx en = + let mt = (t_infos (TEnumDecl en)) in + let p = get_path mt in + let p_name = get_full_name mt in + + let enum_constructs = PMap.foldi (fun k ef acc -> ef :: acc) en.e_constrs [] in + let enum_constructs = List.sort (fun a b -> if a.ef_index < b.ef_index then -1 else if a.ef_index > b.ef_index then 1 else 0) enum_constructs in + + newline ctx; + newline ctx; + print ctx "class %s(Enum):" p; + + let use_pass = ref true in + + if has_feature ctx "python._hx_class_name" then begin + use_pass := false; + print ctx "\n\t_hx_class_name = \"%s\"" p_name + end; + if has_feature ctx "python._hx_constructs" then begin + let fix = match enum_constructs with [] -> "" | _ -> "\"" in + let enum_constructs_str = fix ^ (String.concat ("\", \"") (List.map (fun ef -> ef.ef_name) enum_constructs)) ^ fix in + use_pass := false; + print ctx "\n\t_hx_constructs = [%s]" enum_constructs_str; + end; + + let const_constructors,param_constructors = List.partition (fun ef -> + match follow ef.ef_type with + | TFun(_,_) -> false + | _ -> true + ) enum_constructs in + + List.iter (fun ef -> + match follow ef.ef_type with + | TFun(args, _) -> + let print_args args = + let had_optional = ref false in + let sl = List.map (fun (n,o,_) -> + let name = handle_keywords n in + let arg_value = if !had_optional then + "= None" + else if o then begin + had_optional := true; + " = None" + end else + "" + in + Printf.sprintf "%s%s" name arg_value + ) args in + String.concat "," sl + in + let f = handle_keywords ef.ef_name in + let param_str = print_args args in + let args_str = String.concat "," (List.map (fun (n,_,_) -> handle_keywords n) args) in + newline ctx; + newline ctx; + print ctx "\t@staticmethod\n\tdef %s(%s):\n" f param_str; + print ctx "\t\treturn %s(\"%s\", %i, [%s])" p ef.ef_name ef.ef_index args_str; + use_pass := false; + | _ -> assert false + ) param_constructors; + + if !use_pass then spr ctx "\n\tpass"; + + List.iter (fun ef -> + (* TODO: haxe source has api.quoteString for ef.ef_name *) + let f = handle_keywords ef.ef_name in + newline ctx; + print ctx "%s.%s = %s(\"%s\", %i, list())" p f p ef.ef_name ef.ef_index + ) const_constructors; + + if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p; + if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p; + + gen_enum_metadata ctx en p + + let gen_abstract ctx a = + newline ctx; + newline ctx; + newline ctx; + let mt = (t_infos (TAbstractDecl a)) in + let p = get_path mt in + let p_name = get_full_name mt in + print ctx "class %s:" p; + + let use_pass = ref true in + + if has_feature ctx "python._hx_class_name" then begin + use_pass := false; + print ctx "\n\t_hx_class_name = \"%s\"" p_name + end; + + (match a.a_impl with + | Some c -> + List.iter (fun cf -> + use_pass := false; + if cf.cf_name = "_new" then + gen_class_constructor ctx c cf + else + gen_class_field ctx c p cf + ) c.cl_ordered_statics + | None -> ()); + + if !use_pass then spr ctx "\n\tpass"; + + if has_feature ctx "python._hx_class" then print ctx "\n%s._hx_class = %s" p p; + if has_feature ctx "python._hx_classes" then print ctx "\n_hx_classes[\"%s\"] = %s" p_name p + + + let gen_type ctx mt = match mt with + | TClassDecl c -> gen_class ctx c + | TEnumDecl en when not en.e_extern -> gen_enum ctx en + | TAbstractDecl {a_path = [],"UInt"} -> () + | TAbstractDecl {a_path = [],"Enum"} -> () + | TAbstractDecl {a_path = [],"EnumValue"} when not (has_feature ctx "has_enum") -> () + | TAbstractDecl {a_path = [],"Void"} -> () + | TAbstractDecl {a_path = [],"Int"} when not (has_feature ctx "Int.*") -> () + | TAbstractDecl {a_path = [],"Float"} when not (has_feature ctx "Float.*") -> () + | TAbstractDecl {a_path = [],"Class"} when not (has_feature ctx "Class.*") -> () + | TAbstractDecl {a_path = [],"Dynamic"} when not (has_feature ctx "Dynamic.*") -> () + | TAbstractDecl {a_path = [],"Bool"} when not (has_feature ctx "Bool.*") -> () + + | TAbstractDecl a when Meta.has Meta.CoreType a.a_meta -> gen_abstract ctx a + | _ -> () + + (* Generator parts *) + + let gen_resources ctx = + if Hashtbl.length ctx.com.resources > 0 then begin + let slash_index = try (String.rindex ctx.com.file '/')+1 with Not_found -> 0 in + let len = String.length ctx.com.file - slash_index in + let file_name = String.sub ctx.com.file slash_index len in + newline ctx; + newline ctx; + newline ctx; + spr ctx "def _hx_resources__():"; + spr ctx "\n\timport inspect"; + spr ctx "\n\timport sys"; + spr ctx "\n\tif not hasattr(sys.modules[__name__], '__file__'):"; + print ctx "\n\t\t_file = '%s'" file_name; + spr ctx "\n\telse:"; + spr ctx "\n\t\t_file = __file__"; + + spr ctx "\n\treturn {"; + let first = ref true in + Hashtbl.iter (fun k v -> + let prefix = if !first then begin + first := false; + ""; + end else + "," + in + let k_enc = Codegen.escape_res_name k false in + print ctx "%s\"%s\": open('%%s.%%s'%%(_file,'%s'),'rb').read()" prefix (Ast.s_escape k) k_enc; + Std.output_file (ctx.com.file ^ "." ^ k_enc) v + ) ctx.com.resources; + spr ctx "}" + end + + let gen_imports ctx = + let import path meta = + if Meta.has Meta.PythonImport meta && is_directly_used ctx.com meta then begin + let _, args, mp = Meta.get Meta.PythonImport meta in + + let class_name = match path with + | [],name -> name + | path,name -> (ExtString.String.join "_" path) ^ "_" ^ name + in + + let import_type,ignore_error = match args with + | [(EConst(String(module_name)), _)] + | [(EConst(String(module_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("false")),_)),_)] -> + IModule module_name, false + + | [(EConst(String(module_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("true")),_)),_)] -> + IModule module_name,true + + | [(EConst(String(module_name)), _); (EConst(String(object_name)), _)] + | [(EConst(String(module_name)), _); (EConst(String(object_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("false")),_)),_)] -> + IObject (module_name,object_name), false + + | [(EConst(String(module_name)), _); (EConst(String(object_name)), _); (EBinop(OpAssign, (EConst(Ident("ignoreError")),_), (EConst(Ident("true")),_)),_)] -> + IObject (module_name,object_name), true + | _ -> + error "Unsupported @:pythonImport format" mp + in + + let import = match import_type with + | IModule module_name -> + (* importing whole module *) + "import " ^ module_name ^ " as " ^ class_name + + | IObject (module_name,object_name) -> + if String.contains object_name '.' then + (* importing nested class *) + "import " ^ module_name ^ " as _hx_temp_import; " ^ class_name ^ " = _hx_temp_import." ^ object_name ^ "; del _hx_temp_import" + else + (* importing a class from a module *) + "from " ^ module_name ^ " import " ^ object_name ^ " as " ^ class_name + in + newline ctx; + if ignore_error then begin + spr ctx "try:\n\t"; + spr_line ctx import; + spr ctx "except:\n\tpass" + end else + spr ctx import + end + in + List.iter (fun mt -> + match mt with + | TClassDecl c when c.cl_extern -> import c.cl_path c.cl_meta + | TEnumDecl e when e.e_extern -> import e.e_path e.e_meta + | _ -> () + ) ctx.com.types + + let gen_types ctx = + let used_paths = Hashtbl.create 0 in + let find_type path = + Hashtbl.add used_paths path true; + Utils.find_type ctx.com path + in + let need_anon_for_trace = (has_feature ctx "has_anon_trace") && (has_feature ctx "haxe.Log.trace") in + if (has_feature ctx "has_anon") || (has_feature ctx "_hx_AnonObject") || need_anon_for_trace then begin + let with_body = (has_feature ctx "has_anon") || need_anon_for_trace in + newline ctx; + newline ctx; + newline ctx; + spr ctx "class _hx_AnonObject:\n"; + if with_body then begin + spr ctx "\tdef __init__(self, fields):\n"; + spr ctx "\t\tself.__dict__ = fields" + end else + spr ctx "\tpass"; + Hashtbl.add used_paths ([],"_hx_AnonObject") true; + end; + if has_feature ctx "python._hx_classes" then begin + newline ctx; + newline ctx; + newline ctx; + spr ctx "_hx_classes = {}"; + end; + if has_feature ctx "Boot.*" then + gen_type ctx (find_type (["python"],"Boot")); + if has_feature ctx "has_enum" || has_feature ctx "Enum.*" then + gen_type ctx (find_type ([],"Enum")); + if has_feature ctx "HxOverrides.*" then + gen_type ctx (find_type ([],"HxOverrides")); + List.iter (fun mt -> + if not (Hashtbl.mem used_paths (t_infos mt).mt_path) then + gen_type ctx mt + ) ctx.com.types + + let gen_static_inits ctx = + newline ctx; + List.iter (fun f -> f()) (List.rev ctx.static_inits) + + let gen_class_inits ctx = + newline ctx; + List.iter (fun f -> f()) (List.rev ctx.class_inits) + + let gen_main ctx = + match ctx.com.main with + | None -> + () + | Some e -> + newline ctx; + newline ctx; + gen_expr ctx e "" "" + + (* Entry point *) + + let run com = + Transformer.init com; + let ctx = mk_context com in + gen_imports ctx; + gen_resources ctx; + gen_types ctx; + gen_class_inits ctx; + gen_static_inits ctx; + gen_main ctx; + + mkdir_from_path com.file; + let ch = open_out_bin com.file in + output_string ch (Buffer.contents ctx.buf); + close_out ch +end + +let generate com = + Generator.run com \ No newline at end of file diff --git a/genswf.ml b/genswf.ml index 73c4893cb5781252aa7c5a28c19bbc20f90569f3..e53ec3f271af6f6fc0b18bfa877206bfcb1bb65f 100644 --- a/genswf.ml +++ b/genswf.ml @@ -134,7 +134,7 @@ let build_class com c file = } in (path.tpackage, [(ETypedef inf,pos)]) | _ -> - (* make flags *) + (* make flags *) let flags = [HExtern] in let flags = if c.hlc_interface then HInterface :: flags else flags in let flags = (match c.hlc_super with @@ -157,7 +157,7 @@ let build_class com c file = if c.hlc_interface then HExtends (make_tpath i) else HImplements (make_tpath i) ) (Array.to_list c.hlc_implements) @ flags in let flags = if c.hlc_sealed || Common.defined com Define.FlashStrict then flags else HImplements (make_tpath (HMPath ([],"Dynamic"))) :: flags in - (* make fields *) + (* make fields *) let getters = Hashtbl.create 0 in let setters = Hashtbl.create 0 in let override = Hashtbl.create 0 in @@ -243,7 +243,7 @@ let build_class com c file = | HVInt i | HVUInt i -> Some (Int (Int32.to_string i)) | HVFloat f -> - Some (Float (string_of_float f)) + Some (Float (float_repres f)) ) in match v with | None -> None @@ -458,7 +458,7 @@ let remove_debug_infos as3 = let parse_swf com file = let t = Common.timer "read swf" in - let is_swc = file_extension file = "swc" in + let is_swc = file_extension file = "swc" || file_extension file = "ane" in let file = (try Common.find_file com file with Not_found -> failwith ((if is_swc then "SWC" else "SWF") ^ " Library not found : " ^ file)) in let ch = if is_swc then begin let zip = Zip.open_in file in @@ -483,7 +483,7 @@ let parse_swf com file = IO.close_in ch; List.iter (fun t -> match t.tdata with - | TActionScript3 (id,as3) when not com.debug && not com.display -> + | TActionScript3 (id,as3) when not com.debug && com.display = DMNone -> t.tdata <- TActionScript3 (id,remove_debug_infos as3) | _ -> () ) tags; @@ -525,25 +525,6 @@ let tag ?(ext=false) d = { tdata = d; } -let swf_ver = function - | 6. -> 6 - | 7. -> 7 - | 8. -> 8 - | 9. -> 9 - | 10. | 10.1 -> 10 - | 10.2 -> 11 - | 10.3 -> 12 - | 11. -> 13 - | 11.1 -> 14 - | 11.2 -> 15 - | 11.3 -> 16 - | 11.4 -> 17 - | 11.5 -> 18 - | 11.6 -> 19 - | 11.7 -> 20 - | 11.8 -> 21 - | v -> failwith ("Invalid SWF version " ^ string_of_float v) - let convert_header com (w,h,fps,bg) = let high = (max w h) * 20 in let rec loop b = @@ -551,7 +532,7 @@ let convert_header com (w,h,fps,bg) = in let bits = loop 0 in { - h_version = swf_ver com.flash_version; + h_version = Common.flash_version_tag com.flash_version; h_size = { rect_nbits = bits + 1; left = 0; @@ -587,7 +568,8 @@ let build_dependencies t = (match c.cl_kind with KTypeParameter _ -> () | _ -> add_path c.cl_path DKType); List.iter (add_type_rec (t::l)) pl; | TAbstract (a,pl) -> - add_path a.a_path DKType; + if Meta.has Meta.CoreType a.a_meta then + add_path a.a_path DKType; List.iter (add_type_rec (t::l)) pl; | TFun (pl,t2) -> List.iter (fun (_,_,t2) -> add_type_rec (t::l) t2) pl; @@ -622,13 +604,12 @@ let build_dependencies t = add_type v.v_type; add_expr e1; add_expr e2; - | TVars vl -> - List.iter (fun (v,e) -> + | TVar (v,eo) -> add_type v.v_type; - match e with + begin match eo with | None -> () | Some e -> add_expr e - ) vl + end | _ -> Type.iter add_expr e and add_field f = @@ -662,7 +643,7 @@ let build_dependencies t = match follow t with | TInst (c,_) -> List.iter add_inherit c.cl_implements | _ -> () - ) c.cl_types; + ) c.cl_params; List.iter add_inherit c.cl_implements; | TEnumDecl e when not e.e_extern -> PMap.iter (fun _ f -> add_type f.ef_type) e.e_constrs; @@ -702,7 +683,7 @@ let build_swc_catalog com types = let x = node "swc" ["xmlns","http://www.adobe.com/flash/swccatalog/9"] [ node "versions" [] [ node "swc" ["version","1.2"] []; - node "haxe" ["version",Printf.sprintf "%d.%.2d" (com.version/100) (com.version mod 100)] []; + node "haxe" ["version",Printf.sprintf "%d.%.2d" (com.version/10000) (com.version mod 10000)] []; ]; node "features" [] [ node "feature-script-deps" [] []; @@ -749,35 +730,6 @@ let remove_classes toremove lib hcl = toremove := List.filter (fun p -> not (List.mem p classes)) !toremove; fst lib, tags (snd lib) -let build_swf8 com codeclip exports = - let code, clips = Genswf8.generate com in - let cid = ref 0 in - let clips = List.fold_left (fun acc m -> - let ename = Ast.s_type_path m in - if Hashtbl.mem exports ename then - acc - else begin - incr cid; - tag ~ext:true (TClip { c_id = !cid; c_frame_count = 1; c_tags = [] }) :: - tag ~ext:true (TExport [{ exp_id = !cid; exp_name = ename }]) :: - acc - end; - ) [] clips in - let code = (match codeclip with - | None -> List.map tag code - | Some link -> - incr cid; - [ - tag (TClip { - c_id = !cid; - c_frame_count = 1; - c_tags = List.map tag code @ [tag TShowFrame]; - }); - tag (TExport [{ exp_id = !cid; exp_name = link }]); - ] - ) in - clips @ code - type file_format = | BJPG | BPNG @@ -796,6 +748,8 @@ let detect_format data p = | _ -> error "Unknown file format" p +open TTFData + let build_swf9 com file swc = let boot_name = if swc <> None || Common.defined com Define.HaxeBoot then "haxe" else "boot_" ^ (String.sub (Digest.to_hex (Digest.string (Filename.basename file))) 0 4) in let code = Genswf9.generate com boot_name in @@ -820,7 +774,7 @@ let build_swf9 com file swc = hls_fields = [|f|]; } ) code in - [tag (TActionScript3 (None,As3hlparse.flatten inits))] + [tag (TActionScript3 ((if Common.defined com Define.SwfUseDoAbc then Some(1,boot_name) else None), As3hlparse.flatten inits))] ) in let cid = ref 0 in let classes = ref [{ f9_cid = None; f9_classname = boot_name }] in @@ -844,13 +798,33 @@ let build_swf9 com file swc = | (Meta.Font,(EConst (String file),p) :: args,_) :: l -> let file = try Common.find_file com file with Not_found -> file in let ch = try open_in_bin file with _ -> error "File not found" p in - let ttf = TTFParser.parse ch in + let ttf = try TTFParser.parse ch with e -> error ("Error while parsing font " ^ file ^ " : " ^ Printexc.to_string e) p in close_in ch; - let range_str = match args with - | [EConst (String str),_] -> str - | _ -> "" + let get_string e = match fst e with + | EConst (String s) -> Some s + | _ -> raise Not_found in - let ttf_swf = TTFSwfWriter.to_swf ttf range_str in + let ttf_config = { + ttfc_range_str = ""; + ttfc_font_name = None; + } in + begin match args with + | (EConst (String str),_) :: _ -> ttf_config.ttfc_range_str <- str; + | _ -> () + end; + begin match args with + | _ :: [e] -> + begin match fst e with + | EObjectDecl fl -> + begin try ttf_config.ttfc_font_name <- get_string (List.assoc "fontName" fl) + with Not_found -> () end + | _ -> + () + end + | _ -> + () + end; + let ttf_swf = TTFSwfWriter.to_swf ttf ttf_config in let ch = IO.output_string () in let b = IO.output_bits ch in TTFSwfWriter.write_font2 ch b ttf_swf; @@ -1030,10 +1004,10 @@ let build_swf9 com file swc = res @ bmp @ code @ clips let merge com file priority (h1,tags1) (h2,tags2) = - (* prioritize header+bgcolor for first swf *) - let header = if priority then { h2 with h_version = max h2.h_version (swf_ver com.flash_version) } else h1 in + (* prioritize header+bgcolor for first swf *) + let header = if priority then { h2 with h_version = max h2.h_version (Common.flash_version_tag com.flash_version) } else h1 in let tags1 = if priority then List.filter (function { tdata = TSetBgColor _ } -> false | _ -> true) tags1 else tags1 in - (* remove unused tags *) + (* remove unused tags *) let use_stage = priority && Common.defined com Define.FlashUseStage in let classes = ref [] in let nframe = ref 0 in @@ -1059,12 +1033,11 @@ let merge com file priority (h1,tags1) (h2,tags2) = classes := !classes @ List.map (fun e -> { f9_cid = Some e.exp_id; f9_classname = e.exp_name }) el; false | TF9Classes el when !nframe = 0 -> - if com.flash_version < 9. then failwith "You can't use AS3 SWF with Flash8 target"; classes := !classes @ List.filter (fun e -> e.f9_cid <> None) el; false | _ -> true ) tags2 in - (* rebuild character ids *) +(* rebuild character ids *) let max_id = ref (-1) in List.iter (SwfParser.scan (fun id -> if id > !max_id then max_id := id; id) (fun id -> id)) tags1; incr max_id; @@ -1076,7 +1049,7 @@ let merge com file priority (h1,tags1) (h2,tags2) = in List.iter loop tags2; let classes = List.map (fun e -> match e.f9_cid with None -> e | Some id -> { e with f9_cid = Some (id + !max_id) }) !classes in - (* merge timelines *) + (* merge timelines *) let rec loop l1 l2 = match l1, l2 with | ({ tdata = TSetBgColor _ } as t) :: l1, _ @@ -1105,11 +1078,9 @@ let merge com file priority (h1,tags1) (h2,tags2) = let generate com swf_header = let t = Common.timer "generate swf" in - let isf9 = com.flash_version >= 9. in let swc = if Common.defined com Define.Swc then Some (ref "") else None in - if swc <> None && not isf9 then failwith "SWC support is only available for Flash9+"; let file , codeclip = (try let f , c = ExtString.String.split com.file "@" in f, Some c with _ -> com.file , None) in - (* list exports *) + (* list exports *) let exports = Hashtbl.create 0 in let toremove = ref [] in List.iter (fun (file,lib,_) -> @@ -1140,8 +1111,8 @@ let generate com swf_header = | _ -> () ) tags; ) com.swf_libs; - (* build haxe swf *) - let tags = if isf9 then build_swf9 com file swc else build_swf8 com codeclip exports in + (* build haxe swf *) + let tags = build_swf9 com file swc in let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in let swf_debug_password = try @@ -1149,7 +1120,7 @@ let generate com swf_header = with Not_found -> "" in - let debug = (if isf9 && Common.defined com Define.Fdb then [tag (TEnableDebugger2 (0, swf_debug_password))] else []) in + let debug = (if Common.defined com Define.Fdb then [tag (TEnableDebugger2 (0, swf_debug_password))] else []) in let meta_data = try let file = Common.defined_value com Define.SwfMetadata in @@ -1162,18 +1133,13 @@ let generate com swf_header = let fattr = (if com.flash_version < 8. then [] else [tag (TFilesAttributes { fa_network = Common.defined com Define.NetworkSandbox; - fa_as3 = isf9; + fa_as3 = true; fa_metadata = meta_data <> []; fa_gpu = com.flash_version > 9. && Common.defined com Define.SwfGpu; fa_direct_blt = com.flash_version > 9. && Common.defined com Define.SwfDirectBlit; })] ) in let fattr = if Common.defined com Define.AdvancedTelemetry then fattr @ [tag (TUnknown (0x5D,"\x00\x00"))] else fattr in - let preframe, header = - if Common.defined com Define.SwfPreloaderFrame then - [tag TShowFrame], {h_version=header.h_version; h_size=header.h_size; h_frame_count=header.h_frame_count+1; h_fps=header.h_fps; h_compressed=header.h_compressed; } - else - [], header in let swf_script_limits = try let s = Common.defined_value com Define.SwfScriptTimeout in let i = try int_of_string s with _ -> error "Argument to swf_script_timeout must be an integer" Ast.null_pos in @@ -1181,16 +1147,26 @@ let generate com swf_header = with Not_found -> [] in - let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ preframe @ tags @ [tag TShowFrame] in - (* merge swf libraries *) + let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in + (* merge swf libraries *) let priority = ref (swf_header = None) in let swf = List.fold_left (fun swf (file,lib,cl) -> let swf = merge com file !priority swf (remove_classes toremove lib cl) in priority := false; swf ) swf com.swf_libs in + let swf = match swf with + | header,tags when Common.defined com Define.SwfPreloaderFrame -> + let rec loop l = + match l with + | ({tdata = TFilesAttributes _ | TUnknown (0x5D,"\x00\x00") | TMetaData _ | TSetBgColor _ | TEnableDebugger2 _ | TScriptLimits _} as t) :: l -> t :: loop l + | t :: l -> tag TShowFrame :: t :: l + | [] -> [] + in + {header with h_frame_count = header.h_frame_count + 1},loop tags + | _ -> swf in t(); - (* write swf/swc *) + (* write swf/swc *) let t = Common.timer "write swf" in let level = (try int_of_string (Common.defined_value com Define.SwfCompressLevel) with Not_found -> 9) in SwfParser.init Extc.input_zip (Extc.output_zip ~level); diff --git a/genswf8.ml b/genswf8.ml deleted file mode 100644 index a345e54d55fed57486370b056872d7917b074522..0000000000000000000000000000000000000000 --- a/genswf8.ml +++ /dev/null @@ -1,1589 +0,0 @@ -(* - * Copyright (C)2005-2013 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. - *) - -open Swf -open Ast -open Type -open Common - -type register = - | NoReg - | Reg of int - -type context = { - - stack : Codegen.stack_context; - - (* segs *) - mutable segs : (actions * (string * bool, int) Hashtbl.t) list; - - (* code *) - mutable opcodes : actions; - mutable code_pos : int; - mutable stack_size : int; - mutable opt_push : bool; - mutable ident_count : int; - mutable ident_size : int; - - (* management *) - com : Common.context; - packages : (string list,unit) Hashtbl.t; - flash6 : bool; - mutable idents : (string * bool,int) Hashtbl.t; - mutable movieclips : path list; - mutable inits : texpr list; - mutable statics : (tclass * bool * string * texpr) list; - mutable regs : (string,register) PMap.t; - mutable reg_count : int; - mutable reg_max : int; - mutable fun_stack : int; - mutable curclass : tclass; - mutable curmethod : (string * bool); - mutable fun_pargs : (int * bool list) list; - mutable static_init : bool; - mutable extern_boot : bool; - - (* loops *) - mutable breaks : (unit -> unit) list; - mutable continues : (int -> unit) list; - mutable loop_stack : int; - mutable in_loop : bool; -} - -let invalid_expr p = error "Invalid expression" p -let stack_error p = error "Stack error" p -let protect_all = ref true - -(* -------------------------------------------------------------- *) -(* Bytecode Helpers *) - -type tmp_variable = - | TmpReg of int - | TmpVar of string * int - -type kind = - | VarReg of int - | VarStr - | VarObj - | VarClosure - | VarVolatile - -type push_style = - | VStr of string * bool - | VInt of int - | VInt32 of int32 - | VFloat of float - | VReg of int - | VThis - | VNull - | VUndefined - | VSuper - -let stack_delta = function - | APush l -> List.length l - | ASetReg _ -> 0 - | AAdd | ADivide | ASubtract | AMultiply | AMod | AStringAdd -> -1 - | AAnd | AOr | AXor | AShl | AShr | AAsr -> -1 - | ACompare | AGreater -> -1 - | AEval | ANot | AJump _ | AToInt | AToNumber | AToString | ATry _ | ASwap -> 0 - | ACondJump _ -> -1 - | AEqual | APhysEqual -> -1 - | ANew -> -1 (** only if 0 params **) - | AObject | AInitArray -> 0 (** calculated outside **) - | ASet -> -2 - | APop -> -1 - | AFunction _ | AFunction2 _ -> 1 - | ADup -> 1 - | AWith _ -> -1 - | AObjGet -> -1 - | AObjSet -> -3 - | ALocalVar -> -1 - | ALocalAssign -> -2 - | AReturn -> -1 - | AGetURL2 _ -> -2 - | ADeleteObj | AInstanceOf | ACast -> -1 - | AExtends | AImplements -> -2 - | AEnum2 | ATrace | AThrow -> -1 - | AGetTimer -> 1 - | AIncrement | ADecrement | AChr | AOrd | ARandom | ADelete | ATypeOf | ATargetPath -> 0 - | AObjCall | ACall | ANewMethod -> assert false - | AStringPool _ -> 0 - | AFSCommand2 -> 0 - | op -> failwith ("Unknown stack delta for " ^ (ActionScript.action_string (fun _ -> "") 0 op)) - -let overflow ctx = - failwith ("In or near the method " ^ s_type_path ctx.curclass.cl_path ^ "." ^ fst ctx.curmethod ^ - " too much code is causing an overflow that can't be handled by the SWF format. " ^ - "Please split your code in several methods so it can be correctly compiled.") - -let write ctx op = - let write b op = - DynArray.add ctx.opcodes op; - ctx.code_pos <- ctx.code_pos + 1; - ctx.stack_size <- ctx.stack_size + stack_delta op; - ctx.opt_push <- b - in - match op with - | APush l when ctx.opt_push -> - (match DynArray.last ctx.opcodes with - | (APush l2) as a -> - ctx.code_pos <- ctx.code_pos - 1; - ctx.stack_size <- ctx.stack_size - stack_delta a; - DynArray.delete_last ctx.opcodes; - write true (APush (l2 @ l)) - | _ -> - assert false) - | APush _ -> - write true op - | _ -> - write false op - -let call ctx kind n = - let op , n = (match kind with - | VarReg r -> - write ctx (APush [PReg r;PUndefined]); - AObjCall , n + 2 - | VarStr -> - ACall , n + 1 - | VarClosure | VarObj -> - AObjCall , n + 2 - | VarVolatile -> - assert false - ) in - DynArray.add ctx.opcodes op; - ctx.opt_push <- false; - ctx.code_pos <- ctx.code_pos + 1; - ctx.stack_size <- ctx.stack_size - n - -let new_call ctx kind n = - let op , n = (match kind with - | VarReg r -> - write ctx (APush [PReg r;PUndefined]); - ANewMethod , n + 2 - | VarStr -> - ANew , n + 1 - | VarClosure | VarObj -> - ANewMethod , n + 2 - | VarVolatile -> - assert false - ) in - DynArray.add ctx.opcodes op; - ctx.opt_push <- false; - ctx.code_pos <- ctx.code_pos + 1; - ctx.stack_size <- ctx.stack_size - n - -let unprotect a = !protect_all || a = "" || a = "_" || (a.[0] = '_' && a.[1] != '_') - -let rec is_protected_path path ext = - match path with - | ["flash"] , "Boot" | ["flash"] , "Lib" -> false - | "flash" :: _ , _ | [] , "flash" -> ext - | [] , "Array" | [] , "Math" | [] , "Date" | [] , "String" | [] , "Bool" -> true - | [] , "Int" | [] , "Float" -> true - | "_global" :: l , n -> is_protected_path (l,n) ext - | _ -> false - -let rec is_protected ctx ?(stat=false) t field = - match follow t with - | TInst (c,_) -> - let rec loop c = - (is_protected_path c.cl_path c.cl_extern && PMap.mem field (if stat then c.cl_statics else c.cl_fields)) - || List.exists (fun (i,_) -> i.cl_path = (["mt"],"Protect") || (not stat && loop i)) c.cl_implements - || (not stat && match c.cl_super with None -> false | Some (c,_) -> loop c) - in - loop c - | TAnon a -> - (match !(a.a_status) with - | Statics c -> is_protected ctx ~stat:true (TInst (c,[])) field - | _ -> false) - | _ -> false - -let push ctx items = - write ctx (APush (List.map (fun i -> - match i with - | VStr (str,flag) -> - let flag = if flag || unprotect str then true else flag in - let n = (try - Hashtbl.find ctx.idents (str,flag) - with Not_found -> - let n = ctx.ident_count in - ctx.ident_count <- n + 1; - ctx.ident_size <- ctx.ident_size + 1 + String.length str; - Hashtbl.add ctx.idents (str,flag) n; - n - ) in - if n <= 0xFF then - PStack n - else - PStack2 n - | VInt n -> - PInt (Int32.of_int n) - | VInt32 n -> - PInt n - | VFloat f -> - PDouble f - | VThis -> - PReg 1 - | VNull -> - PNull - | VUndefined -> - PUndefined - | VSuper -> - PReg 2 - | VReg n -> - PReg n - ) items)) - -let pop ctx n dec = - let rec loop n = - if n <> 0 then begin - write ctx APop; - loop (n - 1) - end; - in - if n < 0 then assert false; - let old_s = ctx.stack_size in - loop n; - if not dec then ctx.stack_size <- old_s - -let cjmp ctx = - write ctx (ACondJump 0); - let start_pos = ctx.code_pos in - let op_pos = DynArray.length ctx.opcodes - 1 in - (fun() -> - let delta = ctx.code_pos - start_pos in - DynArray.set ctx.opcodes op_pos (ACondJump delta); - ctx.opt_push <- false - ) - -let jmp ctx = - write ctx (AJump 0); - let start_pos = ctx.code_pos in - let op_pos = DynArray.length ctx.opcodes - 1 in - (fun() -> - let delta = ctx.code_pos - start_pos in - DynArray.set ctx.opcodes op_pos (AJump delta); - ctx.opt_push <- false - ) - -let pos ctx = - ctx.opt_push <- false; - let start_pos = ctx.code_pos in - (fun ~cond -> - let delta = start_pos - (ctx.code_pos + 1) in - write ctx (if cond then ACondJump delta else AJump delta); - ) - -let jmp_pos ctx cond = - write ctx (AJump 0); - let start_pos = ctx.code_pos in - let op_pos = DynArray.length ctx.opcodes - 1 in - (fun pos -> - let delta = pos - start_pos in - DynArray.set ctx.opcodes op_pos (if cond then ACondJump delta else AJump delta); - ctx.opt_push <- false - ) - -let init_array ctx n = - push ctx [VInt n]; - write ctx AInitArray; - ctx.stack_size <- ctx.stack_size - n - -let setvar ?(retval=false) ctx = function - | VarReg (-1) -> assert false (** true, false, null **) - | VarReg n -> write ctx (ASetReg n); if not retval then write ctx APop - | VarStr - | VarObj - | VarClosure as s -> - if retval then write ctx (ASetReg 0); - write ctx (if s = VarStr then ASet else AObjSet); - if retval then push ctx [VReg 0] - | VarVolatile -> - if retval then write ctx (ASetReg 0); - init_array ctx 1; - write ctx AObjSet; - if retval then push ctx [VReg 0] - -let getvar ctx = function - | VarReg (-1) -> () (** true, false, null **) - | VarReg n -> push ctx [VReg n] - | VarStr -> write ctx AEval - | VarObj -> write ctx AObjGet - | VarClosure -> - push ctx [VInt 2; VStr ("@closure",false)]; - call ctx VarStr 2 - | VarVolatile -> - write ctx AObjGet; - push ctx [VInt 0]; - write ctx AObjGet - -let gen_path ctx ?(protect=false) (p,t) is_extern = - let flag = is_protected_path (p,t) is_extern in - match p with - | [] -> - push ctx [VStr (t,flag)]; - VarStr - | x :: l -> - push ctx [VStr (x,protect && flag)]; - write ctx AEval; - List.iter (fun x -> - push ctx [VStr (x,protect && flag)]; - write ctx AObjGet; - ) l; - push ctx [VStr (t,flag)]; - VarObj - -let begin_func ctx need_super need_args args = - if ctx.flash6 then - let f = { - f_name = ""; - Swf.f_args = List.map snd args; - f_codelen = 0; - } in - write ctx (AFunction f); - let start_pos = ctx.code_pos in - let old_stack = ctx.fun_stack in - ctx.fun_stack <- ctx.stack_size; - (fun() -> - let delta = ctx.code_pos - start_pos in - f.f_codelen <- delta; - let codesize = ActionScript.jump_index_to_size ctx.opcodes (start_pos-1) delta in - if codesize >= 1 lsl 16 then overflow ctx; - if ctx.fun_stack <> ctx.stack_size then assert false; - ctx.fun_stack <- old_stack; - ) - else - let default_flags = ThisRegister :: (if need_args then [] else [ArgumentsNoVar]) in - let f = { - f2_name = ""; - f2_args = args; - f2_codelen = 0; - f2_nregs = 0; - f2_flags = (if need_super then SuperRegister :: default_flags else SuperNoVar :: default_flags); - } in - write ctx (AFunction2 f); - let start_pos = ctx.code_pos in - let old_stack = ctx.fun_stack in - let old_rmax = ctx.reg_max in - let old_sinit = ctx.static_init in - ctx.fun_stack <- ctx.stack_size; - ctx.reg_max <- ctx.reg_count; - ctx.static_init <- false; - (fun() -> - let delta = ctx.code_pos - start_pos in - f.f2_codelen <- delta; - f.f2_nregs <- ctx.reg_max + 1; - let codesize = ActionScript.jump_index_to_size ctx.opcodes (start_pos-1) delta in - if codesize >= 1 lsl 16 then overflow ctx; - if ctx.fun_stack <> ctx.stack_size then assert false; - ctx.fun_stack <- old_stack; - ctx.reg_max <- old_rmax; - ctx.static_init <- old_sinit; - ) - -let open_block ctx = - let old_regs = ctx.regs in - let old_rcount = ctx.reg_count in - (fun() -> - ctx.regs <- old_regs; - ctx.reg_count <- old_rcount; - ) - -let begin_loop ctx = - let old_breaks = ctx.breaks in - let old_cont = ctx.continues in - let old_stack = ctx.loop_stack in - let old_loop = ctx.in_loop in - ctx.breaks <- []; - ctx.continues <- []; - ctx.loop_stack <- ctx.stack_size; - ctx.in_loop <- true; - (fun pos -> - List.iter (fun f -> f()) ctx.breaks; - List.iter (fun f -> f pos) ctx.continues; - ctx.breaks <- old_breaks; - ctx.continues <- old_cont; - ctx.loop_stack <- old_stack; - ctx.in_loop <- old_loop; - ) - -let alloc_reg ctx = - ctx.reg_count <- ctx.reg_count + 1; - if ctx.reg_count > ctx.reg_max then ctx.reg_max <- ctx.reg_count; - ctx.reg_count - -let free_reg ctx r p = - if r <> ctx.reg_count then stack_error p; - ctx.reg_count <- ctx.reg_count - 1 - -let segment ctx = - ctx.segs <- (ctx.opcodes,ctx.idents) :: ctx.segs; - ctx.opcodes <- DynArray.create(); - ctx.idents <- Hashtbl.create 0; - ctx.ident_count <- 0; - ctx.ident_size <- 0; - ctx.code_pos <- 0; - write ctx (AStringPool []) - -(* -------------------------------------------------------------- *) -(* Generation Helpers *) - -let define_var ctx v ef = - if ctx.flash6 || v.v_capture || ctx.static_init then begin - push ctx [VStr (v.v_name,false)]; - ctx.regs <- PMap.add v.v_name NoReg ctx.regs; - match ef with - | None -> - write ctx ALocalVar - | Some f -> - f(); - write ctx ALocalAssign - end else begin - let r = alloc_reg ctx in - ctx.regs <- PMap.add v.v_name (Reg r) ctx.regs; - match ef with - | None -> () - | Some f -> - f(); - setvar ctx (VarReg r) - end - -let alloc_tmp ctx = - let r = alloc_reg ctx in - if ctx.flash6 then - let name = "$" ^ string_of_int r in - define_var ctx (alloc_var name t_dynamic) None; - TmpVar (name,r); - else - TmpReg r - -let get_tmp ctx = function - | TmpVar (v,_) -> - push ctx [VStr (v,false)]; - write ctx AEval; - | TmpReg r -> - push ctx [VReg r] - -let set_tmp ctx = function - | TmpVar (v,_) -> - write ctx ADup; - push ctx [VStr (v,false)]; - write ctx ASwap; - write ctx ASet - | TmpReg r -> - write ctx (ASetReg r) - -let free_tmp ctx v p = - match v with - | TmpVar (v,r) -> - ctx.regs <- PMap.remove v ctx.regs; - free_reg ctx r p - | TmpReg r -> - free_reg ctx r p - -let no_value ctx retval = - (* does not push a null but still increment the stack like if - a real value was pushed *) - if retval then ctx.stack_size <- ctx.stack_size + 1 - -let gen_try ctx = - let tdata = { - tr_style = TryRegister 0; - tr_trylen = 0; - tr_catchlen = None; - tr_finallylen = None; - } in - write ctx (ATry tdata); - let start = ctx.code_pos in - (fun() -> - let jump_end = jmp ctx in - tdata.tr_trylen <- ctx.code_pos - start; - let start = ctx.code_pos in - (fun() -> - if ctx.code_pos <> start then tdata.tr_catchlen <- Some (ctx.code_pos - start); - jump_end() - ) - ) - -(* -------------------------------------------------------------- *) -(* Generation *) - -let rec gen_big_string ctx s = - let len = String.length s in - let max = 65000 in - ctx.opt_push <- false; - if len <= max then - write ctx (APush [PString s]) - else begin - write ctx (APush [PString (String.sub s 0 max)]); - gen_big_string ctx (String.sub s max (len - max)); - write ctx AAdd; - end - -let rec gen_constant ctx c p = - match c with - | TInt i -> push ctx [VInt32 i] - | TFloat s -> push ctx [VFloat (try float_of_string s with _ -> invalid_expr p)] - | TString s -> - if String.contains s '\000' then error "A String cannot contain \\0 characters" p; - push ctx [VStr (s,true)] - | TBool b -> write ctx (APush [PBool b]) - | TNull -> push ctx [VNull] - | TThis - | TSuper -> assert false - -let access_local ctx s = - match (try PMap.find s ctx.regs , false with Not_found -> NoReg, s <> "Enum") with - | NoReg , flag -> - push ctx [VStr (s,flag)]; - VarStr - | Reg r , _ -> - VarReg r - -let rec gen_access ?(read_write=false) ctx forcall e = - match e.eexpr with - | TConst TSuper -> - (* for superconstructor *) - if ctx.flash6 then begin - push ctx [VStr ("super",true)]; - VarStr - end else if forcall then begin - push ctx [VSuper]; - write ctx (APush [PUndefined]); - VarObj - end else - VarReg 2 - | TConst TThis -> - if ctx.flash6 then begin - push ctx [VStr ("this",true)]; - VarStr - end else - VarReg 1 - | TLocal { v_name = "__arguments__" } -> - push ctx [VStr ("arguments",true)]; - VarStr - | TLocal v -> - access_local ctx v.v_name - | TField (e,FClosure (_,{ cf_name = f })) -> - gen_expr ctx true e; - if read_write then assert false; - push ctx [VStr (f,is_protected ctx e.etype f)]; - VarClosure - | TField (e2,f) -> - gen_expr ctx true e2; - if read_write then write ctx ADup; - let f = field_name f in - let p = VStr (f,is_protected ctx e2.etype f) in - push ctx [p]; - if read_write then begin - write ctx ASwap; - push ctx [p]; - end; - if not !protect_all && Codegen.is_volatile e.etype then - VarVolatile - else - VarObj - | TArray (ea,eb) -> - if read_write then - try - let r = (match ea.eexpr with TLocal l -> (match PMap.find l.v_name ctx.regs with Reg r -> r | _ -> raise Not_found) | _ -> raise Not_found) in - push ctx [VReg r]; - gen_expr ctx true eb; - write ctx ADup; - push ctx [VReg r]; - write ctx ASwap; - with Not_found -> - gen_expr ctx true eb; - gen_expr ctx true ea; - write ctx (ASetReg 0); - write ctx ASwap; - write ctx ADup; - push ctx [VReg 0]; - write ctx ASwap; - else begin - gen_expr ctx true ea; - gen_expr ctx true eb; - end; - VarObj - | TTypeExpr t -> - (match t with - | TClassDecl c -> gen_path ctx c.cl_path c.cl_extern - | TEnumDecl e -> gen_path ctx e.e_path false - | TAbstractDecl a -> gen_path ctx a.a_path false - | TTypeDecl _ -> assert false) - | _ -> - if not forcall then invalid_expr e.epos; - gen_expr ctx true e; - write ctx (APush [PUndefined]); - VarObj - -and gen_access_rw ctx e = - match e.eexpr with - | TField ({ eexpr = TLocal _ },_) | TArray ({ eexpr = TLocal _ },{ eexpr = TConst _ }) | TArray ({ eexpr = TLocal _ },{ eexpr = TLocal _ }) -> - ignore(gen_access ctx false e); - gen_access ctx false e - | TField _ | TArray _ -> - gen_access ~read_write:true ctx false e - | _ -> - ignore(gen_access ctx false e); - gen_access ctx false e - -and gen_try_catch ctx retval e catchs = - let start_try = gen_try ctx in - gen_expr ctx retval e; - let end_try = start_try() in - let end_throw = ref true in - let jumps = List.map (fun (v,e) -> - if not !end_throw then - (fun () -> ()) - 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 - let next_catch = (match t with - | None -> - end_throw := false; - (fun() -> ()) - | Some t -> - getvar ctx (gen_access ctx false (mk (TTypeExpr t) (mk_mono()) e.epos)); - push ctx [VReg 0; VInt 2; VStr ("@instanceof",false)]; - call ctx VarStr 2; - write ctx ANot; - cjmp ctx - ) in - let block = open_block ctx in - define_var ctx v (Some (fun() -> push ctx [VReg 0])); - gen_expr ctx retval e; - block(); - if retval then ctx.stack_size <- ctx.stack_size - 1; - let j = jmp ctx in - next_catch(); - j - ) catchs in - if !end_throw && catchs <> [] then begin - push ctx [VReg 0]; - write ctx AThrow; - end; - List.iter (fun j -> j()) jumps; - end_try() - -and gen_switch ctx retval e cases def = - gen_expr ctx true e; - let r = alloc_tmp ctx in - set_tmp ctx r; - let first = ref true in - let dispatch = List.map (fun (el,x) -> - List.map (fun e -> - if !first then first := false else get_tmp ctx r; - gen_expr ctx true e; - write ctx AEqual; - cjmp ctx - ) el , x - ) cases in - if !first then write ctx APop; - (match def with - | None -> if retval then push ctx [VNull] - | Some e -> gen_expr ctx retval e); - let jend = jmp ctx in - let jends = List.map (fun (jl,e) -> - List.iter (fun j -> j()) jl; - gen_expr ctx retval e; - if retval then ctx.stack_size <- ctx.stack_size - 1; - jmp ctx; - ) dispatch in - jend(); - free_tmp ctx r e.epos; - List.iter (fun j -> j()) jends - -and gen_match ctx retval e cases def = - gen_expr ctx true e; - let renum = alloc_tmp ctx in - set_tmp ctx renum; - push ctx [VInt 1]; - write ctx AObjGet; - let rtag = alloc_tmp ctx in - set_tmp ctx rtag; - let first = ref true in - let dispatch = List.map (fun (cl,params,e) -> - List.map (fun c -> - if !first then first := false else get_tmp ctx rtag; - push ctx [VInt c]; - write ctx APhysEqual; - cjmp ctx - ) cl, params, e - ) cases in - if !first then write ctx APop; - free_tmp ctx rtag e.epos; - (match def with - | None -> if retval then push ctx [VNull] - | Some e -> gen_expr ctx retval e); - let jend = jmp ctx in - let jends = List.map (fun (jl,args,e) -> - let regs = ctx.regs in - let nregs = ctx.reg_count in - List.iter (fun j -> j()) jl; - let n = ref 1 in - List.iter (fun v -> - incr n; - match v with - | None -> () - | Some v -> - define_var ctx v (Some (fun() -> - get_tmp ctx renum; - push ctx [VInt !n]; - write ctx AObjGet - )) - ) (match args with None -> [] | Some l -> l); - gen_expr ctx retval e; - if retval then ctx.stack_size <- ctx.stack_size - 1; - ctx.regs <- regs; - ctx.reg_count <- nregs; - jmp ctx; - ) dispatch in - jend(); - free_tmp ctx renum e.epos; - List.iter (fun j -> j()) jends - -and gen_binop ctx retval op e1 e2 = - let gen a = - gen_expr ctx true e1; - gen_expr ctx true e2; - write ctx a - in - let make_op = function - | OpAdd -> AAdd - | OpMult -> AMultiply - | OpDiv -> ADivide - | OpSub -> ASubtract - | OpAnd -> AAnd - | OpOr -> AOr - | OpXor -> AXor - | OpShl -> AShl - | OpShr -> AShr - | OpUShr -> AAsr - | OpMod -> AMod - | _ -> assert false - in - match op with - | OpAssign -> - let k = gen_access ctx false e1 in - gen_expr ctx true e2; - setvar ~retval ctx k - | OpAssignOp op -> - let k = gen_access_rw ctx e1 in - getvar ctx k; - gen_expr ctx true e2; - write ctx (make_op op); - setvar ~retval ctx k - | OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod -> - gen (make_op op) - | OpEq -> - gen AEqual - | OpNotEq -> - gen AEqual; - write ctx ANot - | OpGt -> gen AGreater - | OpGte -> - gen ACompare; - write ctx ANot - | OpLt -> gen ACompare - | OpLte -> - gen AGreater; - write ctx ANot - | OpBoolAnd -> - gen_expr ctx true e1; - write ctx ADup; - write ctx ANot; - let jump_end = cjmp ctx in - write ctx APop; - gen_expr ctx true e2; - jump_end() - | OpBoolOr -> - gen_expr ctx true e1; - write ctx ADup; - let jump_end = cjmp ctx in - write ctx APop; - gen_expr ctx true e2; - jump_end() - | OpInterval | OpArrow -> - (* handled by typer *) - assert false - -and gen_unop ctx retval op flag e = - match op with - | Not -> - gen_expr ctx true e; - write ctx ANot - | Neg -> - push ctx [VInt 0]; - gen_expr ctx true e; - write ctx ASubtract - | NegBits -> - gen_expr ctx true e; - push ctx [VInt (-1)]; - write ctx AXor - | Increment - | Decrement -> - let k = gen_access_rw ctx e in - getvar ctx k; - (* store preincr value for later access *) - if retval && flag = Postfix then write ctx (ASetReg 0); - write ctx (match op with Increment -> AIncrement | Decrement -> ADecrement | _ -> assert false); - setvar ~retval:(retval && flag = Prefix) ctx k; - if retval && flag = Postfix then push ctx [VReg 0] - -and gen_call ctx e el = - let loc = match e.eexpr with TLocal v -> v.v_name | _ -> "" in - match loc, el with - | "__instanceof__" , [e1;e2] -> - gen_expr ctx true e1; - gen_expr ctx true e2; - write ctx AInstanceOf - | "__typeof__" , [e] -> - gen_expr ctx true e; - write ctx ATypeOf - | "__delete__" , [e1; e2] -> - gen_expr ctx true e1; - gen_expr ctx true e2; - write ctx ADeleteObj - | "__random__" , [e] -> - gen_expr ctx true e; - write ctx ARandom - | "__trace__" , [e] -> - gen_expr ctx true e; - write ctx ATrace - | "__eval__" , [e] -> - gen_expr ctx true e; - write ctx AEval - | "__gettimer__", [] -> - write ctx AGetTimer - | "__undefined__", [] -> - push ctx [VUndefined] - | "__geturl__" , url :: target :: post -> - gen_expr ctx true url; - gen_expr ctx true target; - write ctx (AGetURL2 (match post with [] -> 0 | [{ eexpr = TConst (TString "GET") }] -> 1 | _ -> 2)) - | "__new__", e :: el -> - let nargs = List.length el in - List.iter (gen_expr ctx true) (List.rev el); - push ctx [VInt nargs]; - let k = gen_access ctx true e in - new_call ctx k nargs - | "__keys__", [e2] - | "__hkeys__", [e2] -> - let r = alloc_tmp ctx in - push ctx [VInt 0; VStr ("Array",true)]; - new_call ctx VarStr 0; - set_tmp ctx r; - write ctx APop; - gen_expr ctx true e2; - write ctx AEnum2; - ctx.stack_size <- ctx.stack_size + 1; (* fake *) - let loop = pos ctx in - write ctx (ASetReg 0); - push ctx [VNull]; - write ctx AEqual; - let jump_end = cjmp ctx in - if loc = "__hkeys__" then begin - push ctx [VInt 1; VInt 1; VReg 0; VStr ("substr",true)]; - call ctx VarObj 1; - end else begin - push ctx [VReg 0]; - end; - push ctx [VInt 1]; - get_tmp ctx r; - push ctx [VStr ("push",true)]; - call ctx VarObj 1; - write ctx APop; - loop false; - jump_end(); - get_tmp ctx r; - free_tmp ctx r e2.epos; - | "__physeq__" , [e1;e2] -> - gen_expr ctx true e1; - gen_expr ctx true e2; - write ctx APhysEqual; - | "__unprotect__", [{ eexpr = TConst (TString s) }] -> - push ctx [VStr (s,false)] - | "__resources__", [] -> - let count = ref 0 in - Hashtbl.iter (fun name data -> - incr count; - push ctx [VStr ("name",false);VStr (name,true)]; - (* if the data contains \0 or is not UTF8 valid, encode into bytes *) - (try - (try ignore(String.index data '\000'); raise Exit; with Not_found -> ()); - UTF8.validate data; - push ctx [VStr ("str",false)]; - gen_big_string ctx data; - with _ -> - push ctx [VStr ("data",false)]; - gen_big_string ctx (Codegen.bytes_serialize data)); - push ctx [VInt 2]; - write ctx AObject; - ctx.stack_size <- ctx.stack_size - 4; - ) ctx.com.resources; - init_array ctx !count - | "__FSCommand2__", l -> - let nargs = List.length l in - List.iter (gen_expr ctx true) (List.rev l); - push ctx [VInt nargs]; - write ctx AFSCommand2; - ctx.stack_size <- ctx.stack_size - nargs - | _ , _ -> - let nargs = List.length el in - List.iter (gen_expr ctx true) (List.rev el); - push ctx [VInt nargs]; - let k = gen_access ctx true e in - call ctx k nargs - - -and gen_expr_2 ctx retval e = - match e.eexpr with - | TConst TSuper - | TConst TThis - | TField _ - | TArray _ - | TLocal _ - | TTypeExpr _ -> - getvar ctx (gen_access ctx false e) - | TConst c -> - gen_constant ctx c e.epos - | TParenthesis e -> - gen_expr ctx retval e - | TBlock el -> - let rec loop = function - | [] -> - if retval then push ctx [VNull] - | [e] -> - gen_expr ctx retval e - | e :: l -> - gen_expr ctx false e; - loop l - in - let b = open_block ctx in - loop el; - b() - | TVars vl -> - List.iter (fun (v,e) -> - define_var ctx v (match e with None -> None | Some e -> Some (fun() -> gen_expr ctx true e)) - ) vl; - if retval then push ctx [VNull] - | TArrayDecl el -> - List.iter (gen_expr ctx true) (List.rev el); - init_array ctx (List.length el); - | TObjectDecl fl -> - let nfields = List.length fl in - List.iter (fun (s,v) -> - push ctx [VStr (s,false)]; - gen_expr ctx true v - ) fl; - push ctx [VInt nfields]; - write ctx AObject; - ctx.stack_size <- ctx.stack_size - (nfields * 2); - | TFunction f -> - let block = open_block ctx in - let old_in_loop = ctx.in_loop in - let old_meth = ctx.curmethod in - let rec loop e = - match e.eexpr with - | TConst TSuper -> raise Exit - | _ -> Type.iter loop e - in - let reg_super = try loop f.tf_expr; false with Exit -> true in - let rec loop e = - match e.eexpr with - | TLocal { v_name = "__arguments__" } -> raise Exit - | _ -> Type.iter loop e - in - let reg_args = try loop f.tf_expr; false with Exit -> true in - if snd ctx.curmethod then - ctx.curmethod <- (fst ctx.curmethod ^ "@" ^ string_of_int (Lexer.get_error_line e.epos), true) - else - ctx.curmethod <- (fst ctx.curmethod, true); - (* only keep None bindings, for protect *) - ctx.regs <- PMap.foldi (fun v x acc -> - match x with - | NoReg -> PMap.add v x acc - | Reg _ -> acc - ) ctx.regs PMap.empty; - ctx.reg_count <- (if reg_super then 2 else 1); - ctx.in_loop <- false; - let pargs = ref [] in - let rargs = List.map (fun (v,_) -> - let no_reg = ctx.flash6 || v.v_capture in - if no_reg then begin - ctx.regs <- PMap.add v.v_name NoReg ctx.regs; - pargs := unprotect v.v_name :: !pargs; - 0 , v.v_name - end else begin - let r = alloc_reg ctx in - ctx.regs <- PMap.add v.v_name (Reg r) ctx.regs; - pargs := false :: !pargs; - r , "" - end - ) f.tf_args in - let tf = begin_func ctx reg_super reg_args rargs in - ctx.fun_pargs <- (ctx.code_pos, List.rev !pargs) :: ctx.fun_pargs; - List.iter (fun (v,c) -> - match c with - | None | Some TNull -> () - | Some c -> gen_expr ctx false (Codegen.set_default ctx.com v c e.epos) - ) f.tf_args; - if ctx.com.debug then begin - gen_expr ctx false (ctx.stack.Codegen.stack_push ctx.curclass (fst ctx.curmethod)); - gen_expr ctx false ctx.stack.Codegen.stack_save_pos; - let start_try = gen_try ctx in - gen_expr ctx false (Codegen.stack_block_loop ctx.stack f.tf_expr); - gen_expr ctx false ctx.stack.Codegen.stack_pop; - let end_try = start_try() in - (* if $spos == 1 , then no upper call, so report as uncaught *) - getvar ctx (access_local ctx ctx.stack.Codegen.stack_pos_var); - push ctx [VInt 1]; - write ctx AEqual; - write ctx ANot; - let j = cjmp ctx in - push ctx [VReg 0]; - push ctx [VInt 1]; - getvar ctx (gen_path ctx (["flash"],"Boot") ctx.extern_boot); - push ctx [VStr ("__exc",false)]; - call ctx VarObj 1; - write ctx AReturn; - j(); - push ctx [VReg 0]; - write ctx AThrow; - end_try(); - end else - gen_expr ctx false f.tf_expr; - ctx.in_loop <- old_in_loop; - ctx.curmethod <- old_meth; - tf(); - block(); - | TIf (cond,e,None) -> - if retval then assert false; - gen_expr ctx true cond; - write ctx ANot; - let j = cjmp ctx in - gen_expr ctx retval e; - j() - | TIf (cond,e,Some e2) -> - gen_expr ctx true cond; - let j = cjmp ctx in - gen_expr ctx retval e2; - let jend = jmp ctx in - j(); - gen_expr ctx retval e; - if retval then ctx.stack_size <- ctx.stack_size - 1; - jend() - | TWhile (cond,e,Ast.NormalWhile) -> - let loop_end = begin_loop ctx in - let cont_pos = ctx.code_pos in - let loop = pos ctx in - gen_expr ctx true cond; - write ctx ANot; - let jend = cjmp ctx in - gen_expr ctx false e; - loop false; - jend(); - loop_end cont_pos - | TWhile (cond,e,Ast.DoWhile) -> - let loop_end = begin_loop ctx in - let p = pos ctx in - gen_expr ctx false e; - let cont_pos = ctx.code_pos in - gen_expr ctx true cond; - p true; - loop_end cont_pos - | TReturn None -> - pop ctx (ctx.stack_size - ctx.fun_stack) false; - write ctx (APush [PUndefined]); - write ctx AReturn; - no_value ctx retval - | TReturn (Some e) -> - pop ctx (ctx.stack_size - ctx.fun_stack) false; - gen_expr ctx true e; - write ctx AReturn; - no_value ctx retval - | TBreak -> - pop ctx (ctx.stack_size - ctx.loop_stack) false; - ctx.breaks <- jmp ctx :: ctx.breaks; - no_value ctx retval - | TContinue -> - pop ctx (ctx.stack_size - ctx.loop_stack) false; - ctx.continues <- jmp_pos ctx false :: ctx.continues; - no_value ctx retval - | TCall (e,el) -> - gen_call ctx e el - | TNew (c,_,el) -> - let nargs = List.length el in - List.iter (gen_expr ctx true) (List.rev el); - push ctx [VInt nargs]; - let acc = gen_path ctx c.cl_path c.cl_extern in - new_call ctx acc nargs - | TSwitch (e,cases,def) -> - gen_switch ctx retval e cases def - | TThrow e -> - gen_expr ctx true e; - write ctx AThrow; - no_value ctx retval - | TTry (e,catchs) -> - gen_try_catch ctx retval e catchs - | TBinop (op,e1,e2) -> - gen_binop ctx retval op e1 e2 - | TUnop (op,flag,e) -> - gen_unop ctx retval op flag e - | TCast (e,None) -> - gen_expr ctx retval e - | TCast (e1,Some t) -> - gen_expr ctx retval (Codegen.default_cast ctx.com e1 t e.etype e.epos) - | TMatch (e,_,cases,def) -> - gen_match ctx retval e cases def - | TFor (v,it,e) -> - gen_expr ctx true it; - let r = alloc_tmp ctx in - set_tmp ctx r; - write ctx APop; - let loop_end = begin_loop ctx in - let cont_pos = ctx.code_pos in - let j_begin = pos ctx in - push ctx [VInt 0]; - get_tmp ctx r; - push ctx [VStr ("hasNext",false)]; - call ctx VarObj 0; - write ctx ANot; - let j_end = cjmp ctx in - let b = open_block ctx in - define_var ctx v (Some (fun() -> - push ctx [VInt 0]; - get_tmp ctx r; - push ctx [VStr ("next",false)]; - call ctx VarObj 0; - )); - gen_expr ctx false e; - j_begin false; - j_end(); - loop_end cont_pos; - if retval then getvar ctx (access_local ctx v.v_name); - b(); - free_tmp ctx r null_pos - -and gen_expr ctx retval e = - let old = ctx.stack_size in - gen_expr_2 ctx retval e; - if old <> ctx.stack_size then begin - if old + 1 <> ctx.stack_size then stack_error e.epos; - if not retval then write ctx APop; - end else if retval then stack_error e.epos - -let gen_class_static_field ctx c flag f = - match f.cf_expr with - | None -> - push ctx [VReg 0; VStr (f.cf_name,flag); VNull]; - setvar ctx VarObj - | Some e -> - match e.eexpr with - | TFunction _ -> - push ctx [VReg 0; VStr (f.cf_name,flag)]; - ctx.curmethod <- (f.cf_name,false); - gen_expr ctx true e; - setvar ctx VarObj - | _ -> - ctx.statics <- (c,flag,f.cf_name,e) :: ctx.statics - -let gen_class_static_init ctx (c,flag,name,e) = - ctx.curclass <- c; - ctx.curmethod <- (name,false); - getvar ctx (gen_path ctx c.cl_path c.cl_extern); - push ctx [VStr (name,flag)]; - gen_expr ctx true e; - setvar ctx VarObj - -let gen_class_field ctx flag f = - push ctx [VReg 1; VStr (f.cf_name,flag)]; - (match f.cf_expr with - | None -> - push ctx [VNull] - | Some e -> - ctx.curmethod <- (f.cf_name,false); - gen_expr ctx true e); - setvar ctx VarObj - -let gen_enum_field ctx e f = - push ctx [VReg 0; VStr (f.ef_name,false)]; - (match follow f.ef_type with - | TFun (args,r) -> - ctx.regs <- PMap.empty; - ctx.reg_count <- 1; - let no_reg = ctx.flash6 in - let rargs = List.map (fun (n,_,_) -> if no_reg then 0, n else alloc_reg ctx , "") args in - let nregs = List.length rargs + 2 in - let tf = begin_func ctx false false rargs in - List.iter (fun (r,name) -> - if no_reg then begin - push ctx [VStr (name,false)]; - write ctx AEval; - end else - push ctx [VReg r] - ) (List.rev rargs); - push ctx [VInt f.ef_index; VStr (f.ef_name,false)]; - init_array ctx nregs; - write ctx ADup; - write ctx ADup; - push ctx [VStr ("__enum__",false); VThis]; - write ctx AObjSet; - push ctx [VStr ("toString",false); VStr ("@estr",false)]; - write ctx AEval; - write ctx AObjSet; - write ctx AReturn; - tf(); - | t -> - push ctx [VInt f.ef_index; VStr (f.ef_name,false)]; - init_array ctx 2; - write ctx ADup; - write ctx ADup; - push ctx [VStr ("__enum__",false); VReg 0]; - write ctx AObjSet; - push ctx [VStr ("toString",false); VStr ("@estr",false)]; - write ctx AEval; - write ctx AObjSet; - ); - write ctx AObjSet - -let init_name ctx path enum = - push ctx [VReg 0; VStr ((if enum then "__ename__" else "__name__"),false)]; - let name = fst path @ [snd path] in - push ctx (List.map (fun s -> VStr (s,false)) (List.rev name)); - init_array ctx (List.length name); - setvar ctx VarObj - -let gen_package ctx path ext = - let rec loop acc = function - | [] -> () - | x :: l -> - let p = x :: acc in - if not (Hashtbl.mem ctx.packages p) then begin - (* create the package and copy the _global one if exists *) - Hashtbl.add ctx.packages p (); - - (* create the package *) - let path = (List.rev acc,x) in - let acc = gen_path ctx path false in - push ctx [VInt 0; VStr ("Object",true)]; - write ctx ANew; - write ctx (ASetReg 1); - setvar ctx acc; - - (* copy the content of the _global package if exists *) - getvar ctx (gen_path ctx ~protect:true ("_global" :: fst path,snd path) ext); - write ctx (ASetReg 2); - write ctx AEnum2; - ctx.stack_size <- ctx.stack_size + 1; (* fake *) - let back = pos ctx in - write ctx (ASetReg 0); - push ctx [VNull]; - write ctx AEqual; - let jend = cjmp ctx in - push ctx [VReg 1; VReg 0]; - push ctx [VReg 2; VReg 0]; - write ctx AObjGet; - write ctx AObjSet; - back false; - jend(); - - write ctx APop; - end; - loop p l - in - loop [] (fst path) - -let gen_type_def ctx t = - if ctx.ident_size > 50000 then segment ctx; - match t with - | TClassDecl c -> - (match c.cl_init with - | None -> () - | Some e -> ctx.inits <- e :: ctx.inits); - gen_package ctx c.cl_path c.cl_extern; - if c.cl_extern then - () - else - let have_constr = ref false in - if c.cl_path = (["flash"] , "Boot") then ctx.extern_boot <- false; - let acc = gen_path ctx c.cl_path false in - let rec loop s = - match s.cl_super with - | None -> () - | Some (s,_) -> - if s.cl_path = (["flash"],"MovieClip") then - ctx.movieclips <- c.cl_path :: ctx.movieclips - else - loop s - in - loop c; - ctx.curclass <- c; - (match c.cl_constructor with - | Some { cf_expr = Some e } -> - have_constr := true; - ctx.curmethod <- ("new",false); - gen_expr ctx true e - | _ -> - let f = begin_func ctx true false [] in - f()); - write ctx (ASetReg 0); - setvar ctx acc; - init_name ctx c.cl_path false; - (match c.cl_super with - | None -> () - | Some (csuper,_) -> - let path = (match csuper.cl_path with (["flash"],x) when csuper.cl_extern -> (["_global"],x) | p -> p) in - push ctx [VReg 0; VStr ("__super__",false)]; - getvar ctx (gen_path ctx path csuper.cl_extern); - setvar ctx VarObj; - if ctx.flash6 then begin - (* myclass.prototype.__proto__ = superclass.prototype *) - push ctx [VReg 0; VStr ("prototype",true)]; - getvar ctx VarObj; - push ctx [VStr ("__proto__",true)]; - getvar ctx (gen_path ctx path csuper.cl_extern); - push ctx [VStr ("prototype",true)]; - getvar ctx VarObj; - setvar ctx VarObj; - (* myclass.prototype.__constructor__ = superclass *) - push ctx [VReg 0; VStr ("prototype",true)]; - getvar ctx VarObj; - push ctx [VStr ("__constructor__",true)]; - getvar ctx (gen_path ctx path csuper.cl_extern); - setvar ctx VarObj - end else begin - push ctx [VReg 0]; - getvar ctx (gen_path ctx path csuper.cl_extern); - write ctx AExtends; - end; - ); - (match c.cl_implements with - | [] -> () - | l -> - let nimpl = List.length l in - push ctx [VReg 0; VStr ("__interfaces__",false)]; - List.iter (fun (c,_) -> getvar ctx (gen_path ctx c.cl_path c.cl_extern)) l; - init_array ctx nimpl; - setvar ctx VarObj; - if not ctx.flash6 then begin - List.iter (fun (c,_) -> getvar ctx (gen_path ctx c.cl_path c.cl_extern)) l; - push ctx [VInt nimpl; VReg 0]; - write ctx AImplements; - ctx.stack_size <- ctx.stack_size - nimpl; - end); - push ctx [VReg 0; VStr ("prototype",true)]; - getvar ctx VarObj; - write ctx (ASetReg 1); - write ctx APop; - push ctx [VReg 1; VStr ("__class__",false); VReg 0]; - setvar ctx VarObj; - (* true if implements mt.Protect *) - let flag = is_protected ctx ~stat:true (TInst (c,[])) "" in - if (Common.has_feature ctx.com "Reflect.getProperty") || (Common.has_feature ctx.com "Reflect.setProperty") then - Codegen.add_property_field ctx.com c; - List.iter (fun f -> if not (is_extern_field f) then gen_class_static_field ctx c flag f) c.cl_ordered_statics; - let flag = is_protected ctx (TInst (c,[])) "" in - PMap.iter (fun _ f -> if not (is_extern_field f) then gen_class_field ctx flag f) c.cl_fields; - | TEnumDecl e when e.e_extern -> - () - | TEnumDecl e -> - gen_package ctx e.e_path e.e_extern; - let acc = gen_path ctx e.e_path false in - push ctx [VInt 0; VStr ("Object",true)]; - write ctx ANew; - write ctx (ASetReg 0); - setvar ctx acc; - init_name ctx e.e_path true; - push ctx [VReg 0; VStr ("__constructs__",true)]; - List.iter (fun s -> push ctx [VStr (s,false)]) (List.rev e.e_names); - init_array ctx (List.length e.e_names); - write ctx AObjSet; - (match Codegen.build_metadata ctx.com t with - | None -> () - | Some e -> - push ctx [VReg 0; VStr ("__meta__",true)]; - gen_expr ctx true e; - write ctx AObjSet; - ); - PMap.iter (fun _ f -> gen_enum_field ctx e f) e.e_constrs - | TTypeDecl _ | TAbstractDecl _ -> - () - -let gen_boot ctx = - (* r0 = Boot *) - getvar ctx (gen_path ctx (["flash"],"Boot") ctx.extern_boot); - write ctx (ASetReg 0); - write ctx APop; - (* r0.__init(eval("this")) *) - push ctx [VStr ("this",true)]; - write ctx AEval; - push ctx [VInt 1; VReg 0; VStr ("__init",false)]; - call ctx VarObj 0; - write ctx APop - -let gen_movieclip ctx m = - getvar ctx (gen_path ctx m false); - push ctx [VStr (s_type_path m,true); VInt 2; VStr ("Object",true)]; - write ctx AEval; - push ctx [VStr ("registerClass",true)]; - call ctx VarObj 2; - write ctx APop - -let to_utf8 str = - try - UTF8.validate str; - str; - with - UTF8.Malformed_code -> - let b = UTF8.Buf.create 0 in - String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str; - UTF8.Buf.contents b - -let build_tag (opcodes,idents) = - let idents = Hashtbl.fold (fun ident pos acc -> (ident,pos) :: acc) idents [] in - let idents = List.sort (fun (_,p1) (_,p2) -> compare p1 p2) idents in - let pidents = List.map (fun ((_,flag),_) -> flag) idents in - let idents = AStringPool (List.map (fun ((id,_),_) -> to_utf8 id) idents) in - if ActionScript.action_length idents >= 1 lsl 16 then failwith "The SWF can't handle more than a total size of 64K of identifers and literal strings. Try reducing this number by using external data files loaded at runtime"; - DynArray.set opcodes 0 idents; - TDoAction opcodes , pidents - -let convert_header ctx ver (w,h,fps,bg) = - { - h_version = ver; - h_size = { - rect_nbits = if (max w h) >= 820 then 16 else 15; - left = 0; - top = 0; - right = w * 20; - bottom = h * 20; - }; - h_frame_count = 1; - h_fps = to_float16 (if fps > 127.0 then 127.0 else fps); - h_compressed = not (Common.defined ctx Define.NoSwfCompress); - } , bg - -let default_header ctx ver = - convert_header ctx ver (400,300,30.,0xFFFFFF) - -let generate com = - let ctx = { - com = com; - stack = Codegen.stack_init com true; - flash6 = com.flash_version = 6.; - segs = []; - opcodes = DynArray.create(); - code_pos = 0; - stack_size = 0; - ident_count = 0; - ident_size = 0; - opt_push = false; - idents = Hashtbl.create 0; - packages = Hashtbl.create 0; - regs = PMap.empty; - reg_count = 0; - reg_max = 0; - breaks = []; - continues = []; - loop_stack = 0; - fun_stack = 0; - statics = []; - movieclips = []; - inits = []; - curclass = null_class; - curmethod = ("",false); - fun_pargs = []; - in_loop = false; - static_init = false; - extern_boot = true; - } in - write ctx (AStringPool []); - protect_all := not (Common.defined com Define.SwfMark); - if com.debug then begin - push ctx [VStr (ctx.stack.Codegen.stack_var,false); VInt 0]; - write ctx AInitArray; - write ctx ASet; - push ctx [VStr (ctx.stack.Codegen.stack_exc_var,false); VInt 0]; - write ctx AInitArray; - write ctx ASet; - end; - (* ----- @estr = function() { return flash.Boot.__string_rec(this,""); } ---- *) - push ctx [VStr ("@estr",false)]; - ctx.reg_count <- 1; - let f = begin_func ctx false false [] in - push ctx [VStr ("xx",false); VThis; VInt 2]; - getvar ctx (gen_path ctx (["flash"],"Boot") false); - push ctx [VStr ("__string_rec",false)]; - call ctx VarObj 2; - write ctx AReturn; - f(); - write ctx ASet; - ctx.reg_count <- 0; - (* ---- *) - List.iter (fun t -> gen_type_def ctx t) com.types; - gen_boot ctx; - List.iter (fun m -> gen_movieclip ctx m) ctx.movieclips; - ctx.static_init <- true; - List.iter (gen_expr ctx false) (List.rev ctx.inits); - let global_try = gen_try ctx in - List.iter (gen_class_static_init ctx) (List.rev ctx.statics); - (match com.main with - | None -> () - | Some e -> gen_expr ctx false e); - ctx.static_init <- false; - let end_try = global_try() in - (* flash.Boot.__trace(exc) *) - push ctx [VReg 0; VInt 1]; - getvar ctx (gen_path ctx (["flash"],"Boot") ctx.extern_boot); - push ctx [VStr ("__exc",false)]; - call ctx VarObj 1; - write ctx APop; - end_try(); - let segs = List.rev ((ctx.opcodes,ctx.idents) :: ctx.segs) in - let tags = List.map build_tag segs in - if Common.defined com Define.SwfMark then begin - if List.length segs > 1 then assert false; - let pidents = snd (List.hd tags) in - let ch = IO.output_channel (open_out_bin (Filename.chop_extension com.file ^ ".mark")) in - IO.write_i32 ch (List.length ctx.fun_pargs); - List.iter (fun (id,l) -> - IO.write_i32 ch id; - IO.write_i32 ch (List.length l); - List.iter (fun f -> IO.write_byte ch (if f then 1 else 0)) l; - ) ctx.fun_pargs; - IO.write_i32 ch (List.length pidents); - List.iter (fun f -> IO.write_byte ch (if f then 1 else 0)) pidents; - IO.close_out ch; - end; - List.map fst tags , ctx.movieclips diff --git a/genswf9.ml b/genswf9.ml index 1df47b7535f39bea3b70a6ec64060763abbccba2..1d3bf9f3c102db40d0e094dc99216ff23aa02528 100644 --- a/genswf9.ml +++ b/genswf9.ml @@ -104,6 +104,12 @@ type context = { mutable for_call : bool; } +let rec follow t = match Type.follow t with + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + follow (Abstract.get_underlying_type a tl) + | t -> + t + let invalid_expr p = error "Invalid expression" p let stack_error p = error "Stack error" p @@ -119,7 +125,7 @@ let is_special_compare e1 e2 = | TConst TNull, _ | _ , TConst TNull -> None | _ -> match follow e1.etype, follow e2.etype with - | TInst ({ cl_path = [],"Xml" } as c,_) , _ | _ , TInst ({ cl_path = [],"Xml" } as c,_) -> Some c + | TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c | _ -> None let write ctx op = @@ -193,20 +199,16 @@ let rec follow_basic t = | TAbstract ({ a_path = ([],"Float") },[]) | TAbstract ({ a_path = [],"UInt" },[]) | TAbstract ({ a_path = ([],"Bool") },[]) - | TInst ({ cl_path = (["haxe"],"Int32") },[]) - | TInst ({ cl_path = ([],"Int") },[]) - | TInst ({ cl_path = ([],"Float") },[]) - | TType ({ t_path = [],"UInt" },[]) - | TEnum ({ e_path = ([],"Bool") },[]) -> t + | TInst ({ cl_path = (["haxe"],"Int32") },[]) -> t | t -> t) | TType ({ t_path = ["flash";"utils"],"Object" },[]) | TType ({ t_path = ["flash";"utils"],"Function" },[]) | TType ({ t_path = [],"UInt" },[]) -> t | TType (t,tl) -> - follow_basic (apply_params t.t_types tl t.t_type) - | TAbstract (a,pl) when a.a_impl <> None -> - follow_basic (apply_params a.a_types pl a.a_this) + follow_basic (apply_params t.t_params tl t.t_type) + | TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> + follow_basic (apply_params a.a_params pl a.a_this) | _ -> t let rec type_id ctx t = @@ -233,7 +235,7 @@ let rec type_id ctx t = type_path ctx ([],"Function") | TType ({ t_path = ([],"UInt") as path },_) -> type_path ctx path - | TEnum ({ e_path = [],"XmlType"; e_extern = true },_) -> + | TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) -> HMPath ([],"String") | TEnum (e,_) -> let rec loop = function @@ -265,7 +267,7 @@ let classify ctx t = KBool | TAbstract ({ a_path = [],"Void" },_) | TEnum ({ e_path = [],"Void" },_) -> KDynamic - | TEnum ({ e_path = [],"XmlType"; e_extern = true },_) -> + | TEnum ({ e_path = ["flash"],"XmlType"; e_extern = true },_) -> KType (HMPath ([],"String")) | TEnum (e,_) -> let rec loop = function @@ -315,6 +317,7 @@ let property ctx p t = | TInst ({ cl_path = [],"Array" },_) -> (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" -> ident p , None, true | _ -> as3 p, None, false); | TInst ({ cl_path = ["flash"],"Vector" },_) -> @@ -326,9 +329,14 @@ let property ctx p t = | TInst ({ cl_path = [],"String" },_) -> (match p with | "length" (* Int in AS3/Haxe *) -> ident p, None, false + | "charCodeAt" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true | "charCodeAt" (* use Haxe version *) -> ident p, None, true | "cca" -> as3 "charCodeAt", None, false | _ -> as3 p, None, false); + | TInst ({ cl_path = [],"Date" },_) -> + (match p with + | "toString" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true + | _ -> ident p, None, false) | TAnon a -> (match !(a.a_status) with | Statics { cl_path = [], "Math" } -> @@ -342,7 +350,7 @@ let property ctx p t = (* cast type when accessing an extension field *) (try let f = PMap.find p c.cl_fields in - ident p, Some (classify ctx (apply_params c.cl_types params f.cf_type)), false + ident p, Some (classify ctx (apply_params c.cl_params params f.cf_type)), false with Not_found -> ident p, None, false) | TInst ({ cl_interface = true } as c,_) -> @@ -350,7 +358,7 @@ let property ctx p t = let rec loop c = try (match PMap.find p c.cl_fields with - | { cf_kind = Var _ } -> raise Exit (* no vars in interfaces in swf9 *) + | { cf_kind = Var _ | Method MethDynamic } -> raise Exit (* no vars in interfaces in swf9 *) | _ -> c) with Not_found -> let rec loop2 = function @@ -619,6 +627,16 @@ let debug_infos ?(is_min=true) ctx p = end end +let to_utf8 str = + try + UTF8.validate str; + str; + with + UTF8.Malformed_code -> + let b = UTF8.Buf.create 0 in + String.iter (fun c -> UTF8.Buf.add_char b (UChar.of_char c)) str; + UTF8.Buf.contents b + let gen_constant ctx c t p = match c with | TInt i -> @@ -632,7 +650,7 @@ let gen_constant ctx c t p = let f = float_of_string f in write ctx (HFloat f); | TString s -> - write ctx (HString (Genswf8.to_utf8 s)); + write ctx (HString (to_utf8 s)); | TBool b -> write ctx (if b then HTrue else HFalse); | TNull -> @@ -747,15 +765,20 @@ let begin_fun ctx args tret el stat p = ignore(alloc_reg ctx (classify ctx v.v_type))); let dparams = (match !dparams with None -> None | Some l -> Some (List.rev l)) in + let is_not_rethrow (_,e) = + match e.eexpr with + | TBlock [{ eexpr = TThrow { eexpr = TNew (_,_,[]) } }] -> false + | _ -> true + in let rec loop_try e = match e.eexpr with | TFunction _ -> () - | TTry _ -> raise Exit + | TTry (_,catches) when List.exists is_not_rethrow catches -> raise Exit | _ -> Type.iter loop_try e in ctx.try_scope_reg <- (try List.iter loop_try el; None with Exit -> Some (alloc_reg ctx KDynamic)); (fun () -> - let hasblock = ctx.block_vars <> [] || ctx.trys <> [] in + let hasblock = ctx.block_vars <> [] || ctx.try_scope_reg <> None in let code = DynArray.to_list ctx.code in let extra = ( if hasblock then begin @@ -862,8 +885,13 @@ let rec gen_access ctx e (forset : 'a) : 'a access = let id, _, _ = property ctx f e1.etype in write ctx HThis; VSuper id - | TField (e1,f) -> - let f = field_name f in + | TEnumParameter (e1,_,i) -> + gen_expr ctx true e1; + write ctx (HGetProp (ident "params")); + write ctx (HSmallInt i); + VArray + | TField (e1,fa) -> + let f = field_name fa in let id, k, closure = property ctx f e1.etype in if closure && not ctx.for_call then error "In Flash9, this method cannot be accessed this way : please define a local function" e1.epos; (match e1.eexpr with @@ -877,9 +905,15 @@ let rec gen_access ctx e (forset : 'a) : 'a access = | _ , TFun _ when not ctx.for_call -> VCast(id,classify ctx e.etype) | TEnum _, _ -> VId id | TInst (_,tl), et -> + let is_type_parameter_field = match fa with + | FInstance(_,_,cf) -> + (match follow cf.cf_type with TInst({cl_kind = KTypeParameter _},_) -> true | _ -> false) + | _ -> + List.exists (fun t -> follow t == et) tl + in (* if the return type is one of the type-parameters, then we need to cast it *) - if List.exists (fun t -> follow t == et) tl then - VCast (id, classify ctx et) + if is_type_parameter_field then + VCast (id, classify ctx e.etype) else if Codegen.is_volatile e.etype then VVolatile (id,None) else @@ -981,19 +1015,21 @@ let rec gen_expr_content ctx retval e = gen_constant ctx c e.etype e.epos | TThrow e -> ctx.infos.icond <- true; - getvar ctx (VGlobal (type_path ctx (["flash"],"Boot"))); - let id = type_path ctx (["flash";"errors"],"Error") in - write ctx (HFindPropStrict id); - write ctx (HConstructProperty (id,0)); - setvar ctx (VId (ident "lastError")) None; + if has_feature ctx.com "haxe.CallStack.exceptionStack" then begin + getvar ctx (VGlobal (type_path ctx (["flash"],"Boot"))); + let id = type_path ctx (["flash";"errors"],"Error") in + write ctx (HFindPropStrict id); + write ctx (HConstructProperty (id,0)); + setvar ctx (VId (ident "lastError")) None; + end; gen_expr ctx true e; write ctx HThrow; no_value ctx retval; - | TParenthesis e -> + | TParenthesis e | TMeta (_,e) -> gen_expr ctx retval e | TObjectDecl fl -> List.iter (fun (name,e) -> - write ctx (HString name); + write ctx (HString (reserved name)); gen_expr ctx true e ) fl; write ctx (HObject (List.length fl)) @@ -1013,16 +1049,14 @@ let rec gen_expr_content ctx retval e = let b = open_block ctx retval in loop el; b(); - | TVars vl -> - List.iter (fun (v,ei) -> - define_local ctx v e.epos; - (match ei with - | None -> () - | Some e -> - let acc = gen_local_access ctx v e.epos Write in - gen_expr ctx true e; - setvar ctx acc None) - ) vl + | TVar (v,ei) -> + define_local ctx v e.epos; + (match ei with + | None -> () + | Some e -> + let acc = gen_local_access ctx v e.epos Write in + gen_expr ctx true e; + setvar ctx acc None) | TReturn None -> write ctx HRetVoid; ctx.infos.icond <- true; @@ -1036,7 +1070,8 @@ let rec gen_expr_content ctx retval e = | TLocal _ | TTypeExpr _ -> getvar ctx (gen_access ctx e Read) - | TArray _ -> + (* both accesses return dynamic so let's cast them to the real type *) + | TEnumParameter _ | TArray _ -> getvar ctx (gen_access ctx e Read); coerce ctx (classify ctx e.etype) | TBinop (op,e1,e2) -> @@ -1114,8 +1149,11 @@ let rec gen_expr_content ctx retval e = if ctx.infos.imax < ctx.infos.istack then ctx.infos.imax <- ctx.infos.istack; write ctx HThis; write ctx HScope; - write ctx (HReg (match ctx.try_scope_reg with None -> assert false | Some r -> r.rid)); - write ctx HScope; + (match ctx.try_scope_reg with + | None -> () + | Some r -> + write ctx (HReg r.rid); + 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 @@ -1136,7 +1174,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 then begin + if has_call && has_feature ctx.com "haxe.CallStack.exceptionStack" 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 @@ -1203,7 +1241,7 @@ let rec gen_expr_content ctx retval e = let rec get_int e = match e.eexpr with | TConst (TInt n) -> if n < 0l || n > 512l then raise Exit; Int32.to_int n - | TParenthesis e | TBlock [e] -> get_int e + | TParenthesis e | TBlock [e] | TMeta (_,e) -> get_int e | _ -> raise Not_found in List.iter (fun (vl,_) -> List.iter (fun v -> @@ -1273,58 +1311,6 @@ let rec gen_expr_content ctx retval e = ); List.iter (fun j -> j()) jend; branch()); - | TMatch (e0,_,cases,def) -> - let t = classify ctx e.etype in - let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in - let has_params = List.exists (fun (_,p,_) -> p <> None) cases in - gen_expr ctx true e0; - if has_params then begin - write ctx HDup; - write ctx (HGetProp (ident "params")); - set_reg ctx rparams; - end; - write ctx (HGetProp (ident "index")); - write ctx HToInt; - let switch,case = begin_switch ctx in - (match def with - | None -> - if retval then begin - write ctx HNull; - coerce ctx t; - end; - | Some e -> - gen_expr ctx retval e; - if retval && classify ctx e.etype <> t then coerce ctx t); - let jends = List.map (fun (cl,params,e) -> - let j = jump ctx J3Always in - List.iter case cl; - pop_value ctx retval; - let b = open_block ctx retval in - (match params with - | None -> () - | Some l -> - let p = ref (-1) in - List.iter (fun v -> - incr p; - match v with - | None -> () - | Some v -> - define_local ctx v e.epos; - let acc = gen_local_access ctx v e.epos Write in - write ctx (HReg rparams.rid); - write ctx (HSmallInt !p); - getvar ctx VArray; - setvar ctx acc None - ) l - ); - gen_expr ctx retval e; - b(); - if retval && classify ctx e.etype <> t then coerce ctx t; - j - ) cases in - switch(); - List.iter (fun j -> j()) jends; - free_reg ctx rparams | TCast (e1,t) -> gen_expr ctx retval e1; if retval then begin @@ -1344,8 +1330,17 @@ let rec gen_expr_content ctx retval e = | KType n when (match n with HMPath ([],"String") -> false | _ -> true) -> (* for normal classes, we can use native cast *) write ctx (HCast tid) + | KInt | KUInt -> + (* allow any number to be cast to int (will coerce) *) + write ctx HDup; + write ctx (HIsType (HMPath([],"Number"))); + let j = jump ctx J3True in + write ctx (HString "Class cast error"); + write ctx HThrow; + j(); + write ctx (HCast tid) | _ -> - (* we need to check with "is" first *) + (* we need to check with "is" first, to prevent convertion *) write ctx HDup; write ctx (HIsType tid); let j = jump ctx J3True in @@ -1361,6 +1356,11 @@ 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] -> + (* fast inlining of Std.is with known values *) + gen_expr ctx true e; + gen_expr ctx true t; + write ctx (HOp A3OIs) | TLocal { v_name = "__as__" }, [e;t] -> gen_expr ctx true e; gen_expr ctx true t; @@ -1601,7 +1601,10 @@ and gen_binop ctx retval op e1 e2 t p = let k1 = classify ctx e1.etype in let k2 = classify ctx e2.etype in (match k1, k2 with - | KInt, KInt | KUInt, KUInt | KInt, KUInt | KUInt, KInt -> write ctx (HOp iop) + | KInt, KInt | KUInt, KUInt | KInt, KUInt | KUInt, KInt -> + write ctx (HOp iop); + let ret = classify ctx t in + if ret <> KInt then coerce ctx ret | _ -> write ctx (HOp op); (* add is a generic operation, so let's make sure we don't loose our type in the process *) @@ -1653,10 +1656,15 @@ and gen_binop ctx retval op e1 e2 t p = gen_expr ctx true e2; write_op op; setvar ctx wacc (if retval then Some (classify ctx e1.etype) else None) - | OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod -> + | OpAdd | OpMult | OpDiv | OpSub | OpAnd | OpOr | OpXor | OpMod -> gen_expr ctx true e1; gen_expr ctx true e2; write_op op + | OpShl | OpShr | OpUShr -> + gen_expr ctx true e1; + gen_expr ctx true e2; + write_op op; + coerce ctx (classify ctx e1.etype) | OpEq -> gen_eq() | OpNotEq -> @@ -1699,15 +1707,14 @@ and generate_function ctx fdata stat = | TReturn (Some e) -> let rec inner_loop e = match e.eexpr with - | TSwitch _ | TMatch _ | TFor _ | TWhile _ | TTry _ -> false + | TSwitch _ | TFor _ | TWhile _ | TTry _ -> false | TIf _ -> loop e - | TParenthesis e -> inner_loop e + | TParenthesis e | TMeta(_,e) -> inner_loop e | _ -> true in inner_loop e | TIf (_,e1,Some e2) -> loop e1 && loop e2 - | TSwitch (_,_,Some e) -> loop e - | TParenthesis e -> loop e + | TParenthesis e | TMeta(_,e) -> loop e | _ -> false in if not (loop fdata.tf_expr) then write ctx HRetVoid; @@ -1716,7 +1723,7 @@ and generate_function ctx fdata stat = and jump_expr_gen ctx e jif jfun = match e.eexpr with - | TParenthesis e -> jump_expr_gen ctx e jif jfun + | TParenthesis e | TMeta(_,e) -> jump_expr_gen ctx e jif jfun | TBinop (op,e1,e2) -> let j t f = check_binop ctx e1 e2; @@ -1800,7 +1807,7 @@ let rec is_const e = | TConst _ -> true | TArrayDecl el | TBlock el -> List.for_all is_const el | TObjectDecl fl -> List.for_all (fun (_,e) -> is_const e) fl - | TParenthesis e -> is_const e + | TParenthesis e | TMeta(_,e) -> is_const e | TFunction _ -> true | _ -> false @@ -1897,36 +1904,29 @@ let generate_enum_init ctx e hc meta = write ctx (HGetLex (type_path ctx path)); write ctx (HClassDef hc); write ctx HPopScope; - let r = alloc_reg ctx KDynamic in - write ctx HDup; - write ctx (HSetReg r.rid); (* needed for setslot *) write ctx (HInitProp name_id); - let nslot = ref 0 in PMap.iter (fun _ f -> - incr nslot; match f.ef_type with | TFun _ -> () | _ -> - write ctx (HReg r.rid); + write ctx (HGetLex name_id); write ctx (HFindPropStrict name_id); write ctx (HString f.ef_name); write ctx (HInt f.ef_index); write ctx HNull; write ctx (HConstructProperty (name_id,3)); - write ctx (HSetSlot !nslot); + write ctx (HInitProp (ident f.ef_name)); ) e.e_constrs; - write ctx (HReg r.rid); + write ctx (HGetLex name_id); List.iter (fun n -> write ctx (HString n)) e.e_names; write ctx (HArray (List.length e.e_names)); - write ctx (HSetProp (ident "__constructs__")); - (match meta with + write ctx (HInitProp (ident "__constructs__")); + match meta with | None -> () | Some e -> - write ctx (HReg r.rid); + write ctx (HGetLex name_id); gen_expr ctx true e; - write ctx (HSetProp (ident "__meta__")); - ); - free_reg ctx r + write ctx (HInitProp (ident "__meta__")) let extract_meta meta = let rec loop = function @@ -1979,7 +1979,7 @@ let generate_field_kind ctx f c stat = Some (HFMethod { hlm_type = m; hlm_final = stat || (Meta.has Meta.Final f.cf_meta); - hlm_override = not stat && loop c name; + hlm_override = not stat && (loop c name || loop c f.cf_name); hlm_kind = kind; }) ); @@ -2008,6 +2008,23 @@ let generate_field_kind ctx f c stat = hlv_const = false; }) +let check_constructor ctx c f = + (* + check that we don't assign a super Float var before we call super() : will result in NaN + *) + let rec loop e = + Type.iter loop e; + match e.eexpr with + | TCall ({ eexpr = TConst TSuper },_) -> raise Exit + | TBinop (OpAssign,{ eexpr = TField({ eexpr = TConst TThis },FInstance (cc,_,cf)) },_) when c != cc && (match classify ctx cf.cf_type with KFloat | KDynamic -> true | _ -> false) -> + error "You cannot assign some super class vars before calling super() in flash, this will reset them to default value" e.epos + | _ -> () + in + try + loop f.tf_expr + with Exit -> + () + let generate_class ctx c = let name = type_path ctx c.cl_path in ctx.cur_class <- c; @@ -2030,6 +2047,7 @@ let generate_class ctx c = | Some { eexpr = TFunction fdata } -> let old = do_debug ctx f.cf_meta in let m = generate_construct ctx fdata c in + check_constructor ctx c fdata; old(); m | _ -> assert false @@ -2166,7 +2184,7 @@ let generate_class ctx c = let generate_enum ctx e meta = let name_id = type_path ctx e.e_path in let api = ctx.com.basic in - let f = begin_fun ctx [alloc_var "tag" api.tstring, None;alloc_var "index" api.tint, None;alloc_var "params" (mk_mono()), None] api.tvoid [ethis] false e.e_pos in + let f = begin_fun ctx [alloc_var "tag" api.tstring, None;alloc_var "index" api.tint, None;alloc_var "params" (api.tarray (mk_mono())), None] api.tvoid [ethis] false e.e_pos in let tag_id = ident "tag" in let index_id = ident "index" in let params_id = ident "params" in @@ -2187,8 +2205,10 @@ let generate_enum ctx e meta = write ctx (HCallProperty (ident "enum_to_string",1)); write ctx HRet; let tostring = f() in - let st_count = ref 0 in + let st_field_count = ref 0 in + let st_meth_count = ref 0 in let constrs = PMap.fold (fun f acc -> + let st_count = (match f.ef_type with TFun _ -> st_meth_count | _ -> st_field_count) in incr st_count; { hlf_name = ident f.ef_name; @@ -2220,10 +2240,10 @@ let generate_enum ctx e meta = let constrs = (match meta with | None -> constrs | Some _ -> - incr st_count; + incr st_field_count; { hlf_name = ident "__meta__"; - hlf_slot = !st_count; + hlf_slot = !st_field_count; hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; }; hlf_metas = None; } :: constrs @@ -2256,17 +2276,17 @@ let generate_enum ctx e meta = }; |]; hlc_static_construct = empty_method ctx e.e_pos; - hlc_static_fields = Array.of_list ({ + hlc_static_fields = Array.of_list (List.rev ({ hlf_name = ident "__isenum"; - hlf_slot = !st_count + 2; + hlf_slot = !st_field_count + 2; hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Boolean")); hlv_value = HVBool true; hlv_const = true; }; hlf_metas = None; } :: { hlf_name = ident "__constructs__"; - hlf_slot = !st_count + 1; - hlf_kind = HFVar { hlv_type = None; hlv_value = HVNone; hlv_const = false; }; + hlf_slot = !st_field_count + 1; + hlf_kind = HFVar { hlv_type = Some (HMPath ([],"Array")); hlv_value = HVNone; hlv_const = false; }; hlf_metas = None; - } :: constrs); + } :: constrs)); } let rec generate_type ctx t = diff --git a/genxml.ml b/genxml.ml index 665052f2c18c2d4bb556aae791390312ab6ab663..34d86dbafaec6172487807bc9c6f43e5f7314363 100644 --- a/genxml.ml +++ b/genxml.ml @@ -23,6 +23,7 @@ open Ast open Type open Common +open ExtString type xml = | Node of string * (string * string) list * xml list @@ -77,36 +78,51 @@ let rec follow_param t = | Some t -> follow_param t | _ -> t) | TType ({ t_path = [],"Null" } as t,tl) -> - follow_param (apply_params t.t_types tl t.t_type) + follow_param (apply_params t.t_params tl t.t_type) | _ -> t -let rec sexpr (e,_) = - match e with - | EConst c -> s_constant c - | EParenthesis e -> "(" ^ (sexpr e) ^ ")" - | EArrayDecl el -> "[" ^ (String.concat "," (List.map sexpr el)) ^ "]" - | EObjectDecl fl -> "{" ^ (String.concat "," (List.map (fun (n,e) -> n ^ ":" ^ (sexpr e)) fl)) ^ "}" - | _ -> "'???'" - let gen_meta meta = let meta = List.filter (fun (m,_,_) -> match m with Meta.Used | Meta.MaybeUsed | Meta.RealPath -> false | _ -> true) meta in match meta with | [] -> [] | _ -> let nodes = List.map (fun (m,el,_) -> - node "m" ["n",fst (MetaInfo.to_string m)] (List.map (fun e -> node "e" [] [gen_string (sexpr e)]) el) + node "m" ["n",fst (MetaInfo.to_string m)] (List.map (fun e -> node "e" [] [gen_string (Ast.s_expr e)]) el) ) meta in [node "meta" [] nodes] -let rec gen_type t = +let rec gen_type ?(values=None) t = match t with | TMono m -> (match !m 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 | TType (t,params) -> gen_type_decl "t" (TTypeDecl t) params - | TFun (args,r) -> node "f" ["a",String.concat ":" (List.map gen_arg_name args)] (List.map gen_type (List.map (fun (_,opt,t) -> if opt then follow_param t else t) args @ [r])) + | TFun (args,r) -> + let names = String.concat ":" (List.map gen_arg_name args) in + let values = match values with + | None -> [] + | Some values -> + let has_value = ref false in + let values = List.map (fun (n,_,_) -> + try + let e = PMap.find n values in + has_value := true; + let s = Ast.s_expr e in + s + with Not_found -> + "" + ) args in + if !has_value then + ["v",String.concat ":" values] + else + [] + in + let args = List.map (fun (_,opt,t) -> + if opt then follow_param t else t + ) args in + node "f" (("a",names) :: values) (List.map gen_type (args @ [r])) | TAnon a -> node "a" [] (pmap (fun f -> gen_field [] { f with cf_public = false }) a.a_fields) | TDynamic t2 -> node "d" [] (if t == t2 then [] else [gen_type t2]) | TLazy f -> gen_type (!f()) @@ -124,16 +140,40 @@ and gen_field att f = | AccInline -> (name,"inline") :: att in let att = (match f.cf_expr with None -> att | Some e -> ("line",string_of_int (Lexer.get_error_line e.epos)) :: att) in - let att = (match f.cf_kind with - | Var v -> add_get_set v.v_read "get" (add_get_set v.v_write "set" att) + let att,values = (match f.cf_kind with + | Var v -> + let att = try + begin match Meta.get Meta.Value f.cf_meta with + | (_,[e],_) -> ("expr",Ast.s_expr e) :: att + | _ -> att + end + with Not_found -> + att + in + add_get_set v.v_read "get" (add_get_set v.v_write "set" att),PMap.empty | Method m -> - (match m with + let att = match m with | MethNormal | MethMacro -> ("set", "method") :: att | MethDynamic -> ("set", "dynamic") :: att - | MethInline -> ("get", "inline") :: ("set","null") :: att) + | MethInline -> ("get", "inline") :: ("set","null") :: att + in + att,get_value_meta f.cf_meta ) in let att = (match f.cf_params with [] -> att | l -> ("params", String.concat ":" (List.map (fun (n,_) -> n) l)) :: att) in - node f.cf_name (if f.cf_public then ("public","1") :: att else att) (gen_type f.cf_type :: gen_meta f.cf_meta @ gen_doc_opt f.cf_doc) + let overloads = match List.map (gen_field []) f.cf_overloads with + | [] -> [] + | nl -> [node "overloads" [] nl] + in + let field_name cf = + try + begin match Meta.get Meta.RealPath cf.cf_meta with + | _,[EConst (String (s)),_],_ -> s + | _ -> raise Not_found + end; + with Not_found -> + cf.cf_name + in + node (field_name f) (if f.cf_public then ("public","1") :: att else att) (gen_type ~values:(Some values) f.cf_type :: gen_meta f.cf_meta @ gen_doc_opt f.cf_doc @ overloads) let gen_constr e = let doc = gen_doc_opt e.ef_doc in @@ -144,7 +184,16 @@ let gen_constr e = | _ -> [] , doc ) in - node e.ef_name args t + node e.ef_name args (t @ gen_meta e.ef_meta) + +let gen_ordered_constr e = + let rec loop el = match el with + | n :: el -> + gen_constr (PMap.find n e.e_constrs) :: loop el + | [] -> + [] + in + loop e.e_names let gen_type_params ipos priv path params pos m = let mpriv = (if priv then [("private","1")] else []) in @@ -161,14 +210,20 @@ let rec exists f c = | None -> false | Some (csup,_) -> exists f csup -let gen_type_decl com pos t = +let rec gen_type_decl com pos t = let m = (t_infos t).mt_module in match t with | TClassDecl c -> - let stats = List.map (gen_field ["static","1"]) (List.filter (fun cf -> cf.cf_name <> "__meta__") c.cl_ordered_statics) in + let stats = List.filter (fun cf -> + cf.cf_name <> "__meta__" && not (Meta.has Meta.GenericInstance cf.cf_meta) + ) c.cl_ordered_statics in + let stats = List.map (gen_field ["static","1"]) stats in + let fields = List.filter (fun cf -> + not (Meta.has Meta.GenericInstance cf.cf_meta) + ) c.cl_ordered_fields in let fields = (match c.cl_super with - | None -> List.map (fun f -> f,[]) c.cl_ordered_fields - | Some (csup,_) -> List.map (fun f -> if exists f csup then (f,["override","1"]) else (f,[])) c.cl_ordered_fields + | None -> List.map (fun f -> f,[]) fields + | Some (csup,_) -> List.map (fun f -> if exists f csup then (f,["override","1"]) else (f,[])) fields ) in let fields = List.map (fun (f,att) -> gen_field att f) fields in let constr = (match c.cl_constructor with None -> [] | Some f -> [gen_field [] f]) in @@ -185,25 +240,32 @@ let gen_type_decl com pos t = | None -> [] | Some t -> [node "haxe_dynamic" [] [gen_type t]] ) in - node "class" (gen_type_params pos c.cl_private (tpath t) c.cl_types c.cl_pos m @ ext @ interf) (tree @ stats @ fields @ constr @ doc @ meta @ dynamic) + 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 @ dynamic) | TEnumDecl e -> let doc = gen_doc_opt e.e_doc in let meta = gen_meta e.e_meta in - node "enum" (gen_type_params pos e.e_private (tpath t) e.e_types e.e_pos m) (pmap gen_constr e.e_constrs @ doc @ meta) + node "enum" (gen_type_params pos e.e_private (tpath t) e.e_params e.e_pos m) (gen_ordered_constr e @ doc @ meta) | TTypeDecl t -> let doc = gen_doc_opt t.t_doc in let meta = gen_meta t.t_meta in let tt = gen_type t.t_type in - node "typedef" (gen_type_params pos t.t_private t.t_path t.t_types t.t_pos m) (tt :: doc @ meta) + node "typedef" (gen_type_params pos t.t_private t.t_path t.t_params t.t_pos m) (tt :: doc @ meta) | TAbstractDecl a -> let doc = gen_doc_opt a.a_doc in let meta = gen_meta a.a_meta in - let sub = (match a.a_from with [] -> [] | l -> [node "from" [] (List.map (fun (t,_) -> gen_type t) l)]) in - let super = (match a.a_to with [] -> [] | l -> [node "to" [] (List.map (fun (t,_) -> gen_type t) l)]) in - node "abstract" (gen_type_params pos a.a_private (tpath t) a.a_types a.a_pos m) (sub @ super @ doc @ meta) + let mk_cast t = node "icast" [] [gen_type t] in + let mk_field_cast (t,cf) = node "icast" ["field",cf.cf_name] [gen_type t] in + let sub = (match a.a_from,a.a_from_field with [],[] -> [] | l1,l2 -> [node "from" [] ((List.map mk_cast l1) @ (List.map mk_field_cast l2))]) in + let super = (match a.a_to,a.a_to_field with [],[] -> [] | l1,l2 -> [node "to" [] ((List.map mk_cast l1) @ (List.map mk_field_cast l2))]) in + let impl = (match a.a_impl with None -> [] | Some c -> [node "impl" [] [gen_type_decl com pos (TClassDecl c)]]) in + let this = [node "this" [] [gen_type a.a_this]] in + node "abstract" (gen_type_params pos a.a_private (tpath t) a.a_params a.a_pos m) (sub @ this @ super @ doc @ meta @ impl) + +let escape_entities s = + Xml.to_string (Xml.PCData s) let att_str att = - String.concat "" (List.map (fun (a,v) -> Printf.sprintf " %s=\"%s\"" a v) att) + String.concat "" (List.map (fun (a,v) -> Printf.sprintf " %s=\"%s\"" a (escape_entities v)) att) let rec write_xml ch tabs x = match x with @@ -257,9 +319,27 @@ let conv_path p = | x :: l when x.[0] = '_' -> List.rev (("priv" ^ x) :: l), snd p | _ -> p +let get_real_path meta path = + try + let real_path = match Meta.get Meta.RealPath meta with + | (_,[(EConst(String s),_)],_) -> + s + | _ -> raise Not_found + in + match List.rev (String.nsplit real_path ".") with + | name :: pack -> + (List.rev pack), name + | _ -> raise Not_found + with | Not_found -> + path + + let generate_type com t = let base_path = "hxclasses" in - let pack , name = conv_path (t_path t) in + let pack, name = + let info = t_infos t in + get_real_path info.mt_meta info.mt_path + in create_dir "." (base_path :: pack); match pack, name with | ["flash";"net"], "NetStreamPlayTransitions" @@ -283,8 +363,8 @@ let generate_type com t = | _ -> t in - let rec path p tl = - let p = conv_path p in + let rec path meta p tl = + let p = conv_path (get_real_path meta p) in (if fst p = pack then snd p else s_type_path p) ^ (match tl with [] -> "" | _ -> "<" ^ String.concat "," (List.map stype tl) ^ ">") and stype t = match t with @@ -293,15 +373,15 @@ let generate_type com t = | None -> "Unknown" | Some t -> stype t) | TInst ({ cl_kind = KTypeParameter _ } as c,tl) -> - path ([],snd c.cl_path) tl + path [] ([],snd c.cl_path) tl | TInst (c,tl) -> - path c.cl_path tl + path c.cl_meta c.cl_path tl | TEnum (e,tl) -> - path e.e_path tl + path e.e_meta e.e_path tl | TType (t,tl) -> - path t.t_path tl + path t.t_meta t.t_path tl | TAbstract (a,tl) -> - path a.a_path tl + path a.a_meta a.a_path tl | TAnon a -> let fields = PMap.fold (fun f acc -> (f.cf_name ^ " : " ^ stype f.cf_type) :: acc) a.a_fields [] in "{" ^ String.concat ", " fields ^ "}" @@ -331,33 +411,48 @@ let generate_type com t = | None -> n ^ " : " ^ stype t | Some (Ident "null") -> - "?" ^ n ^ " : " ^ stype (notnull t) + if is_nullable (notnull t) then + "?" ^ n ^ " : " ^ stype (notnull t) + else + (* we have not found a default value stored in metadata, let's generate it *) + n ^ " : " ^ stype t ^ " = " ^ (match follow t with + | TAbstract ({ a_path = [],("Int"|"Float"|"UInt") },_) -> "0" + | TAbstract ({ a_path = [],"Bool" },_) -> "false" + | _ -> "null") | Some v -> n ^ " : " ^ stype t ^ " = " ^ (match s_constant v with "nan" -> "0./*NaN*/" | v -> v) in let print_meta ml = List.iter (fun (m,pl,_) -> match m with - | Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.MaybeUsed -> () + | Meta.DefParam | Meta.CoreApi | Meta.Used | Meta.MaybeUsed | Meta.FlatEnum | Meta.Value | Meta.DirectlyUsed -> () | _ -> match pl with | [] -> p "@%s " (fst (MetaInfo.to_string m)) - | l -> p "@%s(%s) " (fst (MetaInfo.to_string m)) (String.concat "," (List.map sexpr pl)) + | l -> p "@%s(%s) " (fst (MetaInfo.to_string m)) (String.concat "," (List.map Ast.s_expr pl)) ) ml in - let access a = + let access is_read a = match a, pack with | AccNever, "flash" :: _ -> "null" - | _ -> s_access a + | _ -> s_access is_read a in - let print_field stat f = + let rec print_field stat f = p "\t"; print_meta f.cf_meta; if stat then p "static "; + let name = try (match Meta.get Meta.RealPath f.cf_meta with + | (Meta.RealPath, [EConst( String s ), _], _) -> + s + | _ -> + raise Not_found) + with Not_found -> + f.cf_name + in (match f.cf_kind with | Var v -> - p "var %s" f.cf_name; - if v.v_read <> AccNormal || v.v_write <> AccNormal then p "(%s,%s)" (access v.v_read) (access v.v_write); + p "var %s" name; + if v.v_read <> AccNormal || v.v_write <> AccNormal then p "(%s,%s)" (access true v.v_read) (access false v.v_write); p " : %s" (stype f.cf_type); | Method m -> let params, ret = (match follow f.cf_type with @@ -386,14 +481,15 @@ let generate_type com t = assert false ) in let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in - p "function %s%s(%s) : %s" f.cf_name tparams (String.concat ", " (List.map sparam params)) (stype ret); + p "function %s%s(%s) : %s" name tparams (String.concat ", " (List.map sparam params)) (stype ret); ); - p ";\n" + p ";\n"; + if Meta.has Meta.Overload f.cf_meta then List.iter (fun f -> print_field stat f) f.cf_overloads in (match t with | TClassDecl c -> print_meta c.cl_meta; - p "extern %s %s" (if c.cl_interface then "interface" else "class") (stype (TInst (c,List.map snd c.cl_types))); + p "extern %s %s" (if c.cl_interface then "interface" else "class") (stype (TInst (c,List.map snd c.cl_params))); let ext = (match c.cl_super with | None -> [] | Some (c,pl) -> [" extends " ^ stype (TInst (c,pl))] @@ -434,7 +530,7 @@ let generate_type com t = p "}\n"; | TEnumDecl e -> print_meta e.e_meta; - p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_types))); + p "extern enum %s {\n" (stype (TEnum(e,List.map snd e.e_params))); let sort l = let a = Array.of_list l in Array.sort compare a; @@ -451,12 +547,12 @@ let generate_type com t = p "}\n" | TTypeDecl t -> print_meta t.t_meta; - p "typedef %s = " (stype (TType (t,List.map snd t.t_types))); + p "typedef %s = " (stype (TType (t,List.map snd t.t_params))); p "%s" (stype t.t_type); p "\n"; | TAbstractDecl a -> print_meta a.a_meta; - p "abstract %s {}" (stype (TAbstract (a,List.map snd a.a_types))); + p "abstract %s {}" (stype (TAbstract (a,List.map snd a.a_params))); ); IO.close_out ch diff --git a/haxe.hxproj b/haxe.hxproj index 804af128ba59f95ab3362aa3b82962ce85477463..27bf5b5330ed57fed4797e25a2edfd6e86748d47 100644 --- a/haxe.hxproj +++ b/haxe.hxproj @@ -1,143 +1,166 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - make -j4 MSVC=1 FD_OUTPUT=1 -f Makefile.win kill haxe - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make -j4 MSVC=1 FD_OUTPUT=1 -f Makefile.win kill haxe + + + + + + + \ No newline at end of file diff --git a/interp.ml b/interp.ml index c13ae0a35bd871344987a9ed566e626f22d02eae..492b909bce8ef4e602203b5871bf34ec585e0315 100644 --- a/interp.ml +++ b/interp.ml @@ -1,4545 +1,5105 @@ -(* - * Copyright (C)2005-2013 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. - *) - -open Common -open Nast -open Unix -open Type - -(* ---------------------------------------------------------------------- *) -(* TYPES *) - -type value = - | VNull - | VBool of bool - | VInt of int - | VFloat of float - | VString of string - | VObject of vobject - | VArray of value array - | VAbstract of vabstract - | VFunction of vfunction - | VClosure of value list * (value list -> value list -> value) - | VInt32 of int32 - -and vobject = { - mutable ofields : (int * value) array; - mutable oproto : vobject option; -} - -and vabstract = - | AKind of vabstract - | AHash of (value, value) Hashtbl.t - | ARandom of Random.State.t ref - | ABuffer of Buffer.t - | APos of Ast.pos - | AFRead of in_channel - | AFWrite of out_channel - | AReg of regexp - | AZipI of zlib - | AZipD of zlib - | AUtf8 of UTF8.Buf.buf - | ASocket of Unix.file_descr - | ATExpr of texpr - | ATDecl of module_type - | AUnsafe of Obj.t - | ALazyType of (unit -> Type.t) ref - | ANekoAbstract of Extc.value - | ANekoBuffer of value - | ACacheRef of value - | AInt32Kind - -and vfunction = - | Fun0 of (unit -> value) - | Fun1 of (value -> value) - | Fun2 of (value -> value -> value) - | Fun3 of (value -> value -> value -> value) - | Fun4 of (value -> value -> value -> value -> value) - | Fun5 of (value -> value -> value -> value -> value -> value) - | FunVar of (value list -> value) - -and regexp = { - r : Str.regexp; - mutable r_string : string; - mutable r_groups : (int * int) option array; -} - -and zlib = { - z : Extc.zstream; - mutable z_flush : Extc.zflush; -} - -type cmp = - | CEq - | CSup - | CInf - | CUndef - -type extern_api = { - pos : Ast.pos; - get_com : unit -> Common.context; - get_type : string -> Type.t option; - get_module : string -> Type.t list; - on_generate : (Type.t list -> unit) -> unit; - on_type_not_found : (string -> value) -> unit; - parse_string : string -> Ast.pos -> bool -> Ast.expr; - typeof : Ast.expr -> Type.t; - get_display : string -> string; - allow_package : string -> unit; - type_patch : string -> string -> bool -> string option -> unit; - meta_patch : string -> string -> string option -> bool -> unit; - set_js_generator : (value -> unit) -> unit; - get_local_type : unit -> t option; - get_local_method : unit -> string; - get_local_using : unit -> tclass list; - get_local_vars : unit -> (string, Type.tvar) PMap.t; - get_build_fields : unit -> value; - get_pattern_locals : Ast.expr -> Type.t -> (string,Type.tvar) PMap.t; - define_type : value -> unit; - module_dependency : string -> string -> bool -> unit; - current_module : unit -> module_def; - delayed_macro : int -> (unit -> (unit -> value)); - use_cache : unit -> bool; -} - -type callstack = { - cpos : pos; - cthis : value; - cstack : int; - cenv : value array; -} - -type context = { - gen : Genneko.context; - types : (Type.path,int) Hashtbl.t; - prototypes : (string list, vobject) Hashtbl.t; - fields_cache : (int,string) Hashtbl.t; - mutable error : bool; - mutable error_proto : vobject; - mutable enums : (value * string) array array; - mutable do_call : value -> value -> value list -> pos -> value; - mutable do_string : value -> string; - mutable do_loadprim : value -> value -> value; - mutable do_compare : value -> value -> cmp; - mutable loader : value; - mutable exports : value; - (* runtime *) - mutable stack : value DynArray.t; - mutable callstack : callstack list; - mutable callsize : int; - mutable exc : pos list; - mutable vthis : value; - mutable venv : value array; - (* context *) - mutable curapi : extern_api; - mutable on_reused : (unit -> bool) list; - mutable is_reused : bool; - (* eval *) - mutable locals_map : (string, int) PMap.t; - mutable locals_count : int; - mutable locals_barrier : int; - mutable locals_env : string DynArray.t; - mutable globals : (string, value ref) PMap.t; -} - -type access = - | AccThis - | AccLocal of int - | AccGlobal of value ref - | AccEnv of int - | AccField of (unit -> value) * string - | AccArray of (unit -> value) * (unit -> value) - -exception Runtime of value -exception Builtin_error - -exception Error of string * Ast.pos list - -exception Abort -exception Continue -exception Break of value -exception Return of value -exception Invalid_expr - -(* ---------------------------------------------------------------------- *) -(* UTILS *) - -let get_ctx_ref = ref (fun() -> assert false) -let encode_complex_type_ref = ref (fun t -> assert false) -let encode_type_ref = ref (fun t -> assert false) -let decode_type_ref = ref (fun t -> assert false) -let encode_expr_ref = ref (fun e -> assert false) -let decode_expr_ref = ref (fun e -> assert false) -let encode_clref_ref = ref (fun c -> assert false) -let enc_hash_ref = ref (fun h -> assert false) -let enc_array_ref = ref (fun l -> assert false) -let enc_string_ref = ref (fun s -> assert false) -let make_ast_ref = ref (fun _ -> assert false) -let make_complex_type_ref = ref (fun _ -> assert false) -let get_ctx() = (!get_ctx_ref)() -let enc_array (l:value list) : value = (!enc_array_ref) l -let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t -let encode_type (t:Type.t) : value = (!encode_type_ref) t -let decode_type (v:value) : Type.t = (!decode_type_ref) v -let encode_expr (e:Ast.expr) : value = (!encode_expr_ref) e -let decode_expr (e:value) : Ast.expr = (!decode_expr_ref) e -let encode_clref (c:tclass) : value = (!encode_clref_ref) c -let enc_hash (h:('a,'b) Hashtbl.t) : value = (!enc_hash_ref) h -let make_ast (e:texpr) : Ast.expr = (!make_ast_ref) e -let enc_string (s:string) : value = (!enc_string_ref) s -let make_complex_type (t:Type.t) : Ast.complex_type = (!make_complex_type_ref) t - -let to_int f = Int32.of_float (mod_float f 2147483648.0) -let need_32_bits i = Int32.compare (Int32.logand (Int32.add i 0x40000000l) 0x80000000l) Int32.zero <> 0 -let best_int i = if need_32_bits i then VInt32 i else VInt (Int32.to_int i) - -let make_pos p = - let low = p.pline land 0xFFFFF in - { - Ast.pfile = p.psource; - Ast.pmin = low; - Ast.pmax = low + (p.pline lsr 20); - } - -let warn ctx msg p = - (ctx.curapi.get_com()).Common.warning msg (make_pos p) - -let rec pop ctx n = - if n > 0 then begin - DynArray.delete_last ctx.stack; - pop ctx (n - 1); - end - -let pop_ret ctx f n = - let v = f() in - pop ctx n; - v - -let push ctx v = - DynArray.add ctx.stack v - -let hash f = - let h = ref 0 in - for i = 0 to String.length f - 1 do - h := !h * 223 + int_of_char (String.unsafe_get f i); - done; - if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h - -let constants = - let h = Hashtbl.create 0 in - List.iter (fun f -> Hashtbl.add h (hash f) f) - ["done";"read";"write";"min";"max";"file";"args";"loadprim";"loadmodule";"__a";"__s";"h"; - "tag";"index";"length";"message";"pack";"name";"params";"sub";"doc";"kind";"meta";"access"; - "constraints";"opt";"type";"value";"ret";"expr";"field";"values";"get";"__string";"toString"; - "$";"add";"remove";"has";"__t";"module";"isPrivate";"isPublic";"isExtern";"isInterface";"exclude"; - "constructs";"names";"superClass";"interfaces";"fields";"statics";"constructor";"init";"t"; - "gid";"uid";"atime";"mtime";"ctime";"dev";"ino";"nlink";"rdev";"size";"mode";"pos";"len"; - "binops";"unops";"from";"to";"array";"op";"isPostfix";"impl"]; - h - -let h_get = hash "__get" and h_set = hash "__set" -and h_add = hash "__add" and h_radd = hash "__radd" -and h_sub = hash "__sub" and h_rsub = hash "__rsub" -and h_mult = hash "__mult" and h_rmult = hash "__rmult" -and h_div = hash "__div" and h_rdiv = hash "__rdiv" -and h_mod = hash "__mod" and h_rmod = hash "__rmod" -and h_string = hash "__string" and h_compare = hash "__compare" - -and h_constructs = hash "__constructs__" and h_a = hash "__a" and h_s = hash "__s" -and h_class = hash "__class__" - -let exc v = - raise (Runtime v) - -let hash_field ctx f = - let h = hash f in - (try - let f2 = Hashtbl.find ctx.fields_cache h in - if f <> f2 then exc (VString ("Field conflict between " ^ f ^ " and " ^ f2)); - with Not_found -> - Hashtbl.add ctx.fields_cache h f); - h - -let field_name ctx fid = - try - Hashtbl.find ctx.fields_cache fid - with Not_found -> - "???" - -let obj hash fields = - let fields = Array.of_list (List.map (fun (k,v) -> hash k, v) fields) in - Array.sort (fun (k1,_) (k2,_) -> compare k1 k2) fields; - { - ofields = fields; - oproto = None; - } - -let parse_int s = - let rec loop_hex i = - if i = String.length s then s else - match String.unsafe_get s i with - | '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex (i + 1) - | _ -> String.sub s 0 i - in - let rec loop sp i = - if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else - match String.unsafe_get s i with - | '0'..'9' -> loop sp (i + 1) - | ' ' when sp = i -> loop (sp + 1) (i + 1) - | '-' when i = 0 -> loop sp (i + 1) - | ('x' | 'X') when i = 1 && String.get s 0 = '0' -> loop_hex (i + 1) - | _ -> String.sub s sp (i - sp) - in - best_int (Int32.of_string (loop 0 0)) - -let parse_float s = - let rec loop sp i = - if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else - match String.unsafe_get s i with - | ' ' when sp = i -> loop (sp + 1) (i + 1) - | '0'..'9' | '-' | 'e' | 'E' | '.' -> loop sp (i + 1) - | _ -> String.sub s sp (i - sp) - in - float_of_string (loop 0 0) - -let find_sub str sub start = - let sublen = String.length sub in - if sublen = 0 then - 0 - else - let found = ref 0 in - let len = String.length str in - try - for i = start to len - sublen do - let j = ref 0 in - while String.unsafe_get str (i + !j) = String.unsafe_get sub !j do - incr j; - if !j = sublen then begin found := i; raise Exit; end; - done; - done; - raise Not_found - with - Exit -> !found - -let nargs = function - | Fun0 _ -> 0 - | Fun1 _ -> 1 - | Fun2 _ -> 2 - | Fun3 _ -> 3 - | Fun4 _ -> 4 - | Fun5 _ -> 5 - | FunVar _ -> -1 - -let rec get_field o fid = - let rec loop min max = - if min < max then begin - let mid = (min + max) lsr 1 in - let cid, v = Array.unsafe_get o.ofields mid in - if cid < fid then - loop (mid + 1) max - else if cid > fid then - loop min mid - else - v - end else - match o.oproto with - | None -> VNull - | Some p -> get_field p fid - in - loop 0 (Array.length o.ofields) - -let set_field o fid v = - let rec loop min max = - let mid = (min + max) lsr 1 in - if min < max then begin - let cid, _ = Array.unsafe_get o.ofields mid in - if cid < fid then - loop (mid + 1) max - else if cid > fid then - loop min mid - else - Array.unsafe_set o.ofields mid (cid,v) - end else - let fields = Array.make (Array.length o.ofields + 1) (fid,v) in - Array.blit o.ofields 0 fields 0 mid; - Array.blit o.ofields mid fields (mid + 1) (Array.length o.ofields - mid); - o.ofields <- fields - in - loop 0 (Array.length o.ofields) - -let rec remove_field o fid = - let rec loop min max = - let mid = (min + max) lsr 1 in - if min < max then begin - let cid, v = Array.unsafe_get o.ofields mid in - if cid < fid then - loop (mid + 1) max - else if cid > fid then - loop min mid - else begin - let fields = Array.make (Array.length o.ofields - 1) (fid,VNull) in - Array.blit o.ofields 0 fields 0 mid; - Array.blit o.ofields (mid + 1) fields mid (Array.length o.ofields - mid - 1); - o.ofields <- fields; - true - end - end else - false - in - loop 0 (Array.length o.ofields) - -let rec get_field_opt o fid = - let rec loop min max = - if min < max then begin - let mid = (min + max) lsr 1 in - let cid, v = Array.unsafe_get o.ofields mid in - if cid < fid then - loop (mid + 1) max - else if cid > fid then - loop min mid - else - Some v - end else - match o.oproto with - | None -> None - | Some p -> get_field_opt p fid - in - loop 0 (Array.length o.ofields) - -let catch_errors ctx ?(final=(fun() -> ())) f = - let n = DynArray.length ctx.stack in - try - let v = f() in - final(); - Some v - with Runtime v -> - pop ctx (DynArray.length ctx.stack - n); - final(); - let rec loop o = - if o == ctx.error_proto then true else match o.oproto with None -> false | Some p -> loop p - in - (match v with - | VObject o when loop o -> - (match get_field o (hash "message"), get_field o (hash "pos") with - | VObject msg, VAbstract (APos pos) -> - (match get_field msg h_s with - | VString msg -> raise (Typecore.Error (Typecore.Custom msg,pos)) - | _ -> ()); - | _ -> ()); - | _ -> ()); - raise (Error (ctx.do_string v,List.map (fun s -> make_pos s.cpos) ctx.callstack)) - | Abort -> - pop ctx (DynArray.length ctx.stack - n); - final(); - None - -let make_library fl = - let h = Hashtbl.create 0 in - List.iter (fun (n,f) -> Hashtbl.add h n f) fl; - h - -(* ---------------------------------------------------------------------- *) -(* NEKO INTEROP *) - -type primitive = (string * Extc.value * int) - -type neko_context = { - load : string -> int -> primitive; - call : primitive -> value list -> value; -} - -let neko = - let is_win = Sys.os_type = "Win32" || Sys.os_type = "Cygwin" in - let neko = Extc.dlopen (if is_win then "neko.dll" else "libneko.so") in - let null = Extc.dlint 0 in - let neko = if Obj.magic neko == null && not is_win then Extc.dlopen "libneko.dylib" else neko in - if Obj.magic neko == null then - None - else - let load v = - let s = Extc.dlsym neko v in - if (Obj.magic s) == null then failwith ("Could not load neko." ^ v); - s - in - ignore(Extc.dlcall0 (load "neko_global_init")); - let vm = Extc.dlcall1 (load "neko_vm_alloc") null in - ignore(Extc.dlcall1 (load "neko_vm_select") vm); - let loader = Extc.dlcall2 (load "neko_default_loader") null null in - let loadprim = Extc.dlcall2 (load "neko_val_field") loader (Extc.dlcall1 (load "neko_val_id") (Extc.dlstring "loadprim")) in - - let callN = load "neko_val_callN" in - let callEx = load "neko_val_callEx" in - let copy_string = load "neko_copy_string" in - - let alloc_root = load "neko_alloc_root" in - let free_root = load "neko_free_root" in - - let alloc_root v = - let r = Extc.dlcall1 alloc_root (Extc.dlint 1) in - Extc.dlsetptr r v; - r - in - let free_root r = - ignore(Extc.dlcall1 free_root r) - in - - ignore(alloc_root vm); - ignore(alloc_root loader); - ignore(alloc_root loadprim); - - let alloc_string s = - Extc.dlcall2 copy_string (Extc.dlstring s) (Extc.dlint (String.length s)) - in - let alloc_int (i:int) : Extc.value = - Obj.magic i - in - let loadprim n args = - let exc = ref null in - let vargs = [|alloc_string n;alloc_int args|] in - let p = Extc.dlcall5 callEx loader loadprim (Obj.magic vargs) (Extc.dlint 2) (Obj.magic exc) in - if !exc != null then failwith ("Failed to load " ^ n ^ ":" ^ string_of_int args); - ignore(alloc_root p); - (n,p,args) - in - let call_raw_prim (_,p,nargs) (args:Extc.value array) = - Extc.dlcall3 callN p (Obj.magic args) (Extc.dlint nargs) - in - - (* a bit tricky since load "val_true" does not work as expected on Windows *) - let unser = try loadprim "std@unserialize" 2 with _ -> ("",null,0) in - - (* did we fail to load std.ndll ? *) - if (match unser with ("",_,_) -> true | _ -> false) then None else - - let val_true = call_raw_prim unser [|alloc_string "T";loader|] in - let val_false = call_raw_prim unser [|alloc_string "F";loader|] in - let val_null = call_raw_prim unser [|alloc_string "N";loader|] in - - let is_64 = call_raw_prim (loadprim "std@sys_is64" 0) [||] == val_true in - let alloc_i32, is_v2 = (try load "neko_alloc_int32", true with _ -> Obj.magic 0, false) in - let alloc_i32 = if is_v2 then - (fun i -> Extc.dlcall1 alloc_i32 (Extc.dlint32 i)) - else - (fun i -> alloc_int (Int32.to_int (if Int32.compare i Int32.zero < 0 then Int32.logand i 0x7FFFFFFFl else Int32.logor i 0x80000000l))) - in - let tag_bits = if is_v2 then 4 else 3 in - let tag_mask = (1 lsl tag_bits) - 1 in - let ptr_size = if is_64 then 8 else 4 in - let val_field v i = Extc.dladdr v ((i + 1) * ptr_size) in - let val_str v = Extc.dladdr v 4 in - let val_fun_env v = Extc.dladdr v (8 + ptr_size) in - - (* alloc support *) - - let alloc_function = load "neko_alloc_function" in - let alloc_array = load "neko_alloc_array" in - let alloc_float = load "neko_alloc_float" in - let alloc_object = load "neko_alloc_object" in - let alloc_field = load "neko_alloc_field" in - let alloc_abstract = load "neko_alloc_abstract" in - let val_gc = load "neko_val_gc" in - let val_field_name = load "neko_val_field_name" in - let val_iter_fields = load "neko_val_iter_fields" in - let gen_callback = Extc.dlcaml_callback 2 in - - (* roots *) - - let on_abstract_gc = Extc.dlcaml_callback 1 in - let root_index = ref 0 in - let roots = Hashtbl.create 0 in - Callback.register "dlcallb1" (fun a -> - let index : int = Obj.magic (Extc.dlptr (val_field a 1)) in - Hashtbl.remove roots index; - null - ); - - (* wrapping *) - - let copy_string v = - let head = Extc.dltoint (Extc.dlptr v) in - let size = head asr tag_bits in - let s = String.create size in - Extc.dlmemcpy (Extc.dlstring s) (val_str v) size; - s - in - - let buffers = ref [] in - - let rec value_neko ?(obj=VNull) = function - | VNull -> val_null - | VBool b -> if b then val_true else val_false - | VInt i -> alloc_int i - | VAbstract (ANekoAbstract a) -> a - | VAbstract (ANekoBuffer (VString buf)) -> - let v = value_neko (VString buf) in - buffers := (buf,v) :: !buffers; - v - | VString s -> - let v = alloc_string s in (* make a copy *) - ignore(copy_string v); - v - | VObject o as obj -> - let vo = Extc.dlcall1 alloc_object null in - Array.iter (fun (id,v) -> - ignore(Extc.dlcall3 alloc_field vo (Extc.dlint id) (value_neko ~obj v)) - ) o.ofields; - vo - | VClosure _ -> - failwith "Closure not supported" - | VFunction f -> - let callb = Extc.dlcall3 alloc_function gen_callback (Extc.dlint (-1)) (Obj.magic "") in - let index = !root_index in - incr root_index; - Hashtbl.add roots index (f,obj); - let a = Extc.dlcall2 alloc_abstract null (Obj.magic index) in - if Extc.dlptr (val_field a 1) != Obj.magic index then assert false; - ignore(Extc.dlcall2 val_gc a on_abstract_gc); - Extc.dlsetptr (val_fun_env callb) a; - callb - | VArray a -> - let va = Extc.dlcall1 alloc_array (Extc.dlint (Array.length a)) in - Array.iteri (fun i v -> - Extc.dlsetptr (val_field va i) (value_neko v) - ) a; - va - | VFloat f -> - Extc.dlcall1 alloc_float (Obj.magic f) - | VAbstract _ -> - failwith "Abstract not supported" - | VInt32 i -> - alloc_i32 i - in - let obj_r = ref [] in - let obj_fun = (fun v id -> obj_r := (v,id) :: !obj_r; val_null) in - let rec neko_value (v:Extc.value) = - if Obj.is_int (Obj.magic v) then - VInt (Obj.magic v) - else - let head = Extc.dltoint (Extc.dlptr v) in - match head land tag_mask with - | 0 -> VNull - | 2 -> VBool (v == val_true) - | 3 -> VString (copy_string v) - | 4 -> - ignore(Extc.dlcall3 val_iter_fields v (Extc.dlcallback 2) (Obj.magic obj_fun)); - let r = !obj_r in - obj_r := []; - let ctx = get_ctx() in - let fields = List.rev_map (fun (v,id) -> - let iid = Extc.dltoint id in - if not (Hashtbl.mem ctx.fields_cache iid) then begin - let name = copy_string (Extc.dlcall1 val_field_name id) in - ignore(hash_field ctx name); - end; - iid, neko_value v - ) r in - VObject { ofields = Array.of_list fields; oproto = None } - | 5 -> - VArray (Array.init (head asr tag_bits) (fun i -> neko_value (Extc.dlptr (val_field v i)))) - | 7 -> - let r = alloc_root v in - let a = ANekoAbstract v in - Gc.finalise (fun _ -> free_root r) a; - VAbstract a - | t -> - failwith ("Unsupported Neko value tag " ^ string_of_int t) - in - - Callback.register "dlcallb2" (fun args nargs -> - (* get back the VM env, which was set in value_neko *) - let env = Extc.dlptr (Extc.dladdr vm (2 * ptr_size)) in - (* extract the index stored in abstract data *) - let index : int = Obj.magic (Extc.dlptr (val_field env 1)) in - let f, obj = (try Hashtbl.find roots index with Not_found -> assert false) in - let nargs = Extc.dltoint nargs in - let rec loop i = - if i = nargs then [] else neko_value (Extc.dlptr (Extc.dladdr args (i * ptr_size))) :: loop (i + 1) - in - let v = (get_ctx()).do_call obj (VFunction f) (loop 0) { psource = ""; pline = 0; } in - value_neko v - ); - - let callprim (n,p,nargs) args = - let arr = Array.of_list (List.map value_neko args) in - let exc = ref null in - if Array.length arr <> nargs then failwith n; - let ret = Extc.dlcall5 callEx val_null p (Obj.magic arr) (Extc.dlint nargs) (Obj.magic exc) in - if !exc != null then raise (Runtime (neko_value !exc)); - (match !buffers with - | [] -> () - | l -> - buffers := []; - (* copy back data *) - List.iter (fun (buf,v) -> - Extc.dlmemcpy (Extc.dlstring buf) (val_str v) (String.length buf); - ) l); - neko_value ret - in - Some { - load = loadprim; - call = callprim; - } - -(* ---------------------------------------------------------------------- *) -(* BUILTINS *) - -let builtins = - let p = { psource = ""; pline = 0 } in - let error() = - raise Builtin_error - in - let vint = function - | VInt n -> n - | _ -> error() - in - let varray = function - | VArray a -> a - | _ -> error() - in - let vstring = function - | VString s -> s - | _ -> error() - in - let vobj = function - | VObject o -> o - | _ -> error() - in - let vfun = function - | VFunction f -> f - | VClosure (cl,f) -> FunVar (f cl) - | _ -> error() - in - let vhash = function - | VAbstract (AHash h) -> h - | _ -> error() - in - let build_stack sl = - let make p = - let p = make_pos p in - VArray [|VString p.Ast.pfile;VInt (Lexer.get_error_line p)|] - in - VArray (Array.of_list (List.map make sl)) - in - let do_closure args args2 = - match args with - | f :: obj :: args -> - (get_ctx()).do_call obj f (args @ args2) p - | _ -> - assert false - in - let funcs = [ - (* array *) - "array", FunVar (fun vl -> VArray (Array.of_list vl)); - "amake", Fun1 (fun v -> VArray (Array.create (vint v) VNull)); - "acopy", Fun1 (fun a -> VArray (Array.copy (varray a))); - "asize", Fun1 (fun a -> VInt (Array.length (varray a))); - "asub", Fun3 (fun a p l -> VArray (Array.sub (varray a) (vint p) (vint l))); - "ablit", Fun5 (fun dst dstp src p l -> - Array.blit (varray src) (vint p) (varray dst) (vint dstp) (vint l); - VNull - ); - "aconcat", Fun1 (fun arr -> - let arr = Array.map varray (varray arr) in - VArray (Array.concat (Array.to_list arr)) - ); - (* string *) - "string", Fun1 (fun v -> VString ((get_ctx()).do_string v)); - "smake", Fun1 (fun l -> VString (String.make (vint l) '\000')); - "ssize", Fun1 (fun s -> VInt (String.length (vstring s))); - "scopy", Fun1 (fun s -> VString (String.copy (vstring s))); - "ssub", Fun3 (fun s p l -> VString (String.sub (vstring s) (vint p) (vint l))); - "sget", Fun2 (fun s p -> - try VInt (int_of_char (String.get (vstring s) (vint p))) with Invalid_argument _ -> VNull - ); - "sset", Fun3 (fun s p c -> - let c = char_of_int ((vint c) land 0xFF) in - try - String.set (vstring s) (vint p) c; - VInt (int_of_char c) - with Invalid_argument _ -> VNull); - "sblit", Fun5 (fun dst dstp src p l -> - String.blit (vstring src) (vint p) (vstring dst) (vint dstp) (vint l); - VNull - ); - "sfind", Fun3 (fun src pos pat -> - try VInt (find_sub (vstring src) (vstring pat) (vint pos)) with Not_found -> VNull - ); - (* object *) - "new", Fun1 (fun o -> - match o with - | VNull -> VObject { ofields = [||]; oproto = None } - | VObject o -> VObject { ofields = Array.copy o.ofields; oproto = o.oproto } - | _ -> error() - ); - "objget", Fun2 (fun o f -> - match o with - | VObject o -> get_field o (vint f) - | _ -> VNull - ); - "objset", Fun3 (fun o f v -> - match o with - | VObject o -> set_field o (vint f) v; v - | _ -> VNull - ); - "objcall", Fun3 (fun o f pl -> - match o with - | VObject oo -> - (get_ctx()).do_call o (get_field oo (vint f)) (Array.to_list (varray pl)) p - | _ -> VNull - ); - "objfield", Fun2 (fun o f -> - match o with - | VObject o -> - let p = o.oproto in - o.oproto <- None; - let v = get_field_opt o (vint f) in - o.oproto <- p; - VBool (v <> None) - | _ -> VBool false - ); - "objremove", Fun2 (fun o f -> - VBool (remove_field (vobj o) (vint f)) - ); - "objfields", Fun1 (fun o -> - VArray (Array.map (fun (fid,_) -> VInt fid) (vobj o).ofields) - ); - "hash", Fun1 (fun v -> VInt (hash_field (get_ctx()) (vstring v))); - "fasthash", Fun1 (fun v -> VInt (hash (vstring v))); - "field", Fun1 (fun v -> - try VString (Hashtbl.find (get_ctx()).fields_cache (vint v)) with Not_found -> VNull - ); - "objsetproto", Fun2 (fun o p -> - let o = vobj o in - (match p with - | VNull -> o.oproto <- None - | VObject p -> o.oproto <- Some p - | _ -> error()); - VNull; - ); - "objgetproto", Fun1 (fun o -> - match (vobj o).oproto with - | None -> VNull - | Some p -> VObject p - ); - (* function *) - "nargs", Fun1 (fun f -> - VInt (nargs (vfun f)) - ); - "call", Fun3 (fun f o args -> - (get_ctx()).do_call o f (Array.to_list (varray args)) p - ); - "closure", FunVar (fun vl -> - match vl with - | VFunction f :: _ :: _ -> - VClosure (vl, do_closure) - | _ -> exc (VString "Can't create closure : value is not a function") - ); - "apply", FunVar (fun vl -> - match vl with - | f :: args -> - let f = vfun f in - VFunction (FunVar (fun args2 -> (get_ctx()).do_call VNull (VFunction f) (args @ args2) p)) - | _ -> exc (VString "Invalid closure arguments number") - ); - "varargs", Fun1 (fun f -> - match f with - | VFunction (FunVar _) | VFunction (Fun1 _) | VClosure _ -> - VFunction (FunVar (fun vl -> (get_ctx()).do_call VNull f [VArray (Array.of_list vl)] p)) - | _ -> - error() - ); - (* numbers *) - (* skip iadd, isub, idiv, imult *) - "isnan", Fun1 (fun f -> - match f with - | VFloat f -> VBool (f <> f) - | _ -> VBool false - ); - "isinfinite", Fun1 (fun f -> - match f with - | VFloat f -> VBool (f = infinity || f = neg_infinity) - | _ -> VBool false - ); - "int", Fun1 (fun v -> - match v with - | VInt _ | VInt32 _ -> v - | VFloat f -> best_int (to_int f) - | VString s -> (try parse_int s with _ -> VNull) - | _ -> VNull - ); - "float", Fun1 (fun v -> - match v with - | VInt i -> VFloat (float_of_int i) - | VInt32 i -> VFloat (Int32.to_float i) - | VFloat _ -> v - | VString s -> (try VFloat (parse_float s) with _ -> VNull) - | _ -> VNull - ); - (* abstract *) - "getkind", Fun1 (fun v -> - match v with - | VAbstract a -> VAbstract (AKind a) - | VInt32 _ -> VAbstract (AKind AInt32Kind) - | _ -> error() - ); - "iskind", Fun2 (fun v k -> - match v, k with - | VAbstract a, VAbstract (AKind k) -> VBool (Obj.tag (Obj.repr a) = Obj.tag (Obj.repr k)) - | VInt32 _, VAbstract (AKind AInt32Kind) -> VBool true - | _, VAbstract (AKind _) -> VBool false - | _ -> error() - ); - (* hash *) - "hkey", Fun1 (fun v -> VInt (Hashtbl.hash v)); - "hnew", Fun1 (fun v -> - VAbstract (AHash (match v with - | VNull -> Hashtbl.create 0 - | VInt n -> Hashtbl.create n - | _ -> error())) - ); - "hresize", Fun1 (fun v -> VNull); - "hget", Fun3 (fun h k cmp -> - if cmp <> VNull then assert false; - (try Hashtbl.find (vhash h) k with Not_found -> VNull) - ); - "hmem", Fun3 (fun h k cmp -> - if cmp <> VNull then assert false; - VBool (Hashtbl.mem (vhash h) k) - ); - "hremove", Fun3 (fun h k cmp -> - if cmp <> VNull then assert false; - let h = vhash h in - let old = Hashtbl.mem h k in - if old then Hashtbl.remove h k; - VBool old - ); - "hset", Fun4 (fun h k v cmp -> - if cmp <> VNull then assert false; - let h = vhash h in - let old = Hashtbl.mem h k in - Hashtbl.replace h k v; - VBool (not old); - ); - "hadd", Fun4 (fun h k v cmp -> - if cmp <> VNull then assert false; - let h = vhash h in - let old = Hashtbl.mem h k in - Hashtbl.add h k v; - VBool (not old); - ); - "hiter", Fun2 (fun h f -> Hashtbl.iter (fun k v -> ignore ((get_ctx()).do_call VNull f [k;v] p)) (vhash h); VNull); - "hcount", Fun1 (fun h -> VInt (Hashtbl.length (vhash h))); - "hsize", Fun1 (fun h -> VInt (Hashtbl.length (vhash h))); - (* misc *) - "print", FunVar (fun vl -> List.iter (fun v -> - let ctx = get_ctx() in - let com = ctx.curapi.get_com() in - com.print (ctx.do_string v) - ) vl; VNull); - "throw", Fun1 (fun v -> exc v); - "rethrow", Fun1 (fun v -> - let ctx = get_ctx() in - ctx.callstack <- List.rev (List.map (fun p -> { cpos = p; cthis = ctx.vthis; cstack = DynArray.length ctx.stack; cenv = ctx.venv }) ctx.exc) @ ctx.callstack; - exc v - ); - "istrue", Fun1 (fun v -> - match v with - | VNull | VInt 0 | VBool false | VInt32 0l -> VBool false - | _ -> VBool true - ); - "not", Fun1 (fun v -> - match v with - | VNull | VInt 0 | VBool false | VInt32 0l -> VBool true - | _ -> VBool false - ); - "typeof", Fun1 (fun v -> - VInt (match v with - | VNull -> 0 - | VInt _ | VInt32 _ -> 1 - | VFloat _ -> 2 - | VBool _ -> 3 - | VString _ -> 4 - | VObject _ -> 5 - | VArray _ -> 6 - | VFunction _ | VClosure _ -> 7 - | VAbstract _ -> 8) - ); - "compare", Fun2 (fun a b -> - match (get_ctx()).do_compare a b with - | CUndef -> VNull - | CEq -> VInt 0 - | CSup -> VInt 1 - | CInf -> VInt (-1) - ); - "pcompare", Fun2 (fun a b -> - assert false - ); - "excstack", Fun0 (fun() -> - build_stack (get_ctx()).exc - ); - "callstack", Fun0 (fun() -> - build_stack (List.map (fun s -> s.cpos) (get_ctx()).callstack) - ); - "version", Fun0 (fun() -> - VInt 200 - ); - (* extra *) - "use_neko_dll", Fun0 (fun() -> - VBool (neko <> None) - ); - ] in - let vals = [ - "tnull", VInt 0; - "tint", VInt 1; - "tfloat", VInt 2; - "tbool", VInt 3; - "tstring", VInt 4; - "tobject", VInt 5; - "tarray", VInt 6; - "tfunction", VInt 7; - "tabstract", VInt 8; - ] in - let h = Hashtbl.create 0 in - List.iter (fun (n,f) -> Hashtbl.add h n (VFunction f)) funcs; - List.iter (fun (n,v) -> Hashtbl.add h n v) vals; - h - -(* ---------------------------------------------------------------------- *) -(* STD LIBRARY *) - -let std_lib = - let p = { psource = ""; pline = 0 } in - let error() = - raise Builtin_error - in - let make_list l = - let rec loop acc = function - | [] -> acc - | x :: l -> loop (VArray [|x;acc|]) l - in - loop VNull (List.rev l) - in - let num = function - | VInt i -> float_of_int i - | VInt32 i -> Int32.to_float i - | VFloat f -> f - | _ -> error() - in - let make_date f = - VInt32 (Int32.of_float f) - in - let date = function - | VInt32 i -> Int32.to_float i - | VInt i -> float_of_int i - | _ -> error() - in - let make_i32 i = - VInt32 i - in - let int32 = function - | VInt i -> Int32.of_int i - | VInt32 i -> i - | _ -> error() - in - let vint = function - | VInt n -> n - | _ -> error() - in - let vstring = function - | VString s -> s - | _ -> error() - in - let int32_addr h = - let base = Int32.to_int (Int32.logand h 0xFFFFFFl) in - let str = Printf.sprintf "%ld.%d.%d.%d" (Int32.shift_right_logical h 24) (base lsr 16) ((base lsr 8) land 0xFF) (base land 0xFF) in - Unix.inet_addr_of_string str - in - let int32_op op = Fun2 (fun a b -> make_i32 (op (int32 a) (int32 b))) in - make_library ([ - (* math *) - "math_atan2", Fun2 (fun a b -> VFloat (atan2 (num a) (num b))); - "math_pow", Fun2 (fun a b -> VFloat ((num a) ** (num b))); - "math_abs", Fun1 (fun v -> - match v with - | VInt i -> VInt (abs i) - | VInt32 i -> VInt32 (Int32.abs i) - | VFloat f -> VFloat (abs_float f) - | _ -> error() - ); - "math_ceil", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (ceil (num v)))); - "math_floor", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (floor (num v)))); - "math_round", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (floor (num v +. 0.5)))); - "math_pi", Fun0 (fun() -> VFloat (4.0 *. atan 1.0)); - "math_sqrt", Fun1 (fun v -> VFloat (sqrt (num v))); - "math_atan", Fun1 (fun v -> VFloat (atan (num v))); - "math_cos", Fun1 (fun v -> VFloat (cos (num v))); - "math_sin", Fun1 (fun v -> VFloat (sin (num v))); - "math_tan", Fun1 (fun v -> VFloat (tan (num v))); - "math_log", Fun1 (fun v -> VFloat (Pervasives.log (num v))); - "math_exp", Fun1 (fun v -> VFloat (exp (num v))); - "math_acos", Fun1 (fun v -> VFloat (acos (num v))); - "math_asin", Fun1 (fun v -> VFloat (asin (num v))); - "math_fceil", Fun1 (fun v -> VFloat (ceil (num v))); - "math_ffloor", Fun1 (fun v -> VFloat (floor (num v))); - "math_fround", Fun1 (fun v -> VFloat (floor (num v +. 0.5))); - "math_int", Fun1 (fun v -> - match v with - | VInt _ | VInt32 _ -> v - | VFloat f -> best_int (to_int (if f < 0. then ceil f else floor f)) - | _ -> error() - ); - (* buffer *) - "buffer_new", Fun0 (fun() -> - VAbstract (ABuffer (Buffer.create 0)) - ); - "buffer_add", Fun2 (fun b v -> - match b with - | VAbstract (ABuffer b) -> Buffer.add_string b ((get_ctx()).do_string v); VNull - | _ -> error() - ); - "buffer_add_char", Fun2 (fun b v -> - match b, v with - | VAbstract (ABuffer b), VInt n when n >= 0 && n < 256 -> Buffer.add_char b (char_of_int n); VNull - | _ -> error() - ); - "buffer_add_sub", Fun4 (fun b s p l -> - match b, s, p, l with - | VAbstract (ABuffer b), VString s, VInt p, VInt l -> (try Buffer.add_substring b s p l; VNull with _ -> error()) - | _ -> error() - ); - "buffer_string", Fun1 (fun b -> - match b with - | VAbstract (ABuffer b) -> VString (Buffer.contents b) - | _ -> error() - ); - "buffer_reset", Fun1 (fun b -> - match b with - | VAbstract (ABuffer b) -> Buffer.reset b; VNull; - | _ -> error() - ); - (* date *) - "date_now", Fun0 (fun () -> - make_date (Unix.time()) - ); - "date_new", Fun1 (fun v -> - make_date (match v with - | VNull -> Unix.time() - | VString s -> - (match String.length s with - | 19 -> - let r = Str.regexp "^\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)$" in - if not (Str.string_match r s 0) then exc (VString ("Invalid date format : " ^ s)); - let t = Unix.localtime (Unix.time()) in - let t = { t with - tm_year = int_of_string (Str.matched_group 1 s) - 1900; - tm_mon = int_of_string (Str.matched_group 2 s) - 1; - tm_mday = int_of_string (Str.matched_group 3 s); - tm_hour = int_of_string (Str.matched_group 4 s); - tm_min = int_of_string (Str.matched_group 5 s); - tm_sec = int_of_string (Str.matched_group 6 s); - } in - fst (Unix.mktime t) - | 10 -> - assert false - | 8 -> - assert false - | _ -> - exc (VString ("Invalid date format : " ^ s))); - | _ -> error()) - ); - "date_set_hour", Fun4 (fun d h m s -> - let d = date d in - let t = Unix.localtime d in - make_date (fst (Unix.mktime { t with tm_hour = vint h; tm_min = vint m; tm_sec = vint s })) - ); - "date_set_day", Fun4 (fun d y m da -> - let d = date d in - let t = Unix.localtime d in - make_date (fst (Unix.mktime { t with tm_year = vint y - 1900; tm_mon = vint m - 1; tm_mday = vint da })) - ); - "date_format", Fun2 (fun d fmt -> - match fmt with - | VNull -> - let t = Unix.localtime (date d) in - VString (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) - | VString "%w" -> - (* week day *) - let t = Unix.localtime (date d) in - VString (string_of_int t.tm_wday) - | VString _ -> - exc (VString "Custom date format is not supported") (* use native Haxe implementation *) - | _ -> - error() - ); - "date_get_hour", Fun1 (fun d -> - let t = Unix.localtime (date d) in - let o = obj (hash_field (get_ctx())) [ - "h", VInt t.tm_hour; - "m", VInt t.tm_min; - "s", VInt t.tm_sec; - ] in - VObject o - ); - "date_get_day", Fun1 (fun d -> - let t = Unix.localtime (date d) in - let o = obj (hash_field (get_ctx())) [ - "d", VInt t.tm_mday; - "m", VInt (t.tm_mon + 1); - "y", VInt (t.tm_year + 1900); - ] in - VObject o - ); - (* string *) - "string_split", Fun2 (fun s d -> - make_list (match s, d with - | VString "", VString _ -> [VString ""] - | VString s, VString "" -> Array.to_list (Array.init (String.length s) (fun i -> VString (String.make 1 (String.get s i)))) - | VString s, VString d -> List.map (fun s -> VString s) (ExtString.String.nsplit s d) - | _ -> error()) - ); - "url_encode", Fun1 (fun s -> - let s = vstring s in - let b = Buffer.create 0 in - let hex = "0123456789ABCDEF" in - for i = 0 to String.length s - 1 do - let c = String.unsafe_get s i in - match c with - | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '-' | '.' -> - Buffer.add_char b c - | _ -> - Buffer.add_char b '%'; - Buffer.add_char b (String.unsafe_get hex (int_of_char c lsr 4)); - Buffer.add_char b (String.unsafe_get hex (int_of_char c land 0xF)); - done; - VString (Buffer.contents b) - ); - "url_decode", Fun1 (fun s -> - let s = vstring s in - let b = Buffer.create 0 in - let len = String.length s in - let decode c = - match c with - | '0'..'9' -> Some (int_of_char c - int_of_char '0') - | 'a'..'f' -> Some (int_of_char c - int_of_char 'a' + 10) - | 'A'..'F' -> Some (int_of_char c - int_of_char 'A' + 10) - | _ -> None - in - let rec loop i = - if i = len then () else - let c = String.unsafe_get s i in - match c with - | '%' -> - let p1 = (try decode (String.get s (i + 1)) with _ -> None) in - let p2 = (try decode (String.get s (i + 2)) with _ -> None) in - (match p1, p2 with - | Some c1, Some c2 -> - Buffer.add_char b (char_of_int ((c1 lsl 4) lor c2)); - loop (i + 3) - | _ -> - loop (i + 1)); - | '+' -> - Buffer.add_char b ' '; - loop (i + 1) - | c -> - Buffer.add_char b c; - loop (i + 1) - in - loop 0; - VString (Buffer.contents b) - ); - "base_encode", Fun2 (fun s b -> - match s, b with - | VString s, VString "0123456789abcdef" when String.length s = 16 -> - VString (Digest.to_hex s) - | VString s, VString b -> - if String.length b <> 64 then assert false; - let tbl = Array.init 64 (String.unsafe_get b) in - VString (Base64.str_encode ~tbl s) - | _ -> error() - ); - "base_decode", Fun2 (fun s b -> - let s = vstring s in - let b = vstring b in - if String.length b <> 64 then assert false; - let tbl = Array.init 64 (String.unsafe_get b) in - VString (Base64.str_decode ~tbl:(Base64.make_decoding_table tbl) s) - ); - "make_md5", Fun1 (fun s -> - VString (Digest.string (vstring s)) - ); - (* sprintf *) - (* int32 *) - "int32_new", Fun1 (fun v -> - match v with - | VInt32 _ -> v - | VInt i -> make_i32 (Int32.of_int i) - | VFloat f -> make_i32 (Int32.of_float f) - | _ -> error() - ); - "int32_to_int", Fun1 (fun v -> - let v = int32 v in - let i = Int32.to_int v in - if Int32.compare (Int32.of_int i) v <> 0 then error(); - VInt i - ); - "int32_to_float", Fun1 (fun v -> - VFloat (Int32.to_float (int32 v)) - ); - "int32_compare", Fun2 (fun a b -> - VInt (Int32.compare (int32 a) (int32 b)) - ); - "int32_add", int32_op Int32.add; - "int32_sub", int32_op Int32.sub; - "int32_mul", int32_op Int32.mul; - "int32_div", int32_op Int32.div; - "int32_shl", int32_op (fun a b -> Int32.shift_left a (Int32.to_int b)); - "int32_shr", int32_op (fun a b -> Int32.shift_right a (Int32.to_int b)); - "int32_ushr", int32_op (fun a b -> Int32.shift_right_logical a (Int32.to_int b)); - "int32_mod", int32_op Int32.rem; - "int32_or", int32_op Int32.logor; - "int32_and", int32_op Int32.logand; - "int32_xor", int32_op Int32.logxor; - "int32_neg", Fun1 (fun v -> make_i32 (Int32.neg (int32 v))); - "int32_complement", Fun1 (fun v -> make_i32 (Int32.lognot (int32 v))); - (* misc *) - "same_closure", Fun2 (fun a b -> - VBool (match a, b with - | VClosure (la,fa), VClosure (lb,fb) -> - fa == fb && List.length la = List.length lb && List.for_all2 (fun a b -> (get_ctx()).do_compare a b = CEq) la lb - | VFunction a, VFunction b -> a == b - | _ -> false) - ); - "double_bytes", Fun2 (fun f big -> - let f = (match f with VFloat f -> f | VInt i -> float_of_int i | _ -> error()) in - match big with - | VBool big -> - let ch = IO.output_string() in - if big then IO.BigEndian.write_double ch f else IO.write_double ch f; - VString (IO.close_out ch) - | _ -> - error() - ); - "float_bytes", Fun2 (fun f big -> - let f = (match f with VFloat f -> f | VInt i -> float_of_int i | _ -> error()) in - match big with - | VBool big -> - let ch = IO.output_string() in - let i = Int32.bits_of_float f in - if big then IO.BigEndian.write_real_i32 ch i else IO.write_real_i32 ch i; - VString (IO.close_out ch) - | _ -> - error() - ); - "double_of_bytes", Fun2 (fun s big -> - match s, big with - | VString s, VBool big when String.length s = 8 -> - let ch = IO.input_string s in - VFloat (if big then IO.BigEndian.read_double ch else IO.read_double ch) - | _ -> - error() - ); - "float_of_bytes", Fun2 (fun s big -> - match s, big with - | VString s, VBool big when String.length s = 4 -> - let ch = IO.input_string s in - VFloat (Int32.float_of_bits (if big then IO.BigEndian.read_real_i32 ch else IO.read_real_i32 ch)) - | _ -> - error() - ); - (* random *) - "random_new", Fun0 (fun() -> VAbstract (ARandom (ref (Random.State.make_self_init())))); - "random_set_seed", Fun2 (fun r s -> - match r, s with - | VAbstract (ARandom r), VInt seed -> r := Random.State.make [|seed|]; VNull - | VAbstract (ARandom r), VInt32 seed -> r := Random.State.make [|Int32.to_int seed|]; VNull - | _ -> error() - ); - "random_int", Fun2 (fun r s -> - match r, s with - | VAbstract (ARandom r), VInt max -> VInt (Random.State.int (!r) (if max <= 0 then 1 else max)) - | _ -> error() - ); - "random_float", Fun1 (fun r -> - match r with - | VAbstract (ARandom r) -> VFloat (Random.State.float (!r) 1.0) - | _ -> error() - ); - (* file *) - "file_open", Fun2 (fun f r -> - match f, r with - | VString f, VString r -> - let perms = 0o666 in - VAbstract (match r with - | "r" -> AFRead (open_in_gen [Open_rdonly] 0 f) - | "rb" -> AFRead (open_in_gen [Open_rdonly;Open_binary] 0 f) - | "w" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc] perms f) - | "wb" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc;Open_binary] perms f) - | "a" -> AFWrite (open_out_gen [Open_append] perms f) - | "ab" -> AFWrite (open_out_gen [Open_append;Open_binary] perms f) - | _ -> error()) - | _ -> error() - ); - "file_close", Fun1 (fun f -> - (match f with - | VAbstract (AFRead f) -> close_in f - | VAbstract (AFWrite f) -> close_out f - | _ -> error()); - VNull - ); - (* file_name *) - "file_write", Fun4 (fun f s p l -> - match f, s, p, l with - | VAbstract (AFWrite f), VString s, VInt p, VInt l -> output f s p l; VInt l - | _ -> error() - ); - "file_read", Fun4 (fun f s p l -> - match f, s, p, l with - | VAbstract (AFRead f), VString s, VInt p, VInt l -> - let n = input f s p l in - if n = 0 then exc (VArray [|VString "file_read"|]); - VInt n - | _ -> error() - ); - "file_write_char", Fun2 (fun f c -> - match f, c with - | VAbstract (AFWrite f), VInt c -> output_char f (char_of_int c); VNull - | _ -> error() - ); - "file_read_char", Fun1 (fun f -> - match f with - | VAbstract (AFRead f) -> VInt (int_of_char (try input_char f with _ -> exc (VArray [|VString "file_read_char"|]))) - | _ -> error() - ); - "file_seek", Fun3 (fun f pos mode -> - match f, pos, mode with - | VAbstract (AFRead f), VInt pos, VInt mode -> - seek_in f (match mode with 0 -> pos | 1 -> pos_in f + pos | 2 -> in_channel_length f - pos | _ -> error()); - VNull; - | VAbstract (AFWrite f), VInt pos, VInt mode -> - seek_out f (match mode with 0 -> pos | 1 -> pos_out f + pos | 2 -> out_channel_length f - pos | _ -> error()); - VNull; - | _ -> error() - ); - "file_tell", Fun1 (fun f -> - match f with - | VAbstract (AFRead f) -> VInt (pos_in f) - | VAbstract (AFWrite f) -> VInt (pos_out f) - | _ -> error() - ); - "file_eof", Fun1 (fun f -> - match f with - | VAbstract (AFRead f) -> - VBool (try - ignore(input_char f); - seek_in f (pos_in f - 1); - false - with End_of_file -> - true) - | _ -> error() - ); - "file_flush", Fun1 (fun f -> - (match f with - | VAbstract (AFWrite f) -> flush f - | _ -> error()); - VNull - ); - "file_contents", Fun1 (fun f -> - match f with - | VString f -> VString (Std.input_file ~bin:true f) - | _ -> error() - ); - "file_stdin", Fun0 (fun() -> VAbstract (AFRead Pervasives.stdin)); - "file_stdout", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stdout)); - "file_stderr", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stderr)); - (* serialize *) - (* TODO *) - (* socket *) - "socket_init", Fun0 (fun() -> VNull); - "socket_new", Fun1 (fun v -> - match v with - | VBool b -> VAbstract (ASocket (Unix.socket PF_INET (if b then SOCK_DGRAM else SOCK_STREAM) 0)); - | _ -> error() - ); - "socket_close", Fun1 (fun s -> - match s with - | VAbstract (ASocket s) -> Unix.close s; VNull - | _ -> error() - ); - "socket_send_char", Fun2 (fun s c -> - match s, c with - | VAbstract (ASocket s), VInt c when c >= 0 && c <= 255 -> - ignore(Unix.send s (String.make 1 (char_of_int c)) 0 1 []); - VNull - | _ -> error() - ); - "socket_send", Fun4 (fun s buf pos len -> - match s, buf, pos, len with - | VAbstract (ASocket s), VString buf, VInt pos, VInt len -> VInt (Unix.send s buf pos len []) - | _ -> error() - ); - "socket_recv", Fun4 (fun s buf pos len -> - match s, buf, pos, len with - | VAbstract (ASocket s), VString buf, VInt pos, VInt len -> VInt (Unix.recv s buf pos len []) - | _ -> error() - ); - "socket_recv_char", Fun1 (fun s -> - match s with - | VAbstract (ASocket s) -> - let buf = String.make 1 '\000' in - ignore(Unix.recv s buf 0 1 []); - VInt (int_of_char (String.unsafe_get buf 0)) - | _ -> error() - ); - "socket_write", Fun2 (fun s str -> - match s, str with - | VAbstract (ASocket s), VString str -> - let pos = ref 0 in - let len = ref (String.length str) in - while !len > 0 do - let k = Unix.send s str (!pos) (!len) [] in - pos := !pos + k; - len := !len - k; - done; - VNull - | _ -> error() - ); - "socket_read", Fun1 (fun s -> - match s with - | VAbstract (ASocket s) -> - let tmp = String.make 1024 '\000' in - let buf = Buffer.create 0 in - let rec loop() = - let k = (try Unix.recv s tmp 0 1024 [] with Unix_error _ -> 0) in - if k > 0 then begin - Buffer.add_substring buf tmp 0 k; - loop(); - end - in - loop(); - VString (Buffer.contents buf) - | _ -> error() - ); - "host_resolve", Fun1 (fun s -> - let h = (try Unix.gethostbyname (vstring s) with Not_found -> error()) in - let addr = Unix.string_of_inet_addr h.h_addr_list.(0) in - let a, b, c, d = Scanf.sscanf addr "%d.%d.%d.%d" (fun a b c d -> a,b,c,d) in - VInt32 (Int32.logor (Int32.shift_left (Int32.of_int a) 24) (Int32.of_int (d lor (c lsl 8) lor (b lsl 16)))) - ); - "host_to_string", Fun1 (fun h -> - match h with - | VInt32 h -> VString (Unix.string_of_inet_addr (int32_addr h)); - | _ -> error() - ); - "host_reverse", Fun1 (fun h -> - match h with - | VInt32 h -> VString (gethostbyaddr (int32_addr h)).h_name - | _ -> error() - ); - "host_local", Fun0 (fun() -> - VString (Unix.gethostname()) - ); - "socket_connect", Fun3 (fun s h p -> - match s, h, p with - | VAbstract (ASocket s), VInt32 h, VInt p -> - Unix.connect s (ADDR_INET (int32_addr h,p)); - VNull - | _ -> error() - ); - "socket_listen", Fun2 (fun s l -> - match s, l with - | VAbstract (ASocket s), VInt l -> - Unix.listen s l; - VNull - | _ -> error() - ); - "socket_set_timeout", Fun2 (fun s t -> - match s with - | VAbstract (ASocket s) -> - let t = (match t with VNull -> 0. | VInt t -> float_of_int t | VFloat f -> f | _ -> error()) in - Unix.setsockopt_float s SO_RCVTIMEO t; - Unix.setsockopt_float s SO_SNDTIMEO t; - VNull - | _ -> error() - ); - "socket_shutdown", Fun3 (fun s r w -> - match s, r, w with - | VAbstract (ASocket s), VBool r, VBool w -> - Unix.shutdown s (match r, w with true, true -> SHUTDOWN_ALL | true, false -> SHUTDOWN_RECEIVE | false, true -> SHUTDOWN_SEND | _ -> error()); - VNull - | _ -> error() - ); - (* TODO : select, bind, accept, peer, host *) - (* poll_alloc, poll : not planned *) - (* system *) - "get_env", Fun1 (fun v -> - try VString (Unix.getenv (vstring v)) with _ -> VNull - ); - "put_env", Fun2 (fun e v -> - Unix.putenv (vstring e) (vstring v); - VNull - ); - "sys_sleep", Fun1 (fun f -> - match f with - | VFloat f -> ignore(Unix.select [] [] [] f); VNull - | _ -> error() - ); - "set_time_locale", Fun1 (fun l -> - match l with - | VString s -> VBool false (* always fail *) - | _ -> error() - ); - "get_cwd", Fun0 (fun() -> - let dir = Unix.getcwd() in - let l = String.length dir in - VString (if l = 0 then "./" else match dir.[l - 1] with '/' | '\\' -> dir | _ -> dir ^ "/") - ); - "set_cwd", Fun1 (fun s -> - Unix.chdir (vstring s); - VNull; - ); - "sys_string", Fun0 (fun() -> - VString (match Sys.os_type with - | "Unix" -> "Linux" - | "Win32" | "Cygwin" -> "Windows" - | s -> s) - ); - "sys_is64", Fun0 (fun() -> - VBool (Sys.word_size = 64) - ); - "sys_command", Fun1 (fun cmd -> - VInt (((get_ctx()).curapi.get_com()).run_command (vstring cmd)) - ); - "sys_exit", Fun1 (fun code -> - if (get_ctx()).curapi.use_cache() then raise Typecore.Fatal_error; - exit (vint code); - ); - "sys_exists", Fun1 (fun file -> - VBool (Sys.file_exists (vstring file)) - ); - "file_delete", Fun1 (fun file -> - Sys.remove (vstring file); - VNull; - ); - "sys_rename", Fun2 (fun file target -> - Sys.rename (vstring file) (vstring target); - VNull; - ); - "sys_stat", Fun1 (fun file -> - let s = Unix.stat (vstring file) in - VObject (obj (hash_field (get_ctx())) [ - "gid", VInt s.st_gid; - "uid", VInt s.st_uid; - "atime", VInt32 (Int32.of_float s.st_atime); - "mtime", VInt32 (Int32.of_float s.st_mtime); - "ctime", VInt32 (Int32.of_float s.st_ctime); - "dev", VInt s.st_dev; - "ino", VInt s.st_ino; - "nlink", VInt s.st_nlink; - "rdev", VInt s.st_rdev; - "size", VInt s.st_size; - "mode", VInt s.st_perm; - ]) - ); - "sys_file_type", Fun1 (fun file -> - VString (match (Unix.stat (vstring file)).st_kind with - | S_REG -> "file" - | S_DIR -> "dir" - | S_CHR -> "char" - | S_BLK -> "block" - | S_LNK -> "symlink" - | S_FIFO -> "fifo" - | S_SOCK -> "sock") - ); - "sys_create_dir", Fun2 (fun dir mode -> - Unix.mkdir (vstring dir) (vint mode); - VNull - ); - "sys_remove_dir", Fun1 (fun dir -> - Unix.rmdir (vstring dir); - VNull; - ); - "sys_time", Fun0 (fun() -> - VFloat (Unix.gettimeofday()) - ); - "sys_cpu_time", Fun0 (fun() -> - VFloat (Sys.time()) - ); - "sys_read_dir", Fun1 (fun dir -> - let d = Sys.readdir (vstring dir) in - let rec loop acc i = - if i < 0 then - acc - else - loop (VArray [|VString d.(i);acc|]) (i - 1) - in - loop VNull (Array.length d - 1) - ); - "file_full_path", Fun1 (fun file -> - VString (try Extc.get_full_path (vstring file) with _ -> error()) - ); - "sys_exe_path", Fun0 (fun() -> - VString (Extc.executable_path()) - ); - "sys_env", Fun0 (fun() -> - let env = Unix.environment() in - let rec loop acc i = - if i < 0 then - acc - else - let e, v = ExtString.String.split "=" env.(i) in - loop (VArray [|VString e;VString v;acc|]) (i - 1) - in - loop VNull (Array.length env - 1) - ); - "sys_getch", Fun1 (fun echo -> - match echo with - | VBool b -> VInt (Extc.getch b) - | _ -> error() - ); - "sys_get_pid", Fun0 (fun() -> - VInt (Unix.getpid()) - ); - (* utf8 *) - "utf8_buf_alloc", Fun1 (fun v -> - VAbstract (AUtf8 (UTF8.Buf.create (vint v))) - ); - "utf8_buf_add", Fun2 (fun b c -> - match b with - | VAbstract (AUtf8 buf) -> UTF8.Buf.add_char buf (UChar.chr_of_uint (vint c)); VNull - | _ -> error() - ); - "utf8_buf_content", Fun1 (fun b -> - match b with - | VAbstract (AUtf8 buf) -> VString (UTF8.Buf.contents buf); - | _ -> error() - ); - "utf8_buf_length", Fun1 (fun b -> - match b with - | VAbstract (AUtf8 buf) -> VInt (UTF8.length (UTF8.Buf.contents buf)); - | _ -> error() - ); - "utf8_buf_size", Fun1 (fun b -> - match b with - | VAbstract (AUtf8 buf) -> VInt (String.length (UTF8.Buf.contents buf)); - | _ -> error() - ); - "utf8_validate", Fun1 (fun s -> - VBool (try UTF8.validate (vstring s); true with UTF8.Malformed_code -> false) - ); - "utf8_length", Fun1 (fun s -> - VInt (UTF8.length (vstring s)) - ); - "utf8_sub", Fun3 (fun s p l -> - let buf = UTF8.Buf.create 0 in - let pos = ref (-1) in - let p = vint p and l = vint l in - UTF8.iter (fun c -> - incr pos; - if !pos >= p && !pos < p + l then UTF8.Buf.add_char buf c; - ) (vstring s); - if !pos < p + l then error(); - VString (UTF8.Buf.contents buf) - ); - "utf8_get", Fun2 (fun s p -> - VInt (UChar.uint_code (try UTF8.look (vstring s) (vint p) with _ -> error())) - ); - "utf8_iter", Fun2 (fun s f -> - let ctx = get_ctx() in - UTF8.iter (fun c -> - ignore(ctx.do_call VNull f [VInt (UChar.uint_code c)] p); - ) (vstring s); - VNull; - ); - "utf8_compare", Fun2 (fun s1 s2 -> - VInt (UTF8.compare (vstring s1) (vstring s2)) - ); - (* xml *) - "parse_xml", (match neko with - | None -> Fun2 (fun str o -> - match str, o with - | VString str, VObject events -> - let ctx = get_ctx() in - let p = { psource = "parse_xml"; pline = 0 } in - let xml = get_field events (hash "xml") in - let don = get_field events (hash "done") in - let pcdata = get_field events (hash "pcdata") in - (* - - Since we use the Xml parser, we don't have support for - - CDATA - - comments, prolog, doctype (allowed but skipped) - - let cdata = get_field events (hash "cdata") in - let comment = get_field events (hash "comment") in - *) - let rec loop = function - | Xml.Element (node, attribs, children) -> - ignore(ctx.do_call o xml [VString node;VObject (obj (hash_field ctx) (List.map (fun (a,v) -> a, VString v) attribs))] p); - List.iter loop children; - ignore(ctx.do_call o don [] p); - | Xml.PCData s -> - ignore(ctx.do_call o pcdata [VString s] p); - in - let x = XmlParser.make() in - XmlParser.check_eof x false; - loop (try - XmlParser.parse x (XmlParser.SString str) - with Xml.Error e -> failwith ("Parser failure (" ^ Xml.error e ^ ")") - | e -> failwith ("Parser failure (" ^ Printexc.to_string e ^ ")")); - VNull - | _ -> error()) - | Some neko -> - let parse_xml = neko.load "std@parse_xml" 2 in - Fun2 (fun str o -> neko.call parse_xml [str;o]) - ); - (* memory, module, thread : not planned *) - ] - (* process *) - @ (match neko with - | None -> [] - | Some neko -> - let p_run = neko.load "std@process_run" 2 in - let p_stdout_read = neko.load "std@process_stdout_read" 4 in - let p_stderr_read = neko.load "std@process_stderr_read" 4 in - let p_stdin_write = neko.load "std@process_stdin_write" 4 in - let p_stdin_close = neko.load "std@process_stdin_close" 1 in - let p_exit = neko.load "std@process_exit" 1 in - let p_pid = neko.load "std@process_pid" 1 in - let p_close = neko.load "std@process_close" 1 in - let win_ec = (try Some (neko.load "std@win_env_changed" 0) with _ -> None) in - [ - "process_run", (Fun2 (fun a b -> neko.call p_run [a;b])); - "process_stdout_read", (Fun4 (fun a b c d -> neko.call p_stdout_read [a;VAbstract (ANekoBuffer b);c;d])); - "process_stderr_read", (Fun4 (fun a b c d -> neko.call p_stderr_read [a;VAbstract (ANekoBuffer b);c;d])); - "process_stdin_write", (Fun4 (fun a b c d -> neko.call p_stdin_write [a;b;c;d])); - "process_stdin_close", (Fun1 (fun p -> neko.call p_stdin_close [p])); - "process_exit", (Fun1 (fun p -> neko.call p_exit [p])); - "process_pid", (Fun1 (fun p -> neko.call p_pid [p])); - "process_close", (Fun1 (fun p -> neko.call p_close [p])); - "win_env_changed", (Fun0 (fun() -> match win_ec with None -> error() | Some f -> neko.call f [])); - ])) - - -(* ---------------------------------------------------------------------- *) -(* REGEXP LIBRARY *) - -let reg_lib = - let error() = - raise Builtin_error - in - (* try to load regexp first : we might fail if pcre is not installed *) - let neko = (match neko with - | None -> None - | Some neko -> - (try ignore(neko.load "regexp@regexp_new_options" 2); Some neko with _ -> None) - ) in - match neko with - | None -> - make_library [ - (* regexp_new : deprecated *) - "regexp_new_options", Fun2 (fun str opt -> - match str, opt with - | VString str, VString opt -> - let case_sensitive = ref true in - List.iter (function - | 'm' -> () (* always ON ? *) - | 'i' -> case_sensitive := false - | c -> failwith ("Unsupported regexp option '" ^ String.make 1 c ^ "'") - ) (ExtString.String.explode opt); - let buf = Buffer.create 0 in - let rec loop prev esc = function - | [] -> () - | c :: l when esc -> - (match c with - | 'n' -> Buffer.add_char buf '\n' - | 'r' -> Buffer.add_char buf '\r' - | 't' -> Buffer.add_char buf '\t' - | 'd' -> Buffer.add_string buf "[0-9]" - | '\\' -> Buffer.add_string buf "\\\\" - | '(' | ')' -> Buffer.add_char buf c - | '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' -> - Buffer.add_char buf '\\'; - Buffer.add_char buf c; - | _ -> failwith ("Unsupported escaped char '" ^ String.make 1 c ^ "'")); - loop c false l - | c :: l -> - match c with - | '\\' -> loop prev true l - | '(' | '|' | ')' -> - Buffer.add_char buf '\\'; - Buffer.add_char buf c; - loop c false l - | '?' when prev = '(' && (match l with ':' :: _ -> true | _ -> false) -> - failwith "Non capturing groups '(?:' are not supported in macros" - | '?' when prev = '*' -> - failwith "Ungreedy *? are not supported in macros" - | _ -> - Buffer.add_char buf c; - loop c false l - in - loop '\000' false (ExtString.String.explode str); - let str = Buffer.contents buf in - let r = { - r = if !case_sensitive then Str.regexp str else Str.regexp_case_fold str; - r_string = ""; - r_groups = [||]; - } in - VAbstract (AReg r) - | _ -> error() - ); - "regexp_match", Fun4 (fun r str pos len -> - match r, str, pos, len with - | VAbstract (AReg r), VString str, VInt pos, VInt len -> - let nstr, npos, delta = (if len = String.length str - pos then str, pos, 0 else String.sub str pos len, 0, pos) in - (try - ignore(Str.search_forward r.r nstr npos); - let rec loop n = - if n = 9 then - [] - else try - (Some (Str.group_beginning n + delta, Str.group_end n + delta)) :: loop (n + 1) - with Not_found -> - None :: loop (n + 1) - | Invalid_argument _ -> - [] - in - r.r_string <- str; - r.r_groups <- Array.of_list (loop 0); - VBool true; - with Not_found -> - VBool false) - | _ -> error() - ); - "regexp_matched", Fun2 (fun r n -> - match r, n with - | VAbstract (AReg r), VInt n -> - (match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with - | None -> VNull - | Some (pos,pend) -> VString (String.sub r.r_string pos (pend - pos))) - | _ -> error() - ); - "regexp_matched_pos", Fun2 (fun r n -> - match r, n with - | VAbstract (AReg r), VInt n -> - (match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with - | None -> VNull - | Some (pos,pend) -> VObject (obj (hash_field (get_ctx())) ["pos",VInt pos;"len",VInt (pend - pos)])) - | _ -> error() - ); - (* regexp_replace : not used by Haxe *) - (* regexp_replace_all : not used by Haxe *) - (* regexp_replace_fun : not used by Haxe *) - ] - | Some neko -> - let regexp_new_options = neko.load "regexp@regexp_new_options" 2 in - let regexp_match = neko.load "regexp@regexp_match" 4 in - let regexp_matched = neko.load "regexp@regexp_matched" 2 in - let regexp_matched_pos = neko.load "regexp@regexp_matched_pos" 2 in - make_library [ - "regexp_new_options", Fun2 (fun str opt -> neko.call regexp_new_options [str;opt]); - "regexp_match", Fun4 (fun r str pos len -> neko.call regexp_match [r;str;pos;len]); - "regexp_matched", Fun2 (fun r n -> neko.call regexp_matched [r;n]); - "regexp_matched_pos", Fun2 (fun r n -> neko.call regexp_matched_pos [r;n]); - ] - - -(* ---------------------------------------------------------------------- *) -(* ZLIB LIBRARY *) - -let z_lib = - let error() = - raise Builtin_error - in - make_library [ - "inflate_init", Fun1 (fun f -> - let z = Extc.zlib_inflate_init2 (match f with VNull -> 15 | VInt i -> i | _ -> error()) in - VAbstract (AZipI { z = z; z_flush = Extc.Z_NO_FLUSH }) - ); - "deflate_init", Fun1 (fun f -> - let z = Extc.zlib_deflate_init (match f with VInt i -> i | _ -> error()) in - VAbstract (AZipD { z = z; z_flush = Extc.Z_NO_FLUSH }) - ); - "deflate_end", Fun1 (fun z -> - match z with - | VAbstract (AZipD z) -> Extc.zlib_deflate_end z.z; VNull; - | _ -> error() - ); - "inflate_end", Fun1 (fun z -> - match z with - | VAbstract (AZipI z) -> Extc.zlib_inflate_end z.z; VNull; - | _ -> error() - ); - "set_flush_mode", Fun2 (fun z f -> - match z, f with - | VAbstract (AZipI z | AZipD z), VString s -> - z.z_flush <- (match s with - | "NO" -> Extc.Z_NO_FLUSH - | "SYNC" -> Extc.Z_SYNC_FLUSH - | "FULL" -> Extc.Z_FULL_FLUSH - | "FINISH" -> Extc.Z_FINISH - | "BLOCK" -> Extc.Z_PARTIAL_FLUSH - | _ -> error()); - VNull; - | _ -> error() - ); - "inflate_buffer", Fun5 (fun z src pos dst dpos -> - match z, src, pos, dst, dpos with - | VAbstract (AZipI z), VString src, VInt pos, VString dst, VInt dpos -> - let r = Extc.zlib_inflate z.z src pos (String.length src - pos) dst dpos (String.length dst - dpos) z.z_flush in - VObject (obj (hash_field (get_ctx())) [ - "done", VBool r.Extc.z_finish; - "read", VInt r.Extc.z_read; - "write", VInt r.Extc.z_wrote; - ]) - | _ -> error() - ); - "deflate_buffer", Fun5 (fun z src pos dst dpos -> - match z, src, pos, dst, dpos with - | VAbstract (AZipD z), VString src, VInt pos, VString dst, VInt dpos -> - let r = Extc.zlib_deflate z.z src pos (String.length src - pos) dst dpos (String.length dst - dpos) z.z_flush in - VObject (obj (hash_field (get_ctx())) [ - "done", VBool r.Extc.z_finish; - "read", VInt r.Extc.z_read; - "write", VInt r.Extc.z_wrote; - ]) - | _ -> error() - ); - "deflate_bound", Fun2 (fun z size -> - match z, size with - | VAbstract (AZipD z), VInt size -> VInt (size + 1024) - | _ -> error() - ); - ] - -(* ---------------------------------------------------------------------- *) -(* MACRO LIBRARY *) - -let macro_lib = - let error() = - raise Builtin_error - in - let ccom() = - (get_ctx()).curapi.get_com() - in - make_library [ - "curpos", Fun0 (fun() -> VAbstract (APos (get_ctx()).curapi.pos)); - "error", Fun2 (fun msg p -> - match msg, p with - | VString s, VAbstract (APos p) -> - (ccom()).Common.error s p; - raise Abort - | _ -> error() - ); - "warning", Fun2 (fun msg p -> - match msg, p with - | VString s, VAbstract (APos p) -> - (ccom()).warning s p; - VNull; - | _ -> error() - ); - "class_path", Fun0 (fun() -> - VArray (Array.of_list (List.map (fun s -> VString s) (ccom()).class_path)); - ); - "resolve", Fun1 (fun file -> - match file with - | VString s -> VString (try Common.find_file (ccom()) s with Not_found -> failwith ("File not found '" ^ s ^ "'")) - | _ -> error(); - ); - "define", Fun1 (fun s -> - match s with - | VString s -> Common.raw_define (ccom()) s; VNull - | _ -> error(); - ); - "defined", Fun1 (fun s -> - match s with - | VString s -> VBool (Common.raw_defined (ccom()) s) - | _ -> error(); - ); - "defined_value", Fun1 (fun s -> - match s with - | VString s -> (try VString (Common.raw_defined_value (ccom()) s) with Not_found -> VNull) - | _ -> error(); - ); - "get_type", Fun1 (fun s -> - match s with - | VString s -> - (match (get_ctx()).curapi.get_type s with - | None -> failwith ("Type not found '" ^ s ^ "'") - | Some t -> encode_type t) - | _ -> error() - ); - "get_module", Fun1 (fun s -> - match s with - | VString s -> - enc_array (List.map encode_type ((get_ctx()).curapi.get_module s)) - | _ -> error() - ); - "on_generate", Fun1 (fun f -> - match f with - | VFunction (Fun1 _) -> - let ctx = get_ctx() in - ctx.curapi.on_generate (fun tl -> - ignore(catch_errors ctx (fun() -> ctx.do_call VNull f [enc_array (List.map encode_type tl)] null_pos)); - ); - VNull - | _ -> error() - ); - "on_type_not_found", Fun1 (fun f -> - match f with - | VFunction (Fun1 _) -> - let ctx = get_ctx() in - ctx.curapi.on_type_not_found (fun path -> - ctx.do_call VNull f [enc_string path] null_pos - ); - VNull - | _ -> error() - ); - "parse", Fun3 (fun s p b -> - match s, p, b with - | VString s, VAbstract (APos p), VBool b -> encode_expr ((get_ctx()).curapi.parse_string s p b) - | _ -> error() - ); - "make_expr", Fun2 (fun v p -> - match p with - | VAbstract (APos p) -> - let h_enum = hash "__enum__" and h_et = hash "__et__" and h_ct = hash "__ct__" in - let h_tag = hash "tag" and h_args = hash "args" in - let h_length = hash "length" in - let ctx = get_ctx() in - let error v = failwith ("Unsupported value " ^ ctx.do_string v) in - let make_path t = - let rec loop = function - | [] -> assert false - | [name] -> (Ast.EConst (Ast.Ident name),p) - | name :: l -> (Ast.EField (loop l,name),p) - in - let t = t_infos t in - loop (List.rev (if t.mt_module.m_path = t.mt_path then fst t.mt_path @ [snd t.mt_path] else fst t.mt_module.m_path @ [snd t.mt_module.m_path;snd t.mt_path])) - in - let rec loop = function - | VNull -> (Ast.EConst (Ast.Ident "null"),p) - | VBool b -> (Ast.EConst (Ast.Ident (if b then "true" else "false")),p) - | VInt i -> (Ast.EConst (Ast.Int (string_of_int i)),p) - | VInt32 i -> (Ast.EConst (Ast.Int (Int32.to_string i)),p) - | VFloat f -> (Ast.EConst (Ast.Float (string_of_float f)),p) - | VAbstract (APos p) -> - (Ast.EObjectDecl ( - ("fileName" , (Ast.EConst (Ast.String p.Ast.pfile) , p)) :: - ("lineNumber" , (Ast.EConst (Ast.Int (string_of_int (Lexer.get_error_line p))),p)) :: - ("className" , (Ast.EConst (Ast.String ("")),p)) :: - [] - ), p) - | VString _ | VArray _ | VAbstract _ | VFunction _ | VClosure _ as v -> error v - | VObject o as v -> - match o.oproto with - | None -> - (match get_field_opt o h_ct with - | Some (VAbstract (ATDecl t)) -> - make_path t - | _ -> - let fields = List.fold_left (fun acc (fid,v) -> (field_name ctx fid, loop v) :: acc) [] (Array.to_list o.ofields) in - (Ast.EObjectDecl fields, p)) - | Some proto -> - match get_field_opt proto h_enum, get_field_opt o h_a, get_field_opt o h_s, get_field_opt o h_length with - | _, Some (VArray a), _, Some (VInt len) -> - (Ast.EArrayDecl (List.map loop (Array.to_list (Array.sub a 0 len))),p) - | _, _, Some (VString s), _ -> - (Ast.EConst (Ast.String s),p) - | Some (VObject en), _, _, _ -> - (match get_field en h_et, get_field o h_tag with - | VAbstract (ATDecl t), VString tag -> - let e = (Ast.EField (make_path t,tag),p) in - (match get_field_opt o h_args with - | Some (VArray args) -> - let args = List.map loop (Array.to_list args) in - (Ast.ECall (e,args),p) - | _ -> e) - | _ -> - error v) - | _ -> - error v - in - encode_expr (loop v) - | _ -> error() - ); - "signature", Fun1 (fun v -> - let cache = ref [] in - let cache_count = ref 0 in - let hfiles = Hashtbl.create 0 in - let get_file f = - try - Hashtbl.find hfiles f - with Not_found -> - let ff = Common.unique_full_path f in - Hashtbl.add hfiles f ff; - ff - in - let do_cache (v:value) (v2:value) = - (* - tricky : we need to have a quick not-linear cache based on objects address - but we can't use address since the GC might be triggered here. - Instead let's mutate the object temporary. - *) - let vt = Obj.repr v in - let old = Obj.tag vt in - let old_val = Obj.field vt 0 in - let abstract_tag = 7 in - Obj.set_tag vt abstract_tag; - Obj.set_field vt 0 (Obj.repr (ACacheRef v2)); - cache := (vt,old,old_val) :: !cache; - incr cache_count - in - let rec loop v = - match v with - | VNull | VBool _ | VInt _ | VFloat _ | VString _ | VInt32 _ -> v - | VObject o -> - let o2 = { ofields = [||]; oproto = None } in - let v2 = VObject o2 in - do_cache v v2; - Array.iter (fun (f,v) -> if f <> h_class then set_field o2 f (loop v)) o.ofields; - (match o.oproto with - | None -> () - | Some p -> (match loop (VObject p) with VObject p2 -> o2.oproto <- Some p2 | _ -> assert false)); - v2 - | VArray a -> - let a2 = Array.create (Array.length a) VNull in - let v2 = VArray a2 in - do_cache v v2; - for i = 0 to Array.length a - 1 do - a2.(i) <- loop a.(i); - done; - v2 - | VFunction f -> - let v2 = VFunction (Obj.magic !cache_count) in - do_cache v v2; - v2 - | VClosure (vl,f) -> - let rl = ref [] in - let v2 = VClosure (Obj.magic rl, Obj.magic !cache_count) in - do_cache v v2; - rl := List.map loop vl; - v2 - | VAbstract (APos p) -> VAbstract (APos { p with Ast.pfile = get_file p.Ast.pfile }) - | VAbstract (ACacheRef v) -> v - | VAbstract (AHash h) -> - let h2 = Hashtbl.create 0 in - let v2 = VAbstract (AHash h2) in - do_cache v v2; - Hashtbl.iter (fun k v -> Hashtbl.add h2 k (loop v)) h2; - v2 - | VAbstract _ -> - let v2 = VAbstract (Obj.magic !cache_count) in - do_cache v v2; - v2 - in - let v = loop v in - (* restore *) - List.iter (fun (vt,tag,field) -> - Obj.set_tag vt tag; - Obj.set_field vt 0 field; - ) !cache; - VString (Digest.to_hex (Digest.string (Marshal.to_string v [Marshal.Closures]))) - ); - "to_complex", Fun1 (fun v -> - try encode_complex_type (make_complex_type (decode_type v)) - with Exit -> VNull - ); - "unify", Fun2 (fun t1 t2 -> - try Type.unify (decode_type t1) (decode_type t2); VBool true - with Unify_error _ -> VBool false - ); - "typeof", Fun1 (fun v -> - encode_type ((get_ctx()).curapi.typeof (decode_expr v)) - ); - "s_type", Fun1 (fun v -> - VString (Type.s_type (print_context()) (decode_type v)) - ); - "display", Fun1 (fun v -> - match v with - | VString s -> - VString ((get_ctx()).curapi.get_display s) - | _ -> - error() - ); - "allow_package", Fun1 (fun v -> - match v with - | VString s -> - (get_ctx()).curapi.allow_package s; - VNull - | _ -> error()); - "type_patch", Fun4 (fun t f s v -> - let p = (get_ctx()).curapi.type_patch in - (match t, f, s, v with - | VString t, VString f, VBool s, VString v -> p t f s (Some v) - | VString t, VString f, VBool s, VNull -> p t f s None - | _ -> error()); - VNull - ); - "meta_patch", Fun4 (fun m t f s -> - let p = (get_ctx()).curapi.meta_patch in - (match m, t, f, s with - | VString m, VString t, VString f, VBool s -> p m t (Some f) s - | VString m, VString t, VNull, VBool s -> p m t None s - | _ -> error()); - VNull - ); - "custom_js", Fun1 (fun f -> - match f with - | VFunction (Fun1 _) -> - let ctx = get_ctx() in - ctx.curapi.set_js_generator (fun api -> - ignore(catch_errors ctx (fun() -> ctx.do_call VNull f [api] null_pos)); - ); - VNull - | _ -> error() - ); - "get_pos_infos", Fun1 (fun p -> - match p with - | VAbstract (APos p) -> VObject (obj (hash_field (get_ctx())) ["min",VInt p.Ast.pmin;"max",VInt p.Ast.pmax;"file",VString p.Ast.pfile]) - | _ -> error() - ); - "make_pos", Fun3 (fun min max file -> - match min, max, file with - | VInt min, VInt max, VString file -> VAbstract (APos { Ast.pmin = min; Ast.pmax = max; Ast.pfile = file }) - | _ -> error() - ); - "add_resource", Fun2 (fun name data -> - match name, data with - | VString name, VString data -> - Hashtbl.replace (ccom()).resources name data; - let m = (get_ctx()).curapi.current_module() in - m.m_extra.m_binded_res <- PMap.add name data m.m_extra.m_binded_res; - VNull - | _ -> error() - ); - "local_type", Fun0 (fun() -> - match (get_ctx()).curapi.get_local_type() with - | None -> VNull - | Some t -> encode_type t - ); - "local_method", Fun0 (fun() -> - VString ((get_ctx()).curapi.get_local_method()) - ); - "local_using", Fun0 (fun() -> - enc_array (List.map encode_clref ((get_ctx()).curapi.get_local_using())) - ); - "local_vars", Fun0 (fun() -> - let vars = (get_ctx()).curapi.get_local_vars() in - let h = Hashtbl.create 0 in - PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars; - enc_hash h - ); - "follow", Fun2 (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_types tl t.t_type - | TLazy f -> - (!f)() - in - encode_type (match once with VNull | VBool false -> follow t | VBool true -> follow_once t | _ -> error()) - ); - "build_fields", Fun0 (fun() -> - (get_ctx()).curapi.get_build_fields() - ); - "define_type", Fun1 (fun v -> - (get_ctx()).curapi.define_type v; - VNull - ); - "add_class_path", Fun1 (fun v -> - match v with - | VString cp -> - let com = ccom() in - com.class_path <- (Common.normalize_path cp) :: com.class_path; - VNull - | _ -> - error() - ); - "add_native_lib", Fun1 (fun v -> - match v with - | VString file -> - let com = ccom() in - (match com.platform with - | Flash -> Genswf.add_swf_lib com file false - | _ -> failwith "Unsupported platform"); - VNull - | _ -> - error() - ); - "module_dependency", Fun2 (fun m file -> - match m, file with - | VString m, VString file -> - (get_ctx()).curapi.module_dependency m file false; - VNull - | _ -> error() - ); - "module_reuse_call", Fun2 (fun m mcall -> - match m, mcall with - | VString m, VString mcall -> - (get_ctx()).curapi.module_dependency m mcall true; - VNull - | _ -> error() - ); - "get_typed_expr", Fun1 (fun e -> - match e with - | VAbstract (ATExpr e) -> - encode_expr (make_ast e) - | _ -> error() - ); - "get_output", Fun0 (fun() -> - VString (ccom()).file - ); - "set_output", Fun1 (fun s -> - match s with - | VString s -> (ccom()).file <- s; VNull - | _ -> error() - ); - "get_display_pos", Fun0 (fun() -> - let p = !Parser.resume_display in - if p = Ast.null_pos then - VNull - else - VObject (obj (hash_field (get_ctx())) ["file",VString p.Ast.pfile;"pos",VInt p.Ast.pmin]) - ); - "pattern_locals", Fun2 (fun e t -> - let loc = (get_ctx()).curapi.get_pattern_locals (decode_expr e) (decode_type t) in - let h = Hashtbl.create 0 in - PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) loc; - enc_hash h - ); - "macro_context_reused", Fun1 (fun c -> - match c with - | VFunction (Fun0 _) -> - let ctx = get_ctx() in - ctx.on_reused <- (fun() -> catch_errors ctx (fun() -> ctx.do_call VNull c [] null_pos) = Some (VBool true)) :: ctx.on_reused; - VNull - | _ -> error() - ); - ] - -(* ---------------------------------------------------------------------- *) -(* EVAL *) - -let throw ctx p msg = - ctx.callstack <- { cpos = p; cthis = ctx.vthis; cstack = DynArray.length ctx.stack; cenv = ctx.venv } :: ctx.callstack; - exc (VString msg) - -let declare ctx var = - ctx.locals_map <- PMap.add var ctx.locals_count ctx.locals_map; - ctx.locals_count <- ctx.locals_count + 1 - -let save_locals ctx = - let old, oldcount = ctx.locals_map, ctx.locals_count in - (fun() -> - let n = ctx.locals_count - oldcount in - ctx.locals_count <- oldcount; - ctx.locals_map <- old; - n; - ) - -let get_ident ctx s = - try - let index = PMap.find s ctx.locals_map in - if index >= ctx.locals_barrier then - AccLocal (ctx.locals_count - index) - else (try - AccEnv (DynArray.index_of (fun s2 -> s = s2) ctx.locals_env) - with Not_found -> - let index = DynArray.length ctx.locals_env in - DynArray.add ctx.locals_env s; - AccEnv index - ) - with Not_found -> try - AccGlobal (PMap.find s ctx.globals) - with Not_found -> - let g = ref VNull in - ctx.globals <- PMap.add s g ctx.globals; - AccGlobal g - -let no_env = [||] - -let rec eval ctx (e,p) = - match e with - | EConst c -> - (match c with - | True -> (fun() -> VBool true) - | False -> (fun() -> VBool false) - | Null -> (fun() -> VNull) - | This -> (fun() -> ctx.vthis) - | Int i -> (fun() -> VInt i) - | Int32 i -> (fun() -> VInt32 i) - | Float f -> - let f = float_of_string f in - (fun() -> VFloat f) - | String s -> (fun() -> VString s) - | Builtin "loader" -> - (fun() -> ctx.loader) - | Builtin "exports" -> - (fun() -> ctx.exports) - | Builtin s -> - let b = (try Hashtbl.find builtins s with Not_found -> throw ctx p ("Builtin not found '" ^ s ^ "'")) in - (fun() -> b) - | Ident s -> - acc_get ctx p (get_ident ctx s)) - | EBlock el -> - let old = save_locals ctx in - let el = List.map (eval ctx) el in - let n = old() in - let rec loop = function - | [] -> VNull - | [e] -> e() - | e :: l -> - ignore(e()); - loop l - in - (fun() -> - let v = loop el in - pop ctx n; - v) - | EParenthesis e -> - eval ctx e - | EField (e,f) -> - let e = eval ctx e in - let h = hash_field ctx f in - (fun() -> - match e() with - | VObject o -> get_field o h - | _ -> throw ctx p ("Invalid field access : " ^ f) - ) - | ECall ((EConst (Builtin "mk_pos"),_),[(ECall (_,[EConst (String file),_]),_);(EConst (Int min),_);(EConst (Int max),_)]) -> - let pos = VAbstract (APos { Ast.pfile = file; Ast.pmin = min; Ast.pmax = max }) in - (fun() -> pos) - | ECall ((EConst (Builtin "typewrap"),_),[t]) -> - (fun() -> VAbstract (ATDecl (Obj.magic t))) - | ECall ((EConst (Builtin "delay_call"),_),[EConst (Int index),_]) -> - let f = ctx.curapi.delayed_macro index in - let fbuild = ref None in - let old = { ctx with gen = ctx.gen } in - let compile_delayed_call() = - let oldl, oldc, oldb, olde = ctx.locals_map, ctx.locals_count, ctx.locals_barrier, ctx.locals_env in - ctx.locals_map <- old.locals_map; - ctx.locals_count <- old.locals_count; - ctx.locals_barrier <- old.locals_barrier; - ctx.locals_env <- DynArray.copy old.locals_env; - let save = save_locals ctx in - let e = f() in - let n = save() in - let e = if DynArray.length ctx.locals_env = DynArray.length old.locals_env then - e - else - let n = DynArray.get ctx.locals_env (DynArray.length ctx.locals_env - 1) in - (fun() -> exc (VString ("Macro-in-macro call can't access to closure variable '" ^ n ^ "'"))) - in - ctx.locals_map <- oldl; - ctx.locals_count <- oldc; - ctx.locals_barrier <- oldb; - ctx.locals_env <- olde; - (fun() -> - let v = e() in - pop ctx n; - v - ) - in - (fun() -> - let e = (match !fbuild with - | Some e -> e - | None -> - let e = compile_delayed_call() in - fbuild := Some e; - e - ) in - e()) - | ECall (e,el) -> - let el = List.map (eval ctx) el in - (match fst e with - | EField (e,f) -> - let e = eval ctx e in - let h = hash_field ctx f in - (fun() -> - let pl = List.map (fun f -> f()) el in - let o = e() in - let f = (match o with - | VObject o -> get_field o h - | _ -> throw ctx p ("Invalid field access : " ^ f) - ) in - call ctx o f pl p - ) - | _ -> - let e = eval ctx e in - (fun() -> - let pl = List.map (fun f -> f()) el in - call ctx ctx.vthis (e()) pl p - )) - | EArray (e1,e2) -> - let e1 = eval ctx e1 in - let e2 = eval ctx e2 in - let acc = AccArray (e1,e2) in - acc_get ctx p acc - | EVars vl -> - let vl = List.map (fun (v,eo) -> - let eo = (match eo with None -> (fun() -> VNull) | Some e -> eval ctx e) in - declare ctx v; - eo - ) vl in - (fun() -> - List.iter (fun e -> push ctx (e())) vl; - VNull - ) - | EWhile (econd,e,NormalWhile) -> - let econd = eval ctx econd in - let e = eval ctx e in - let rec loop st = - match econd() with - | VBool true -> - let v = (try - ignore(e()); None - with - | Continue -> pop ctx (DynArray.length ctx.stack - st); None - | Break v -> pop ctx (DynArray.length ctx.stack - st); Some v - ) in - (match v with - | None -> loop st - | Some v -> v) - | _ -> - VNull - in - (fun() -> try loop (DynArray.length ctx.stack) with Sys.Break -> throw ctx p "Ctrl+C") - | EWhile (econd,e,DoWhile) -> - let e = eval ctx e in - let econd = eval ctx econd in - let rec loop st = - let v = (try - ignore(e()); None - with - | Continue -> pop ctx (DynArray.length ctx.stack - st); None - | Break v -> pop ctx (DynArray.length ctx.stack - st); Some v - ) in - match v with - | Some v -> v - | None -> - match econd() with - | VBool true -> loop st - | _ -> VNull - in - (fun() -> loop (DynArray.length ctx.stack)) - | EIf (econd,eif,eelse) -> - let econd = eval ctx econd in - let eif = eval ctx eif in - let eelse = (match eelse with None -> (fun() -> VNull) | Some e -> eval ctx e) in - (fun() -> - match econd() with - | VBool true -> eif() - | _ -> eelse() - ) - | ETry (e,exc,ecatch) -> - let old = save_locals ctx in - let e = eval ctx e in - let n1 = old() in - declare ctx exc; - let ecatch = eval ctx ecatch in - let n2 = old() in - (fun() -> - let vthis = ctx.vthis in - let venv = ctx.venv in - let stack = ctx.callstack in - let csize = ctx.callsize in - let size = DynArray.length ctx.stack in - try - pop_ret ctx e n1 - with Runtime v -> - let rec loop n l = - if n = 0 then List.map (fun s -> s.cpos) l else - match l with - | [] -> [] - | _ :: l -> loop (n - 1) l - in - ctx.exc <- loop (List.length stack) (List.rev ctx.callstack); - ctx.callstack <- stack; - ctx.callsize <- csize; - ctx.vthis <- vthis; - ctx.venv <- venv; - pop ctx (DynArray.length ctx.stack - size); - push ctx v; - pop_ret ctx ecatch n2 - ) - | EFunction (pl,e) -> - let old = save_locals ctx in - let oldb, oldenv = ctx.locals_barrier, ctx.locals_env in - ctx.locals_barrier <- ctx.locals_count; - ctx.locals_env <- DynArray.create(); - List.iter (declare ctx) pl; - let e = eval ctx e in - ignore(old()); - let env = ctx.locals_env in - ctx.locals_barrier <- oldb; - ctx.locals_env <- oldenv; - let env = DynArray.to_array (DynArray.map (fun s -> - acc_get ctx p (get_ident ctx s)) env - ) in - let init_env = if Array.length env = 0 then - (fun() -> no_env) - else - (fun() -> Array.map (fun e -> e()) env) - in - (match pl with - | [] -> - (fun() -> - let env = init_env() in - VFunction (Fun0 (fun() -> - ctx.venv <- env; - e()))) - | [a] -> - (fun() -> - let env = init_env() in - VFunction (Fun1 (fun v -> - ctx.venv <- env; - push ctx v; - e(); - ))) - | [a;b] -> - (fun() -> - let env = init_env() in - VFunction (Fun2 (fun va vb -> - ctx.venv <- env; - push ctx va; - push ctx vb; - e(); - ))) - | [a;b;c] -> - (fun() -> - let env = init_env() in - VFunction (Fun3 (fun va vb vc -> - ctx.venv <- env; - push ctx va; - push ctx vb; - push ctx vc; - e(); - ))) - | [a;b;c;d] -> - (fun() -> - let env = init_env() in - VFunction (Fun4 (fun va vb vc vd -> - ctx.venv <- env; - push ctx va; - push ctx vb; - push ctx vc; - push ctx vd; - e(); - ))) - | [a;b;c;d;pe] -> - (fun() -> - let env = init_env() in - VFunction (Fun5 (fun va vb vc vd ve -> - ctx.venv <- env; - push ctx va; - push ctx vb; - push ctx vc; - push ctx vd; - push ctx ve; - e(); - ))) - | _ -> - (fun() -> - let env = init_env() in - VFunction (FunVar (fun vl -> - if List.length vl != List.length pl then exc (VString "Invalid call"); - ctx.venv <- env; - List.iter (push ctx) vl; - e(); - ))) - ) - | EBinop (op,e1,e2) -> - eval_op ctx op e1 e2 p - | EReturn None -> - (fun() -> raise (Return VNull)) - | EReturn (Some e) -> - let e = eval ctx e in - (fun() -> raise (Return (e()))) - | EBreak None -> - (fun() -> raise (Break VNull)) - | EBreak (Some e) -> - let e = eval ctx e in - (fun() -> raise (Break (e()))) - | EContinue -> - (fun() -> raise Continue) - | ENext (e1,e2) -> - let e1 = eval ctx e1 in - let e2 = eval ctx e2 in - (fun() -> ignore(e1()); e2()) - | EObject fl -> - let fl = List.map (fun (f,e) -> hash_field ctx f, eval ctx e) fl in - let fields = Array.of_list (List.map (fun (f,_) -> f,VNull) fl) in - Array.sort (fun (f1,_) (f2,_) -> compare f1 f2) fields; - (fun() -> - let o = { - ofields = Array.copy fields; - oproto = None; - } in - List.iter (fun (f,e) -> set_field o f (e())) fl; - VObject o - ) - | ELabel l -> - assert false - | ESwitch (e1,el,eo) -> - let e1 = eval ctx e1 in - let el = List.map (fun (cond,e) -> cond, eval ctx cond, eval ctx e) el in - let eo = (match eo with None -> (fun() -> VNull) | Some e -> eval ctx e) in - let cases = (try - let max = ref (-1) in - let ints = List.map (fun (cond,_,e) -> - match fst cond with - | EConst (Int i) -> if i < 0 then raise Exit; if i > !max then max := i; i, e - | _ -> raise Exit - ) el in - let a = Array.create (!max + 1) eo in - List.iter (fun (i,e) -> a.(i) <- e) (List.rev ints); - Some a; - with - Exit -> None - ) in - let def v = - let rec loop = function - | [] -> eo() - | (_,c,e) :: l -> - if ctx.do_compare v (c()) = CEq then e() else loop l - in - loop el - in - (match cases with - | None -> (fun() -> def (e1())) - | Some t -> - (fun() -> - match e1() with - | VInt i -> if i >= 0 && i < Array.length t then t.(i)() else eo() - | v -> def v - )) - | ENeko _ -> - throw ctx p "Inline neko code unsupported" - -and eval_oop ctx p o field (params:value list) = - match get_field_opt o field with - | None -> None - | Some f -> Some (call ctx (VObject o) f params p) - -and eval_access ctx (e,p) = - match e with - | EField (e,f) -> - let v = eval ctx e in - AccField (v,f) - | EArray (e,eindex) -> - let v = eval ctx e in - let idx = eval ctx eindex in - AccArray (v,idx) - | EConst (Ident s) -> - get_ident ctx s - | EConst This -> - AccThis - | _ -> - throw ctx p "Invalid assign" - -and eval_access_get_set ctx (e,p) = - match e with - | EField (e,f) -> - let v = eval ctx e in - let cache = ref VNull in - AccField ((fun() -> cache := v(); !cache),f), AccField((fun() -> !cache), f) - | EArray (e,eindex) -> - let v = eval ctx e in - let idx = eval ctx eindex in - let vcache = ref VNull and icache = ref VNull in - AccArray ((fun() -> vcache := v(); !vcache),(fun() -> icache := idx(); !icache)), AccArray ((fun() -> !vcache),(fun() -> !icache)) - | EConst (Ident s) -> - let acc = get_ident ctx s in - acc, acc - | EConst This -> - AccThis, AccThis - | _ -> - throw ctx p "Invalid assign" - -and acc_get ctx p = function - | AccField (v,f) -> - let h = hash_field ctx f in - (fun() -> - match v() with - | VObject o -> get_field o h - | _ -> throw ctx p ("Invalid field access : " ^ f)) - | AccArray (e,index) -> - (fun() -> - let e = e() in - let index = index() in - (match index, e with - | VInt i, VArray a -> (try Array.get a i with _ -> VNull) - | VInt32 _, VArray _ -> VNull - | _, VObject o -> - (match eval_oop ctx p o h_get [index] with - | None -> throw ctx p "Invalid array access" - | Some v -> v) - | _ -> throw ctx p "Invalid array access")) - | AccLocal i -> - (fun() -> DynArray.get ctx.stack (DynArray.length ctx.stack - i)) - | AccGlobal g -> - (fun() -> !g) - | AccThis -> - (fun() -> ctx.vthis) - | AccEnv i -> - (fun() -> ctx.venv.(i)) - -and acc_set ctx p acc value = - match acc with - | AccField (v,f) -> - let h = hash_field ctx f in - (fun() -> - let v = v() in - let value = value() in - match v with - | VObject o -> set_field o h value; value - | _ -> throw ctx p ("Invalid field access : " ^ f)) - | AccArray (e,index) -> - (fun() -> - let e = e() in - let index = index() in - let value = value() in - (match index, e with - | VInt i, VArray a -> (try Array.set a i value; value with _ -> value) - | VInt32 _, VArray _ -> value - | _, VObject o -> - (match eval_oop ctx p o h_set [index;value] with - | None -> throw ctx p "Invalid array access" - | Some _ -> value); - | _ -> throw ctx p "Invalid array access")) - | AccLocal i -> - (fun() -> - let value = value() in - DynArray.set ctx.stack (DynArray.length ctx.stack - i) value; - value) - | AccGlobal g -> - (fun() -> - let value = value() in - g := value; - value) - | AccThis -> - (fun() -> - let value = value() in - ctx.vthis <- value; - value) - | AccEnv i -> - (fun() -> - let value = value() in - ctx.venv.(i) <- value; - value) - -and number_op ctx p sop iop fop oop rop v1 v2 = - (fun() -> - let v1 = v1() in - let v2 = v2() in - exc_number_op ctx p sop iop fop oop rop v1 v2) - -and exc_number_op ctx p sop iop fop oop rop v1 v2 = - match v1, v2 with - | VInt a, VInt b -> best_int (iop (Int32.of_int a) (Int32.of_int b)) - | VInt32 a, VInt b -> best_int (iop a (Int32.of_int b)) - | VInt a, VInt32 b -> best_int (iop (Int32.of_int a) b) - | VFloat a, VInt b -> VFloat (fop a (float_of_int b)) - | VFloat a, VInt32 b -> VFloat (fop a (Int32.to_float b)) - | VInt a, VFloat b -> VFloat (fop (float_of_int a) b) - | VInt32 a, VFloat b -> VFloat (fop (Int32.to_float a) b) - | VFloat a, VFloat b -> VFloat (fop a b) - | VInt32 a, VInt32 b -> best_int (iop a b) - | VObject o, _ -> - (match eval_oop ctx p o oop [v2] with - | Some v -> v - | None -> - match v2 with - | VObject o -> - (match eval_oop ctx p o rop [v1] with - | Some v -> v - | None -> throw ctx p sop) - | _ -> - throw ctx p sop) - | _ , VObject o -> - (match eval_oop ctx p o rop [v1] with - | Some v -> v - | None -> throw ctx p sop) - | _ -> - throw ctx p sop - -and int_op ctx p op iop v1 v2 = - (fun() -> - let v1 = v1() in - let v2 = v2() in - match v1, v2 with - | VInt a, VInt b -> best_int (iop (Int32.of_int a) (Int32.of_int b)) - | VInt32 a, VInt b -> best_int (iop a (Int32.of_int b)) - | VInt a, VInt32 b -> best_int (iop (Int32.of_int a) b) - | VInt32 a, VInt32 b -> best_int (iop a b) - | _ -> throw ctx p op) - -and base_op ctx op v1 v2 p = - match op with - | "+" -> - (fun() -> - let v1 = v1() in - let v2 = v2() in - match v1, v2 with - | (VInt _ | VInt32 _), (VInt _ | VInt32 _) | (VInt _ | VInt32 _), VFloat _ | VFloat _ , (VInt _ | VInt32 _) | VFloat _ , VFloat _ | VObject _ , _ | _ , VObject _ -> exc_number_op ctx p op Int32.add (+.) h_add h_radd v1 v2 - | VString a, _ -> VString (a ^ ctx.do_string v2) - | _, VString b -> VString (ctx.do_string v1 ^ b) - | _ -> throw ctx p op) - | "-" -> - number_op ctx p op Int32.sub (-.) h_sub h_rsub v1 v2 - | "*" -> - number_op ctx p op Int32.mul ( *. ) h_mult h_rmult v1 v2 - | "/" -> - (fun() -> - let v1 = v1() in - let v2 = v2() in - match v1, v2 with - | VInt i, VInt j -> VFloat ((float_of_int i) /. (float_of_int j)) - | VInt i, VInt32 j -> VFloat ((float_of_int i) /. (Int32.to_float j)) - | VInt32 i, VInt j -> VFloat ((Int32.to_float i) /. (float_of_int j)) - | VInt32 i, VInt32 j -> VFloat ((Int32.to_float i) /. (Int32.to_float j)) - | _ -> exc_number_op ctx p op Int32.div (/.) h_div h_rdiv v1 v2) - | "%" -> - number_op ctx p op (fun x y -> if y = 0l then throw ctx p op; Int32.rem x y) mod_float h_mod h_rmod v1 v2 - | "&" -> - int_op ctx p op Int32.logand v1 v2 - | "|" -> - int_op ctx p op Int32.logor v1 v2 - | "^" -> - int_op ctx p op Int32.logxor v1 v2 - | "<<" -> - int_op ctx p op (fun x y -> Int32.shift_left x (Int32.to_int y)) v1 v2 - | ">>" -> - int_op ctx p op (fun x y -> Int32.shift_right x (Int32.to_int y)) v1 v2 - | ">>>" -> - int_op ctx p op (fun x y -> Int32.shift_right_logical x (Int32.to_int y)) v1 v2 - | _ -> - throw ctx p op - -and eval_op ctx op e1 e2 p = - match op with - | "=" -> - let acc = eval_access ctx e1 in - let v = eval ctx e2 in - acc_set ctx p acc v - | "==" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CEq -> VBool true - | _ -> VBool false) - | "!=" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CEq -> VBool false - | _ -> VBool true) - | ">" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CSup -> VBool true - | _ -> VBool false) - | ">=" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CSup | CEq -> VBool true - | _ -> VBool false) - | "<" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CInf -> VBool true - | _ -> VBool false) - | "<=" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - (fun() -> - let v1 = v1() in - let v2 = v2() in - match ctx.do_compare v1 v2 with - | CInf | CEq -> VBool true - | _ -> VBool false) - | "+" | "-" | "*" | "/" | "%" | "|" | "&" | "^" | "<<" | ">>" | ">>>" -> - let v1 = eval ctx e1 in - let v2 = eval ctx e2 in - base_op ctx op v1 v2 p - | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "&=" | "^=" -> - let aset, aget = eval_access_get_set ctx e1 in - let v1 = acc_get ctx p aget in - let v2 = eval ctx e2 in - let v = base_op ctx (String.sub op 0 (String.length op - 1)) v1 v2 p in - acc_set ctx p aset v - | "&&" -> - let e1 = eval ctx e1 in - let e2 = eval ctx e2 in - (fun() -> - match e1() with - | VBool false as v -> v - | _ -> e2()) - | "||" -> - let e1 = eval ctx e1 in - let e2 = eval ctx e2 in - (fun() -> - match e1() with - | VBool true as v -> v - | _ -> e2()) - | "++=" | "--=" -> - let aset, aget = eval_access_get_set ctx e1 in - let v1 = acc_get ctx p aget in - let v2 = eval ctx e2 in - let vcache = ref VNull in - let v = base_op ctx (String.sub op 0 1) (fun() -> vcache := v1(); !vcache) v2 p in - let set = acc_set ctx p aset v in - (fun() -> ignore(set()); !vcache) - | _ -> - throw ctx p ("Unsupported " ^ op) - -and call ctx vthis vfun pl p = - let oldthis = ctx.vthis in - let stackpos = DynArray.length ctx.stack in - let oldstack = ctx.callstack in - let oldsize = ctx.callsize in - let oldenv = ctx.venv in - ctx.vthis <- vthis; - ctx.callstack <- { cpos = p; cthis = oldthis; cstack = stackpos; cenv = oldenv } :: ctx.callstack; - ctx.callsize <- oldsize + 1; - if oldsize > 200 then exc (VString "Stack overflow"); - let ret = (try - (match vfun with - | VClosure (vl,f) -> - f vl pl - | VFunction f -> - (match pl, f with - | [], Fun0 f -> f() - | [a], Fun1 f -> f a - | [a;b], Fun2 f -> f a b - | [a;b;c], Fun3 f -> f a b c - | [a;b;c;d], Fun4 f -> f a b c d - | [a;b;c;d;e], Fun5 f -> f a b c d e - | _, FunVar f -> f pl - | _ -> exc (VString (Printf.sprintf "Invalid call (%d args instead of %d)" (List.length pl) (nargs f)))) - | VAbstract (ALazyType f) -> - encode_type ((!f)()) - | _ -> - exc (VString "Invalid call")) - with Return v -> v - | Stack_overflow -> exc (VString "Compiler Stack overflow") - | Sys_error msg | Failure msg -> exc (VString msg) - | Unix.Unix_error (_,cmd,msg) -> exc (VString ("Error " ^ cmd ^ " " ^ msg)) - | Invalid_expr -> exc (VString "Invalid input value") - | Builtin_error | Invalid_argument _ -> exc (VString "Invalid call")) in - ctx.vthis <- oldthis; - ctx.venv <- oldenv; - ctx.callstack <- oldstack; - ctx.callsize <- oldsize; - pop ctx (DynArray.length ctx.stack - stackpos); - ret - -(* ---------------------------------------------------------------------- *) -(* OTHERS *) - -let rec to_string ctx n v = - if n > 5 then - "<...>" - else let n = n + 1 in - match v with - | VNull -> "null" - | VBool true -> "true" - | VBool false -> "false" - | VInt i -> string_of_int i - | VInt32 i -> Int32.to_string i - | VFloat f -> - let s = string_of_float f in - let len = String.length s in - if String.unsafe_get s (len - 1) = '.' then String.sub s 0 (len - 1) else s - | VString s -> s - | VArray vl -> "[" ^ String.concat "," (Array.to_list (Array.map (to_string ctx n) vl)) ^ "]" - | VAbstract a -> - (match a with - | APos p -> "#pos(" ^ Lexer.get_error_pos (Printf.sprintf "%s:%d:") p ^ ")" - | _ -> "#abstract") - | VFunction f -> "#function:" ^ string_of_int (nargs f) - | VClosure _ -> "#function:-1" - | VObject o -> - match eval_oop ctx null_pos o h_string [] with - | Some (VString s) -> s - | _ -> - let b = Buffer.create 0 in - let first = ref true in - Buffer.add_char b '{'; - Array.iter (fun (f,v) -> - if !first then begin - Buffer.add_char b ' '; - first := false; - end else - Buffer.add_string b ", "; - Buffer.add_string b (field_name ctx f); - Buffer.add_string b " => "; - Buffer.add_string b (to_string ctx n v); - ) o.ofields; - Buffer.add_string b (if !first then "}" else " }"); - Buffer.contents b - -let rec compare ctx a b = - let fcmp (a:float) b = if a = b then CEq else if a < b then CInf else CSup in - let scmp (a:string) b = if a = b then CEq else if a < b then CInf else CSup in - let icmp (a:int32) b = let l = Int32.compare a b in if l = 0 then CEq else if l < 0 then CInf else CSup in - match a, b with - | VNull, VNull -> CEq - | VInt a, VInt b -> if a = b then CEq else if a < b then CInf else CSup - | VInt32 a, VInt32 b -> icmp a b - | VInt a, VInt32 b -> icmp (Int32.of_int a) b - | VInt32 a, VInt b -> icmp a (Int32.of_int b) - | VFloat a, VFloat b -> fcmp a b - | VFloat a, VInt b -> fcmp a (float_of_int b) - | VFloat a, VInt32 b -> fcmp a (Int32.to_float b) - | VInt a, VFloat b -> fcmp (float_of_int a) b - | VInt32 a, VFloat b -> fcmp (Int32.to_float a) b - | VBool a, VBool b -> if a = b then CEq else if a then CSup else CInf - | VString a, VString b -> scmp a b - | VInt _ , VString s - | VInt32 _, VString s - | VFloat _ , VString s - | VBool _ , VString s -> scmp (to_string ctx 0 a) s - | VString s, VInt _ - | VString s, VInt32 _ - | VString s, VFloat _ - | VString s, VBool _ -> scmp s (to_string ctx 0 b) - | VObject oa, VObject ob -> - if oa == ob then CEq else - (match eval_oop ctx null_pos oa h_compare [b] with - | Some (VInt i) -> if i = 0 then CEq else if i < 0 then CInf else CSup - | _ -> CUndef) - | VAbstract a, VAbstract b -> - if a == b then CEq else CUndef - | VArray a, VArray b -> - if a == b then CEq else CUndef - | VFunction a, VFunction b -> - if a == b then CEq else CUndef - | VClosure (la,fa), VClosure (lb,fb) -> - if la == lb && fa == fb then CEq else CUndef - | _ -> - CUndef - -let select ctx = - get_ctx_ref := (fun() -> ctx) - -let load_prim ctx f n = - match f, n with - | VString f, VInt n -> - let lib, fname = (try ExtString.String.split f "@" with _ -> "", f) in - (try - let f = (match lib with - | "std" -> Hashtbl.find std_lib fname - | "macro" -> Hashtbl.find macro_lib fname - | "regexp" -> Hashtbl.find reg_lib fname - | "zlib" -> Hashtbl.find z_lib fname - | _ -> failwith ("You cannot use the library '" ^ lib ^ "' inside a macro"); - ) in - if nargs f <> n then raise Not_found; - VFunction f - with Not_found -> - VFunction (FunVar (fun _ -> exc (VString ("Primitive not found " ^ f ^ ":" ^ string_of_int n))))) - | _ -> - exc (VString "Invalid call") - -let create com api = - let loader = obj hash [ - "args",VArray (Array.of_list (List.map (fun s -> VString s) com.sys_args)); - "loadprim",VFunction (Fun2 (fun a b -> (get_ctx()).do_loadprim a b)); - "loadmodule",VFunction (Fun2 (fun a b -> assert false)); - ] in - let ctx = { - gen = Genneko.new_context com 2 true; - types = Hashtbl.create 0; - error = false; - error_proto = { ofields = [||]; oproto = None }; - prototypes = Hashtbl.create 0; - enums = [||]; - (* eval *) - locals_map = PMap.empty; - locals_count = 0; - locals_barrier = 0; - locals_env = DynArray.create(); - globals = PMap.empty; - (* runtime *) - callstack = []; - callsize = 0; - stack = DynArray.create(); - exc = []; - vthis = VNull; - venv = [||]; - fields_cache = Hashtbl.copy constants; - (* api *) - do_call = Obj.magic(); - do_string = Obj.magic(); - do_loadprim = Obj.magic(); - do_compare = Obj.magic(); - (* context *) - curapi = api; - loader = VObject loader; - on_reused = []; - is_reused = true; - exports = VObject { ofields = [||]; oproto = None }; - } in - ctx.do_call <- call ctx; - ctx.do_string <- to_string ctx 0; - ctx.do_loadprim <- load_prim ctx; - ctx.do_compare <- compare ctx; - select ctx; - List.iter (fun e -> ignore((eval ctx e)())) (Genneko.header()); - ctx - - - -let do_reuse ctx = - ctx.is_reused <- false - -let can_reuse ctx types = - let has_old_version t = - let inf = Type.t_infos t in - try - Hashtbl.find ctx.types inf.mt_path <> inf.mt_module.m_id - with Not_found -> - false - in - if List.exists has_old_version types then - false - else if ctx.is_reused then - true - else if not (List.for_all (fun f -> f()) ctx.on_reused) then - false - else begin - ctx.is_reused <- true; - true; - end - -let add_types ctx types ready = - let types = List.filter (fun t -> - let path = Type.t_path t in - if Hashtbl.mem ctx.types path then false else begin - Hashtbl.add ctx.types path (Type.t_infos t).mt_module.m_id; - true; - end - ) types in - List.iter ready types; - let e = (EBlock (Genneko.build ctx.gen types), null_pos) in - ignore(catch_errors ctx (fun() -> ignore((eval ctx e)()))) - -let eval_expr ctx e = - let e = Genneko.gen_expr ctx.gen e in - catch_errors ctx (fun() -> (eval ctx e)()) - -let get_path ctx path p = - let rec loop = function - | [] -> assert false - | [x] -> (EConst (Ident x),p) - | x :: l -> (EField (loop l,x),p) - in - (eval ctx (loop (List.rev path)))() - -let set_error ctx e = - ctx.error <- e - -let call_path ctx path f vl api = - if ctx.error then - None - else let old = ctx.curapi in - ctx.curapi <- api; - let p = Genneko.pos ctx.gen api.pos in - catch_errors ctx ~final:(fun() -> ctx.curapi <- old) (fun() -> - match get_path ctx path p with - | VObject o -> - let f = get_field o (hash f) in - call ctx (VObject o) f vl p - | _ -> assert false - ) - -(* ---------------------------------------------------------------------- *) -(* EXPR ENCODING *) - -type enum_index = - | IExpr - | IBinop - | IUnop - | IConst - | ITParam - | ICType - | IField - | IType - | IFieldKind - | IMethodKind - | IVarAccess - | IAccess - | IClassKind - -let enum_name = function - | IExpr -> "ExprDef" - | IBinop -> "Binop" - | IUnop -> "Unop" - | IConst -> "Constant" - | ITParam -> "TypeParam" - | ICType -> "ComplexType" - | IField -> "FieldType" - | IType -> "Type" - | IFieldKind -> "FieldKind" - | IMethodKind -> "MethodKind" - | IVarAccess -> "VarAccess" - | IAccess -> "Access" - | IClassKind -> "ClassKind" - -let init ctx = - let enums = [IExpr;IBinop;IUnop;IConst;ITParam;ICType;IField;IType;IFieldKind;IMethodKind;IVarAccess;IAccess;IClassKind] in - let get_enum_proto e = - match get_path ctx ["haxe";"macro";enum_name e] null_pos with - | VObject e -> - (match get_field e h_constructs with - | VObject cst -> - (match get_field cst h_a with - | VArray a -> - Array.map (fun s -> - match s with - | VObject s -> (match get_field s h_s with VString s -> get_field e (hash s),s | _ -> assert false) - | _ -> assert false - ) a - | _ -> assert false) - | _ -> assert false) - | _ -> failwith ("haxe.macro." ^ enum_name e ^ " does not exists") - in - ctx.enums <- Array.of_list (List.map get_enum_proto enums); - ctx.error_proto <- (match get_path ctx ["haxe";"macro";"Error";"prototype"] null_pos with VObject p -> p | _ -> failwith ("haxe.macro.Error does not exists")) - -open Ast - -let null f = function - | None -> VNull - | Some v -> f v - -let encode_pos p = - VAbstract (APos p) - -let enc_inst path fields = - let ctx = get_ctx() in - let p = (try Hashtbl.find ctx.prototypes path with Not_found -> try - (match get_path ctx (path@["prototype"]) Nast.null_pos with - | VObject o -> Hashtbl.add ctx.prototypes path o; o - | _ -> raise (Runtime VNull)) - with Runtime _ -> - failwith ("Prototype not found " ^ String.concat "." path) - ) in - let o = obj hash fields in - o.oproto <- Some p; - VObject o - -let enc_array l = - let a = Array.of_list l in - enc_inst ["Array"] [ - "__a", VArray a; - "length", VInt (Array.length a); - ] - -let enc_string s = - enc_inst ["String"] [ - "__s", VString s; - "length", VInt (String.length s) - ] - -let enc_hash h = - enc_inst ["haxe";"ds";"StringMap"] [ - "h", VAbstract (AHash h); - ] - -let enc_obj l = VObject (obj hash l) - -let enc_enum (i:enum_index) index pl = - let eindex : int = Obj.magic i in - let edef = (get_ctx()).enums.(eindex) in - if pl = [] then - fst edef.(index) - else - enc_inst ["haxe";"macro";enum_name i] [ - "tag", VString (snd edef.(index)); - "index", VInt index; - "args", VArray (Array.of_list pl); - ] - -let compiler_error msg pos = - exc (enc_inst ["haxe";"macro";"Error"] [("message",enc_string msg);("pos",encode_pos pos)]) - -let encode_const c = - let tag, pl = match c with - | Int s -> 0, [enc_string s] - | Float s -> 1, [enc_string s] - | String s -> 2, [enc_string s] - | Ident s -> 3, [enc_string s] - | Regexp (s,opt) -> 4, [enc_string s;enc_string opt] - in - enc_enum IConst tag pl - -let rec encode_binop op = - let tag, pl = match op with - | OpAdd -> 0, [] - | OpMult -> 1, [] - | OpDiv -> 2, [] - | OpSub -> 3, [] - | OpAssign -> 4, [] - | OpEq -> 5, [] - | OpNotEq -> 6, [] - | OpGt -> 7, [] - | OpGte -> 8, [] - | OpLt -> 9, [] - | OpLte -> 10, [] - | OpAnd -> 11, [] - | OpOr -> 12, [] - | OpXor -> 13, [] - | OpBoolAnd -> 14, [] - | OpBoolOr -> 15, [] - | OpShl -> 16, [] - | OpShr -> 17, [] - | OpUShr -> 18, [] - | OpMod -> 19, [] - | OpAssignOp op -> 20, [encode_binop op] - | OpInterval -> 21, [] - | OpArrow -> 22, [] - in - enc_enum IBinop tag pl - -let encode_unop op = - let tag = match op with - | Increment -> 0 - | Decrement -> 1 - | Not -> 2 - | Neg -> 3 - | NegBits -> 4 - in - enc_enum IUnop tag [] - -let rec encode_path t = - let fields = [ - "pack", enc_array (List.map enc_string t.tpackage); - "name", enc_string t.tname; - "params", enc_array (List.map encode_tparam t.tparams); - ] in - enc_obj (match t.tsub with - | None -> fields - | Some s -> ("sub", enc_string s) :: fields) - -and encode_tparam = function - | TPType t -> enc_enum ITParam 0 [encode_ctype t] - | TPExpr e -> enc_enum ITParam 1 [encode_expr e] - -and encode_access a = - let tag = match a with - | APublic -> 0 - | APrivate -> 1 - | AStatic -> 2 - | AOverride -> 3 - | ADynamic -> 4 - | AInline -> 5 - | AMacro -> 6 - in - enc_enum IAccess tag [] - -and encode_meta_entry (m,ml,p) = - enc_obj [ - "name", enc_string (fst (MetaInfo.to_string m)); - "params", enc_array (List.map encode_expr ml); - "pos", encode_pos p; - ] - -and encode_meta_content m = - enc_array (List.map encode_meta_entry m) - -and encode_field (f:class_field) = - let tag, pl = match f.cff_kind with - | FVar (t,e) -> 0, [null encode_ctype t; null encode_expr e] - | FFun f -> 1, [encode_fun f] - | FProp (get,set, t, e) -> 2, [enc_string get; enc_string set; null encode_ctype t; null encode_expr e] - in - enc_obj [ - "name",enc_string f.cff_name; - "doc", null enc_string f.cff_doc; - "pos", encode_pos f.cff_pos; - "kind", enc_enum IField tag pl; - "meta", encode_meta_content f.cff_meta; - "access", enc_array (List.map encode_access f.cff_access); - ] - -and encode_ctype t = - let tag, pl = match t with - | CTPath p -> - 0, [encode_path p] - | CTFunction (pl,r) -> - 1, [enc_array (List.map encode_ctype pl);encode_ctype r] - | CTAnonymous fl -> - 2, [enc_array (List.map encode_field fl)] - | CTParent t -> - 3, [encode_ctype t] - | CTExtend (t,fields) -> - 4, [encode_path t; enc_array (List.map encode_field fields)] - | CTOptional t -> - 5, [encode_ctype t] - in - enc_enum ICType tag pl - -and encode_tparam_decl tp = - enc_obj [ - "name", enc_string tp.tp_name; - "params", enc_array (List.map encode_tparam_decl tp.tp_params); - "constraints", enc_array (List.map encode_ctype tp.tp_constraints); - ] - -and encode_fun f = - enc_obj [ - "params", enc_array (List.map encode_tparam_decl f.f_params); - "args", enc_array (List.map (fun (n,opt,t,e) -> - enc_obj [ - "name", enc_string n; - "opt", VBool opt; - "type", null encode_ctype t; - "value", null encode_expr e; - ] - ) f.f_args); - "ret", null encode_ctype f.f_type; - "expr", null encode_expr f.f_expr - ] - -and encode_expr e = - let rec loop (e,p) = - let tag, pl = match e with - | EConst c -> - 0, [encode_const c] - | EArray (e1,e2) -> - 1, [loop e1;loop e2] - | EBinop (op,e1,e2) -> - 2, [encode_binop op;loop e1;loop e2] - | EField (e,f) -> - 3, [loop e;enc_string f] - | EParenthesis e -> - 4, [loop e] - | EObjectDecl fl -> - 5, [enc_array (List.map (fun (f,e) -> enc_obj [ - "field",enc_string f; - "expr",loop e; - ]) fl)] - | EArrayDecl el -> - 6, [enc_array (List.map loop el)] - | ECall (e,el) -> - 7, [loop e;enc_array (List.map loop el)] - | ENew (p,el) -> - 8, [encode_path p; enc_array (List.map loop el)] - | EUnop (op,flag,e) -> - 9, [encode_unop op; VBool (match flag with Prefix -> false | Postfix -> true); loop e] - | EVars vl -> - 10, [enc_array (List.map (fun (v,t,eo) -> - enc_obj [ - "name",enc_string v; - "type",null encode_ctype t; - "expr",null loop eo; - ] - ) vl)] - | EFunction (name,f) -> - 11, [null enc_string name; encode_fun f] - | EBlock el -> - 12, [enc_array (List.map loop el)] - | EFor (e,eloop) -> - 13, [loop e;loop eloop] - | EIn (e1,e2) -> - 14, [loop e1;loop e2] - | EIf (econd,e,eelse) -> - 15, [loop econd;loop e;null loop eelse] - | EWhile (econd,e,flag) -> - 16, [loop econd;loop e;VBool (match flag with NormalWhile -> true | DoWhile -> false)] - | ESwitch (e,cases,eopt) -> - 17, [loop e;enc_array (List.map (fun (ecl,eg,e) -> - enc_obj [ - "values",enc_array (List.map loop ecl); - "guard",null loop eg; - "expr",null loop e - ] - ) cases);null encode_null_expr eopt] - | ETry (e,catches) -> - 18, [loop e;enc_array (List.map (fun (v,t,e) -> - enc_obj [ - "name",enc_string v; - "type",encode_ctype t; - "expr",loop e - ] - ) catches)] - | EReturn eo -> - 19, [null loop eo] - | EBreak -> - 20, [] - | EContinue -> - 21, [] - | EUntyped e -> - 22, [loop e] - | EThrow e -> - 23, [loop e] - | ECast (e,t) -> - 24, [loop e; null encode_ctype t] - | EDisplay (e,flag) -> - 25, [loop e; VBool flag] - | EDisplayNew t -> - 26, [encode_path t] - | ETernary (econd,e1,e2) -> - 27, [loop econd;loop e1;loop e2] - | ECheckType (e,t) -> - 28, [loop e; encode_ctype t] - | EMeta (m,e) -> - 29, [encode_meta_entry m;loop e] - in - enc_obj [ - "pos", encode_pos p; - "expr", enc_enum IExpr tag pl; - ] - in - loop e - -and encode_null_expr e = - match e with - | None -> - enc_obj ["pos", VNull;"expr",VNull] - | Some e -> - encode_expr e - -(* ---------------------------------------------------------------------- *) -(* EXPR DECODING *) - -let opt f v = - match v with - | VNull -> None - | _ -> Some (f v) - -let opt_list f v = - match v with - | VNull -> [] - | _ -> f v - -let decode_pos = function - | VAbstract (APos p) -> p - | _ -> raise Invalid_expr - -let field v f = - match v with - | VObject o -> get_field o (hash f) - | _ -> raise Invalid_expr - -let decode_enum v = - match field v "index", field v "args" with - | VInt i, VNull -> i, [] - | VInt i, VArray a -> i, Array.to_list a - | _ -> raise Invalid_expr - -let dec_bool = function - | VBool b -> b - | _ -> raise Invalid_expr - -let dec_string v = - match field v "__s" with - | VString s -> s - | _ -> raise Invalid_expr - -let dec_array v = - match field v "__a", field v "length" with - | VArray a, VInt l -> Array.to_list (if Array.length a = l then a else Array.sub a 0 l) - | _ -> raise Invalid_expr - -let decode_const c = - match decode_enum c with - | 0, [s] -> Int (dec_string s) - | 1, [s] -> Float (dec_string s) - | 2, [s] -> String (dec_string s) - | 3, [s] -> Ident (dec_string s) - | 4, [s;opt] -> Regexp (dec_string s, dec_string opt) - | 5, [s] -> Ident (dec_string s) (** deprecated CType, keep until 3.0 release **) - | _ -> raise Invalid_expr - -let rec decode_op op = - match decode_enum op with - | 0, [] -> OpAdd - | 1, [] -> OpMult - | 2, [] -> OpDiv - | 3, [] -> OpSub - | 4, [] -> OpAssign - | 5, [] -> OpEq - | 6, [] -> OpNotEq - | 7, [] -> OpGt - | 8, [] -> OpGte - | 9, [] -> OpLt - | 10, [] -> OpLte - | 11, [] -> OpAnd - | 12, [] -> OpOr - | 13, [] -> OpXor - | 14, [] -> OpBoolAnd - | 15, [] -> OpBoolOr - | 16, [] -> OpShl - | 17, [] -> OpShr - | 18, [] -> OpUShr - | 19, [] -> OpMod - | 20, [op] -> OpAssignOp (decode_op op) - | 21, [] -> OpInterval - | 22,[] -> OpArrow - | _ -> raise Invalid_expr - -let decode_unop op = - match decode_enum op with - | 0, [] -> Increment - | 1, [] -> Decrement - | 2, [] -> Not - | 3, [] -> Neg - | 4, [] -> NegBits - | _ -> raise Invalid_expr - -let rec decode_path t = - { - tpackage = List.map dec_string (dec_array (field t "pack")); - tname = dec_string (field t "name"); - tparams = List.map decode_tparam (dec_array (field t "params")); - tsub = opt dec_string (field t "sub"); - } - -and decode_tparam v = - match decode_enum v with - | 0,[t] -> TPType (decode_ctype t) - | 1,[e] -> TPExpr (decode_expr e) - | _ -> raise Invalid_expr - -and decode_tparam_decl v = - { - tp_name = dec_string (field v "name"); - tp_constraints = (match field v "constraints" with VNull -> [] | a -> List.map decode_ctype (dec_array a)); - tp_params = (match field v "params" with VNull -> [] | a -> List.map decode_tparam_decl (dec_array a)); - } - -and decode_fun v = - { - f_params = List.map decode_tparam_decl (dec_array (field v "params")); - f_args = List.map (fun o -> - (dec_string (field o "name"),dec_bool (field o "opt"),opt decode_ctype (field o "type"),opt decode_expr (field o "value")) - ) (dec_array (field v "args")); - f_type = opt decode_ctype (field v "ret"); - f_expr = opt decode_expr (field v "expr"); - } - -and decode_access v = - match decode_enum v with - | 0, [] -> APublic - | 1, [] -> APrivate - | 2, [] -> AStatic - | 3, [] -> AOverride - | 4, [] -> ADynamic - | 5, [] -> AInline - | 6, [] -> AMacro - | _ -> raise Invalid_expr - -and decode_meta_entry v = - MetaInfo.from_string (dec_string (field v "name")), List.map decode_expr (dec_array (field v "params")), decode_pos (field v "pos") - -and decode_meta_content v = - List.map decode_meta_entry (dec_array v) - -and decode_field v = - let fkind = match decode_enum (field v "kind") with - | 0, [t;e] -> - FVar (opt decode_ctype t, opt decode_expr e) - | 1, [f] -> - FFun (decode_fun f) - | 2, [get;set; t; e] -> - FProp (dec_string get, dec_string set, opt decode_ctype t, opt decode_expr e) - | _ -> - raise Invalid_expr - in - { - cff_name = dec_string (field v "name"); - cff_doc = opt dec_string (field v "doc"); - cff_pos = decode_pos (field v "pos"); - cff_kind = fkind; - cff_access = List.map decode_access (opt_list dec_array (field v "access")); - cff_meta = opt_list decode_meta_content (field v "meta"); - } - -and decode_ctype t = - match decode_enum t with - | 0, [p] -> - CTPath (decode_path p) - | 1, [a;r] -> - CTFunction (List.map decode_ctype (dec_array a), decode_ctype r) - | 2, [fl] -> - CTAnonymous (List.map decode_field (dec_array fl)) - | 3, [t] -> - CTParent (decode_ctype t) - | 4, [t;fl] -> - CTExtend (decode_path t, List.map decode_field (dec_array fl)) - | 5, [t] -> - CTOptional (decode_ctype t) - | _ -> - raise Invalid_expr - -let rec decode_expr v = - let rec loop v = - (decode (field v "expr"), decode_pos (field v "pos")) - and decode e = - match decode_enum e with - | 0, [c] -> - EConst (decode_const c) - | 1, [e1;e2] -> - EArray (loop e1, loop e2) - | 2, [op;e1;e2] -> - EBinop (decode_op op, loop e1, loop e2) - | 3, [e;f] -> - EField (loop e, dec_string f) - | 4, [e] -> - EParenthesis (loop e) - | 5, [a] -> - EObjectDecl (List.map (fun o -> - (dec_string (field o "field"), loop (field o "expr")) - ) (dec_array a)) - | 6, [a] -> - EArrayDecl (List.map loop (dec_array a)) - | 7, [e;el] -> - ECall (loop e,List.map loop (dec_array el)) - | 8, [t;el] -> - ENew (decode_path t,List.map loop (dec_array el)) - | 9, [op;VBool f;e] -> - EUnop (decode_unop op,(if f then Postfix else Prefix),loop e) - | 10, [vl] -> - EVars (List.map (fun v -> - (dec_string (field v "name"),opt decode_ctype (field v "type"),opt loop (field v "expr")) - ) (dec_array vl)) - | 11, [fname;f] -> - EFunction (opt dec_string fname,decode_fun f) - | 12, [el] -> - EBlock (List.map loop (dec_array el)) - | 13, [e1;e2] -> - EFor (loop e1, loop e2) - | 14, [e1;e2] -> - EIn (loop e1, loop e2) - | 15, [e1;e2;e3] -> - EIf (loop e1, loop e2, opt loop e3) - | 16, [e1;e2;VBool flag] -> - EWhile (loop e1,loop e2,if flag then NormalWhile else DoWhile) - | 17, [e;cases;eo] -> - let cases = List.map (fun c -> - (List.map loop (dec_array (field c "values")),opt loop (field c "guard"),opt loop (field c "expr")) - ) (dec_array cases) in - ESwitch (loop e,cases,opt decode_null_expr eo) - | 18, [e;catches] -> - let catches = List.map (fun c -> - (dec_string (field c "name"),decode_ctype (field c "type"),loop (field c "expr")) - ) (dec_array catches) in - ETry (loop e, catches) - | 19, [e] -> - EReturn (opt loop e) - | 20, [] -> - EBreak - | 21, [] -> - EContinue - | 22, [e] -> - EUntyped (loop e) - | 23, [e] -> - EThrow (loop e) - | 24, [e;t] -> - ECast (loop e,opt decode_ctype t) - | 25, [e;f] -> - EDisplay (loop e,dec_bool f) - | 26, [t] -> - EDisplayNew (decode_path t) - | 27, [e1;e2;e3] -> - ETernary (loop e1,loop e2,loop e3) - | 28, [e;t] -> - ECheckType (loop e, decode_ctype t) - | 29, [m;e] -> - EMeta (decode_meta_entry m,loop e) - | 30, [e;f] -> - EField (loop e, dec_string f) (*** deprecated EType, keep until haxe 3 **) - | _ -> - raise Invalid_expr - in - try - loop v - with Stack_overflow -> - raise Invalid_expr - -and decode_null_expr v = - match field v "expr" with - | VNull -> None - | _ -> Some (decode_expr v) - - -(* ---------------------------------------------------------------------- *) -(* TYPE ENCODING *) - -let encode_ref v convert tostr = - enc_obj [ - "get", VFunction (Fun0 (fun() -> convert v)); - "__string", VFunction (Fun0 (fun() -> VString (tostr()))); - "toString", VFunction (Fun0 (fun() -> enc_string (tostr()))); - "$", VAbstract (AUnsafe (Obj.repr v)); - ] - -let decode_ref v : 'a = - match field v "$" with - | VAbstract (AUnsafe t) -> Obj.obj t - | _ -> raise Invalid_expr - -let encode_pmap convert m = - let h = Hashtbl.create 0 in - PMap.iter (fun k v -> Hashtbl.add h (VString k) (convert v)) m; - enc_hash h - -let encode_pmap_array convert m = - let l = ref [] in - PMap.iter (fun _ v -> l := !l @ [(convert v)]) m; - enc_array !l - -let encode_array convert l = - enc_array (List.map convert l) - -let encode_meta m set = - let meta = ref m in - enc_obj [ - "get", VFunction (Fun0 (fun() -> - encode_meta_content (!meta) - )); - "add", VFunction (Fun3 (fun k vl p -> - (try - let el = List.map decode_expr (dec_array vl) in - meta := (MetaInfo.from_string (dec_string k), el, decode_pos p) :: !meta; - set (!meta) - with Invalid_expr -> - failwith "Invalid expression"); - VNull - )); - "remove", VFunction (Fun1 (fun k -> - let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in - meta := List.filter (fun (m,_,_) -> m <> k) (!meta); - set (!meta); - VNull - )); - "has", VFunction (Fun1 (fun k -> - let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in - VBool (List.exists (fun (m,_,_) -> m = k) (!meta)); - )); - ] - -let rec encode_mtype t fields = - let i = t_infos t in - enc_obj ([ - "__t", VAbstract (ATDecl t); - "pack", enc_array (List.map enc_string (fst i.mt_path)); - "name", enc_string (snd i.mt_path); - "pos", encode_pos i.mt_pos; - "module", enc_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 enc_string i.mt_doc; - "params", encode_type_params i.mt_types; - ] @ fields) - -and encode_type_params tl = - enc_array (List.map (fun (n,t) -> enc_obj ["name",enc_string n;"t",encode_type t]) tl) - -and encode_tenum e = - encode_mtype (TEnumDecl e) [ - "isExtern", VBool e.e_extern; - "exclude", VFunction (Fun0 (fun() -> e.e_extern <- true; VNull)); - "constructs", encode_pmap encode_efield e.e_constrs; - "names", enc_array (List.map enc_string e.e_names); - ] - -and encode_tabstract a = - encode_mtype (TAbstractDecl a) [ - "type", encode_type a.a_this; - "impl", (match a.a_impl with None -> VNull | Some c -> encode_clref c); - "binops", enc_array (List.map (fun (op,cf) -> enc_obj [ "op",encode_binop op; "field",encode_cfield cf]) a.a_ops); - "unops", enc_array (List.map (fun (op,postfix,cf) -> enc_obj [ "op",encode_unop op; "isPostfix",VBool (match postfix with Postfix -> true | Prefix -> false); "field",encode_cfield cf]) a.a_unops); - "from", enc_array (List.map (fun (t,cfo) -> enc_obj [ "t",encode_type t; "field",match cfo with None -> VNull | Some cf -> encode_cfield cf]) a.a_from); - "to", enc_array (List.map (fun (t,cfo) -> enc_obj [ "t",encode_type t; "field",match cfo with None -> VNull | Some cf -> encode_cfield cf]) a.a_to); - "array", enc_array (List.map encode_cfield a.a_array); - ] - -and encode_efield f = - enc_obj [ - "name", enc_string f.ef_name; - "type", encode_type f.ef_type; - "pos", encode_pos f.ef_pos; - "index", VInt f.ef_index; - "meta", encode_meta f.ef_meta (fun m -> f.ef_meta <- m); - "doc", null enc_string f.ef_doc; - "params", encode_type_params f.ef_params; - ] - -and encode_cfield f = - enc_obj [ - "name", enc_string f.cf_name; - "type", (match f.cf_kind with Method _ -> encode_lazy_type f.cf_type | _ -> encode_type f.cf_type); - "isPublic", VBool f.cf_public; - "params", encode_type_params f.cf_params; - "meta", encode_meta f.cf_meta (fun m -> f.cf_meta <- m); - "expr", (VFunction (Fun0 (fun() -> ignore(follow f.cf_type); (match f.cf_expr with None -> VNull | Some e -> encode_texpr e)))); - "kind", encode_field_kind f.cf_kind; - "pos", encode_pos f.cf_pos; - "doc", null enc_string f.cf_doc; - ] - -and encode_field_kind k = - let tag, pl = (match k with - | Type.Var v -> 0, [encode_var_access v.v_read; encode_var_access v.v_write] - | Method m -> 1, [encode_method_kind m] - ) in - enc_enum IFieldKind tag pl - -and encode_var_access a = - let tag, pl = (match a with - | AccNormal -> 0, [] - | AccNo -> 1, [] - | AccNever -> 2, [] - | AccResolve -> 3, [] - | AccCall -> 4, [] - | AccInline -> 5, [] - | AccRequire (s,msg) -> 6, [enc_string s; null enc_string msg] - ) in - enc_enum IVarAccess tag pl - -and encode_method_kind m = - let tag, pl = (match m with - | MethNormal -> 0, [] - | MethInline -> 1, [] - | MethDynamic -> 2, [] - | MethMacro -> 3, [] - ) in - enc_enum IMethodKind tag pl - -and encode_class_kind k = - let tag, pl = (match k with - | KNormal -> 0, [] - | KTypeParameter pl -> 1, [encode_tparams pl] - | KExtension (cl, params) -> 2, [encode_clref cl; encode_tparams params] - | KExpr e -> 3, [encode_expr e] - | KGeneric -> 4, [] - | KGenericInstance (cl, params) -> 5, [encode_clref cl; encode_tparams params] - | KMacroType -> 6, [] - | KAbstractImpl a -> 7, [encode_ref a encode_tabstract (fun() -> s_type_path a.a_path)] - ) in - enc_enum IClassKind tag pl - -and encode_tclass c = - c.cl_build(); - encode_mtype (TClassDecl c) [ - "kind", encode_class_kind c.cl_kind; - "isExtern", VBool c.cl_extern; - "exclude", VFunction (Fun0 (fun() -> c.cl_extern <- true; c.cl_init <- None; VNull)); - "isInterface", VBool c.cl_interface; - "superClass", (match c.cl_super with - | None -> VNull - | Some (c,pl) -> enc_obj ["t",encode_clref c;"params",encode_tparams pl] - ); - "interfaces", enc_array (List.map (fun (c,pl) -> enc_obj ["t",encode_clref c;"params",encode_tparams pl]) c.cl_implements); - "fields", encode_ref c.cl_ordered_fields (encode_array encode_cfield) (fun() -> "class fields"); - "statics", encode_ref c.cl_ordered_statics (encode_array encode_cfield) (fun() -> "class fields"); - "constructor", (match c.cl_constructor with None -> VNull | Some c -> encode_ref c encode_cfield (fun() -> "constructor")); - "init", (match c.cl_init with None -> VNull | Some e -> encode_texpr e); - ] - -and encode_ttype t = - encode_mtype (TTypeDecl t) [ - "isExtern", VBool false; - "exclude", VFunction (Fun0 (fun() -> VNull)); - "type", encode_type t.t_type; - ] - -and encode_tanon a = - enc_obj [ - "fields", encode_pmap_array encode_cfield a.a_fields; - ] - -and encode_tparams pl = - enc_array (List.map encode_type pl) - -and encode_clref c = - encode_ref c encode_tclass (fun() -> s_type_path c.cl_path) - -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() -> "")] - | Some t -> loop t) - | TEnum (e, pl) -> - 1 , [encode_ref e encode_tenum (fun() -> s_type_path e.e_path); encode_tparams pl] - | TInst (c, pl) -> - 2 , [encode_clref c; encode_tparams pl] - | TType (t,pl) -> - 3 , [encode_ref t encode_ttype (fun() -> s_type_path t.t_path); encode_tparams pl] - | TFun (pl,ret) -> - let pl = List.map (fun (n,o,t) -> - enc_obj [ - "name",enc_string n; - "opt",VBool o; - "t",encode_type t - ] - ) pl in - 4 , [enc_array pl; encode_type ret] - | TAnon a -> - 5, [encode_ref a encode_tanon (fun() -> "")] - | TDynamic tsub as t -> - if t == t_dynamic then - 6, [VNull] - else - 6, [encode_type tsub] - | TLazy f -> - loop (!f()) - | TAbstract (a, pl) -> - 8, [encode_ref a encode_tabstract (fun() -> s_type_path a.a_path); encode_tparams pl] - in - let tag, pl = loop t in - enc_enum IType tag pl - -and encode_lazy_type t = - let rec loop = function - | TMono r -> - (match !r with - | Some t -> loop t - | _ -> encode_type t) - | TLazy f -> - enc_enum IType 7 [VAbstract (ALazyType f)] - | _ -> - encode_type t - in - loop t - -and decode_type t = - match decode_enum t with - | 0, [r] -> TMono (decode_ref r) - | 1, [e; pl] -> TEnum (decode_ref e, List.map decode_type (dec_array pl)) - | 2, [c; pl] -> TInst (decode_ref c, List.map decode_type (dec_array pl)) - | 3, [t; pl] -> TType (decode_ref t, List.map decode_type (dec_array pl)) - | 4, [pl; r] -> TFun (List.map (fun p -> dec_string (field p "name"), dec_bool (field p "opt"), decode_type (field p "t")) (dec_array pl), decode_type r) - | 5, [a] -> TAnon (decode_ref a) - | 6, [VNull] -> t_dynamic - | 6, [t] -> TDynamic (decode_type t) - | 7, [VAbstract (ALazyType f)] -> TLazy f - | 8, [a; pl] -> TAbstract (decode_ref a, List.map decode_type (dec_array pl)) - | _ -> raise Invalid_expr - -and encode_texpr e = - VAbstract (ATExpr e) - -let decode_tdecl v = - match v with - | VObject o -> - (match get_field o (hash "__t") with - | VAbstract (ATDecl t) -> t - | _ -> raise Invalid_expr) - | _ -> raise Invalid_expr - -(* ---------------------------------------------------------------------- *) -(* TYPE DEFINITION *) - -let decode_type_def v = - let pack = List.map dec_string (dec_array (field v "pack")) in - let name = dec_string (field v "name") in - let meta = decode_meta_content (field v "meta") in - let pos = decode_pos (field v "pos") in - let isExtern = dec_bool (field v "isExtern") in - let fields = List.map decode_field (dec_array (field v "fields")) in - let mk fl dl = - { - d_name = name; - d_doc = None; - d_params = List.map decode_tparam_decl (dec_array (field v "params")); - d_meta = meta; - d_flags = fl; - d_data = dl; - } - in - let tdef = (match decode_enum (field v "kind") with - | 0, [] -> - let conv f = - let loop (n,opt,t,_) = - match t with - | None -> raise Invalid_expr - | Some t -> n, opt, t - in - let args, params, t = (match f.cff_kind with - | FVar (t,None) -> [], [], t - | FFun f -> List.map loop f.f_args, f.f_params, f.f_type - | _ -> raise Invalid_expr - ) in - { - ec_name = f.cff_name; - ec_doc = f.cff_doc; - ec_meta = f.cff_meta; - ec_pos = f.cff_pos; - ec_args = args; - ec_params = params; - ec_type = t; - } - in - EEnum (mk (if isExtern then [EExtern] else []) (List.map conv fields)) - | 1, [] -> - ETypedef (mk (if isExtern then [EExtern] else []) (CTAnonymous fields)) - | 2, [ext;impl;interf] -> - let flags = if isExtern then [HExtern] else [] in - let flags = (match interf with VNull | VBool false -> flags | VBool true -> HInterface :: flags | _ -> raise Invalid_expr) in - let flags = (match opt decode_path ext with None -> flags | Some t -> HExtends t :: flags) in - let flags = (match opt (fun v -> List.map decode_path (dec_array v)) impl with None -> flags | Some l -> List.map (fun t -> HImplements t) l @ flags) in - EClass (mk flags fields) - | 3, [t] -> - ETypedef (mk (if isExtern then [EExtern] else []) (decode_ctype t)) - | 4, [tthis;tfrom;tto] -> - let flags = match opt dec_array tfrom with None -> [] | Some ta -> List.map (fun t -> AFromType (decode_ctype t)) ta in - let flags = match opt dec_array tto with None -> flags | Some ta -> (List.map (fun t -> AToType (decode_ctype t)) ta) @ flags in - let flags = match opt decode_ctype tthis with None -> flags | Some t -> (AIsType t) :: flags in - EAbstract(mk flags fields) - | _ -> - raise Invalid_expr - ) in - (pack, name), tdef, pos - -(* ---------------------------------------------------------------------- *) -(* VALUE-TO-CONSTANT *) - -let rec make_const e = - match e.eexpr with - | TConst c -> - (match c with - | TInt i -> best_int i - | TFloat s -> VFloat (float_of_string s) - | TString s -> enc_string s - | TBool b -> VBool b - | TNull -> VNull - | TThis | TSuper -> raise Exit) - | TParenthesis e -> - make_const e - | TObjectDecl el -> - VObject (obj (hash_field (get_ctx())) (List.map (fun (f,e) -> f, make_const e) el)) - | TArrayDecl al -> - enc_array (List.map make_const al) - | _ -> - raise Exit - -(* ---------------------------------------------------------------------- *) -(* TEXPR-TO-AST-EXPR *) - -open Ast - -let tpath p mp pl = - if snd mp = snd p then - CTPath { - tpackage = fst p; - tname = snd p; - tparams = List.map (fun t -> TPType t) pl; - tsub = None; - } - else CTPath { - tpackage = fst mp; - tname = snd mp; - tparams = List.map (fun t -> TPType t) pl; - tsub = Some (snd p); - } - -let rec make_type = function - | TMono r -> - (match !r with - | None -> raise Exit - | Some t -> make_type t) - | TEnum (e,pl) -> - tpath e.e_path e.e_module.m_path (List.map make_type pl) - | TInst({cl_kind = KTypeParameter _} as c,pl) -> - tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map make_type pl) - | TInst (c,pl) -> - tpath c.cl_path c.cl_module.m_path (List.map make_type pl) - | TType (t,pl) as tf -> - (* recurse on type-type *) - if (snd t.t_path).[0] = '#' then make_type (follow tf) else tpath t.t_path t.t_module.m_path (List.map make_type pl) - | TAbstract (a,pl) -> - tpath a.a_path a.a_module.m_path (List.map make_type pl) - | TFun (args,ret) -> - CTFunction (List.map (fun (_,_,t) -> make_type t) args, make_type ret) - | TAnon a -> - begin match !(a.a_status) with - | Statics c -> tpath ([],"Class") ([],"Class") [tpath c.cl_path c.cl_path []] - | EnumStatics e -> tpath ([],"Enum") ([],"Enum") [tpath e.e_path e.e_path []] - | _ -> - CTAnonymous (PMap.foldi (fun _ f acc -> - { - cff_name = f.cf_name; - cff_kind = FVar (mk_ot f.cf_type,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 [make_type t2]) - | TLazy f -> - make_type ((!f)()) - -and mk_ot t = - match follow t with - | TMono _ -> None - | _ -> (try Some (make_type t) with Exit -> None) - -let rec make_ast 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 (pack,name) p = - match List.rev pack with - | [] -> (EConst (Ident name),p) - | pl -> - let rec loop = function - | [] -> assert false - | [n] -> (EConst (Ident n),p) - | n :: l -> (EField (loop l, n),p) - in - (EField (loop pl,name),p) - in - let mk_const = function - | TInt i -> Int (Int32.to_string i) - | TFloat s -> Float s - | TString s -> String s - | TBool b -> Ident (if b then "true" else "false") - | TNull -> Ident "null" - | TThis -> Ident "this" - | TSuper -> Ident "super" - in - let mk_ident = function - | "`trace" -> Ident "trace" - | n -> Ident n - in - let eopt = function None -> None | Some e -> Some (make_ast e) in - ((match e.eexpr with - | TConst c -> - EConst (mk_const c) - | TLocal v -> EConst (mk_ident v.v_name) - | TArray (e1,e2) -> EArray (make_ast e1,make_ast e2) - | TBinop (op,e1,e2) -> EBinop (op, make_ast e1, make_ast e2) - | TField (e,f) -> EField (make_ast e, Type.field_name f) - | TTypeExpr t -> fst (mk_path (full_type_path t) e.epos) - | TParenthesis e -> EParenthesis (make_ast e) - | TObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> f, make_ast e) fl) - | TArrayDecl el -> EArrayDecl (List.map make_ast el) - | TCall (e,el) -> ECall (make_ast e,List.map make_ast el) - | TNew (c,pl,el) -> ENew ((match (try make_type (TInst (c,pl)) with Exit -> make_type (TInst (c,[]))) with CTPath p -> p | _ -> assert false),List.map make_ast el) - | TUnop (op,p,e) -> EUnop (op,p,make_ast e) - | TFunction f -> - let arg (v,c) = v.v_name, false, mk_ot v.v_type, (match c with None -> None | Some c -> Some (EConst (mk_const c),e.epos)) in - EFunction (None,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_ot f.tf_type; f_expr = Some (make_ast f.tf_expr) }) - | TVars vl -> - EVars (List.map (fun (v,e) -> v.v_name, mk_ot v.v_type, eopt e) vl) - | TBlock el -> EBlock (List.map make_ast el) - | TFor (v,it,e) -> - let ein = (EIn ((EConst (Ident v.v_name),it.epos),make_ast it),it.epos) in - EFor (ein,make_ast e) - | TIf (e,e1,e2) -> EIf (make_ast e,make_ast e1,eopt e2) - | TWhile (e1,e2,flag) -> EWhile (make_ast e1, make_ast e2, flag) - | TSwitch (e,cases,def) -> - let cases = List.map (fun (vl,e) -> - List.map make_ast vl,None,(match e.eexpr with TBlock [] -> None | _ -> Some (make_ast e)) - ) cases in - let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in - ESwitch (make_ast e,cases,def) - | TMatch (e,(en,_),cases,def) -> - let scases (idx,args,e) = - let p = e.epos in - let unused = (EConst (Ident "_"),p) in - let args = (match args with - | None -> None - | Some l -> Some (List.map (function None -> unused | Some v -> (EConst (Ident v.v_name),p)) l) - ) in - let mk_args n = - match args with - | None -> [unused] - | Some args -> - args @ Array.to_list (Array.make (n - List.length args) unused) - in - List.map (fun i -> - let c = (try List.nth en.e_names i with _ -> assert false) in - let cfield = (try PMap.find c en.e_constrs with Not_found -> assert false) in - let c = (EConst (Ident c),p) in - (match follow cfield.ef_type with TFun (eargs,_) -> (ECall (c,mk_args (List.length eargs)),p) | _ -> c) - ) idx, None, (match e.eexpr with TBlock [] -> None | _ -> Some (make_ast e)) - in - let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in - ESwitch (make_ast e,List.map scases cases,def) - | TTry (e,catches) -> ETry (make_ast e,List.map (fun (v,e) -> v.v_name, (try make_type v.v_type with Exit -> assert false), make_ast e) catches) - | TReturn e -> EReturn (eopt e) - | TBreak -> EBreak - | TContinue -> EContinue - | TThrow e -> EThrow (make_ast 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 make_type t with Exit -> assert false) - ) in - ECast (make_ast e,t)) - ,e.epos) - -;; -make_ast_ref := make_ast; -make_complex_type_ref := make_type; -encode_complex_type_ref := encode_ctype; -enc_array_ref := enc_array; -encode_type_ref := encode_type; -decode_type_ref := decode_type; -encode_expr_ref := encode_expr; -decode_expr_ref := decode_expr; -encode_clref_ref := encode_clref; -enc_string_ref := enc_string; -enc_hash_ref := enc_hash \ No newline at end of file +(* + * Copyright (C)2005-2013 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. + *) + +open Common +open Nast +open Unix +open Type + +(* ---------------------------------------------------------------------- *) +(* TYPES *) + +type value = + | VNull + | VBool of bool + | VInt of int + | VFloat of float + | VString of string + | VObject of vobject + | VArray of value array + | VAbstract of vabstract + | VFunction of vfunction + | VClosure of value list * (value list -> value list -> value) + | VInt32 of int32 + +and vobject = { + mutable ofields : (int * value) array; + mutable oproto : vobject option; +} + +and vabstract = + | ADeallocated of int ref + | AKind of vabstract + | AHash of (value, value) Hashtbl.t + | ARandom of Random.State.t ref + | ABuffer of Buffer.t + | APos of Ast.pos + | AFRead of (in_channel * bool ref) + | AFWrite of out_channel + | AReg of regexp + | AZipI of zlib + | AZipD of zlib + | AUtf8 of UTF8.Buf.buf + | ASocket of Unix.file_descr + | ATDecl of module_type + | AUnsafe of Obj.t + | ALazyType of (unit -> Type.t) ref + | ANekoAbstract of Extc.value + | ANekoBuffer of value + | ACacheRef of value + | AInt32Kind + | ATls of value ref + | AProcess of Process.process + +and vfunction = + | Fun0 of (unit -> value) + | Fun1 of (value -> value) + | Fun2 of (value -> value -> value) + | Fun3 of (value -> value -> value -> value) + | Fun4 of (value -> value -> value -> value -> value) + | Fun5 of (value -> value -> value -> value -> value -> value) + | FunVar of (value list -> value) + +and regexp = { + r : Str.regexp; + mutable r_string : string; + mutable r_groups : (int * int) option array; +} + +and zlib = { + z : Extc.zstream; + mutable z_flush : Extc.zflush; +} + +type cmp = + | CEq + | CSup + | CInf + | CUndef + +type extern_api = { + pos : Ast.pos; + get_com : unit -> Common.context; + get_type : string -> Type.t option; + get_module : string -> Type.t list; + on_generate : (Type.t list -> unit) -> unit; + after_generate : (unit -> unit) -> unit; + on_type_not_found : (string -> value) -> unit; + parse_string : string -> Ast.pos -> bool -> Ast.expr; + type_expr : Ast.expr -> Type.texpr; + store_typed_expr : Type.texpr -> Ast.expr; + get_display : string -> string; + allow_package : string -> unit; + type_patch : string -> string -> bool -> string option -> unit; + meta_patch : string -> string -> string option -> bool -> unit; + set_js_generator : (value -> unit) -> unit; + get_local_type : unit -> t option; + get_expected_type : unit -> t option; + get_call_arguments : unit -> Ast.expr list option; + get_local_method : unit -> string; + get_local_using : unit -> tclass list; + get_local_vars : unit -> (string, Type.tvar) PMap.t; + get_build_fields : unit -> value; + get_pattern_locals : Ast.expr -> Type.t -> (string,Type.tvar * Ast.pos) PMap.t; + define_type : value -> unit; + define_module : string -> value list -> ((string * Ast.pos) list * Ast.import_mode) list -> Ast.type_path list -> unit; + module_dependency : string -> string -> bool -> unit; + current_module : unit -> module_def; + delayed_macro : int -> (unit -> (unit -> value)); + use_cache : unit -> bool; + format_string : string -> Ast.pos -> Ast.expr; + cast_or_unify : Type.t -> texpr -> Ast.pos -> Type.texpr; + add_global_metadata : string -> string -> (bool * bool * bool) -> unit; +} + +type callstack = { + cpos : pos; + cthis : value; + cstack : int; + cenv : value array; +} + +type context = { + gen : Genneko.context; + types : (Type.path,int) Hashtbl.t; + prototypes : (string list, vobject) Hashtbl.t; + fields_cache : (int,string) Hashtbl.t; + mutable error : bool; + mutable error_proto : vobject; + mutable enums : (value * string) array array; + mutable do_call : value -> value -> value list -> pos -> value; + mutable do_string : value -> string; + mutable do_loadprim : value -> value -> value; + mutable do_compare : value -> value -> cmp; + mutable loader : value; + mutable exports : value; + (* runtime *) + mutable stack : value DynArray.t; + mutable callstack : callstack list; + mutable callsize : int; + mutable exc : pos list; + mutable vthis : value; + mutable venv : value array; + (* context *) + mutable curapi : extern_api; + mutable on_reused : (unit -> bool) list; + mutable is_reused : bool; + (* eval *) + mutable locals_map : (string, int) PMap.t; + mutable locals_count : int; + mutable locals_barrier : int; + mutable locals_env : string DynArray.t; + mutable globals : (string, value ref) PMap.t; +} + +type access = + | AccThis + | AccLocal of int + | AccGlobal of value ref + | AccEnv of int + | AccField of (unit -> value) * string + | AccArray of (unit -> value) * (unit -> value) + +exception Runtime of value +exception Builtin_error + +exception Error of string * Ast.pos list + +exception Abort +exception Continue +exception Break of value +exception Return of value +exception Invalid_expr +exception Sys_exit of int + +(* ---------------------------------------------------------------------- *) +(* UTILS *) + +let get_ctx_ref = ref (fun() -> assert false) +let encode_complex_type_ref = ref (fun t -> assert false) +let encode_type_ref = ref (fun t -> assert false) +let decode_type_ref = ref (fun t -> assert false) +let encode_expr_ref = ref (fun e -> assert false) +let decode_expr_ref = ref (fun e -> assert false) +let encode_texpr_ref = ref (fun e -> assert false) +let decode_texpr_ref = ref (fun e -> assert false) +let encode_clref_ref = ref (fun c -> assert false) +let enc_hash_ref = ref (fun h -> assert false) +let enc_array_ref = ref (fun l -> assert false) +let dec_array_ref = ref (fun v -> assert false) +let enc_string_ref = ref (fun s -> assert false) +let make_ast_ref = ref (fun _ -> assert false) +let make_complex_type_ref = ref (fun _ -> assert false) +let encode_tvar_ref = ref (fun _ -> assert false) +let decode_path_ref = ref (fun _ -> assert false) +let decode_import_ref = ref (fun _ -> assert false) +let get_ctx() = (!get_ctx_ref)() +let enc_array (l:value list) : value = (!enc_array_ref) l +let dec_array (l:value) : value list = (!dec_array_ref) l +let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t +let encode_type (t:Type.t) : value = (!encode_type_ref) t +let decode_type (v:value) : Type.t = (!decode_type_ref) v +let encode_expr (e:Ast.expr) : value = (!encode_expr_ref) e +let decode_expr (e:value) : Ast.expr = (!decode_expr_ref) e +let encode_texpr (e:Type.texpr) : value = (!encode_texpr_ref) e +let decode_texpr (v:value) : Type.texpr = (!decode_texpr_ref) v +let encode_clref (c:tclass) : value = (!encode_clref_ref) c +let enc_hash (h:('a,'b) Hashtbl.t) : value = (!enc_hash_ref) h +let make_ast (e:texpr) : Ast.expr = (!make_ast_ref) e +let enc_string (s:string) : value = (!enc_string_ref) s +let make_complex_type (t:Type.t) : Ast.complex_type = (!make_complex_type_ref) t +let encode_tvar (v:tvar) : value = (!encode_tvar_ref) v +let decode_path (v:value) : Ast.type_path = (!decode_path_ref) v +let decode_import (v:value) : ((string * Ast.pos) list * Ast.import_mode) = (!decode_import_ref) v + +let to_int f = Int32.of_float (mod_float f 2147483648.0) +let need_32_bits i = Int32.compare (Int32.logand (Int32.add i 0x40000000l) 0x80000000l) Int32.zero <> 0 +let best_int i = if need_32_bits i then VInt32 i else VInt (Int32.to_int i) + +let make_pos p = + let low = p.pline land 0xFFFFF in + { + Ast.pfile = p.psource; + Ast.pmin = low; + Ast.pmax = low + (p.pline lsr 20); + } + +let warn ctx msg p = + (ctx.curapi.get_com()).Common.warning msg (make_pos p) + +let rec pop ctx n = + if n > 0 then begin + DynArray.delete_last ctx.stack; + pop ctx (n - 1); + end + +let pop_ret ctx f n = + let v = f() in + pop ctx n; + v + +let push ctx v = + DynArray.add ctx.stack v + +let hash f = + let h = ref 0 in + for i = 0 to String.length f - 1 do + h := !h * 223 + int_of_char (String.unsafe_get f i); + done; + if Sys.word_size = 64 then Int32.to_int (Int32.shift_right (Int32.shift_left (Int32.of_int !h) 1) 1) else !h + +let constants = + let h = Hashtbl.create 0 in + List.iter (fun f -> Hashtbl.add h (hash f) f) + ["done";"read";"write";"min";"max";"file";"args";"loadprim";"loadmodule";"__a";"__s";"h"; + "tag";"index";"length";"message";"pack";"name";"params";"sub";"doc";"kind";"meta";"access"; + "constraints";"opt";"type";"value";"ret";"expr";"field";"values";"get";"__string";"toString"; + "$";"add";"remove";"has";"__t";"module";"isPrivate";"isPublic";"isExtern";"isInterface";"exclude"; + "constructs";"names";"superClass";"interfaces";"fields";"statics";"constructor";"init";"t"; + "gid";"uid";"atime";"mtime";"ctime";"dev";"ino";"nlink";"rdev";"size";"mode";"pos";"len"; + "binops";"unops";"from";"to";"array";"op";"isPostfix";"impl"; + "id";"capture";"extra";"v";"ids";"vars";"en";"overrides";"status"]; + h + +let h_get = hash "__get" and h_set = hash "__set" +and h_add = hash "__add" and h_radd = hash "__radd" +and h_sub = hash "__sub" and h_rsub = hash "__rsub" +and h_mult = hash "__mult" and h_rmult = hash "__rmult" +and h_div = hash "__div" and h_rdiv = hash "__rdiv" +and h_mod = hash "__mod" and h_rmod = hash "__rmod" +and h_string = hash "__string" and h_compare = hash "__compare" + +and h_constructs = hash "__constructs__" and h_a = hash "__a" and h_s = hash "__s" +and h_class = hash "__class__" + +let exc v = + raise (Runtime v) + +let hash_field ctx f = + let h = hash f in + (try + let f2 = Hashtbl.find ctx.fields_cache h in + if f <> f2 then exc (VString ("Field conflict between " ^ f ^ " and " ^ f2)); + with Not_found -> + Hashtbl.add ctx.fields_cache h f); + h + +let field_name ctx fid = + try + Hashtbl.find ctx.fields_cache fid + with Not_found -> + "???" + +let obj hash fields = + let fields = Array.of_list (List.map (fun (k,v) -> hash k, v) fields) in + Array.sort (fun (k1,_) (k2,_) -> compare k1 k2) fields; + { + ofields = fields; + oproto = None; + } + +let parse_int s = + let rec loop_hex i = + if i = String.length s then s else + match String.unsafe_get s i with + | '0'..'9' | 'a'..'f' | 'A'..'F' -> loop_hex (i + 1) + | _ -> String.sub s 0 i + in + let rec loop sp i = + if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else + match String.unsafe_get s i with + | '0'..'9' -> loop sp (i + 1) + | ' ' when sp = i -> loop (sp + 1) (i + 1) + | '-' when i = 0 -> loop sp (i + 1) + | ('x' | 'X') when i = 1 && String.get s 0 = '0' -> loop_hex (i + 1) + | _ -> String.sub s sp (i - sp) + in + best_int (Int32.of_string (loop 0 0)) + +let parse_float s = + let rec loop sp i = + if i = String.length s then (if sp = 0 then s else String.sub s sp (i - sp)) else + match String.unsafe_get s i with + | ' ' when sp = i -> loop (sp + 1) (i + 1) + | '0'..'9' | '-' | '+' | 'e' | 'E' | '.' -> loop sp (i + 1) + | _ -> String.sub s sp (i - sp) + in + float_of_string (loop 0 0) + +let find_sub str sub start = + let sublen = String.length sub in + if sublen = 0 then + 0 + else + let found = ref 0 in + let len = String.length str in + try + for i = start to len - sublen do + let j = ref 0 in + while String.unsafe_get str (i + !j) = String.unsafe_get sub !j do + incr j; + if !j = sublen then begin found := i; raise Exit; end; + done; + done; + raise Not_found + with + Exit -> !found + +let nargs = function + | Fun0 _ -> 0 + | Fun1 _ -> 1 + | Fun2 _ -> 2 + | Fun3 _ -> 3 + | Fun4 _ -> 4 + | Fun5 _ -> 5 + | FunVar _ -> -1 + +let rec get_field o fid = + let rec loop min max = + if min < max then begin + let mid = (min + max) lsr 1 in + let cid, v = Array.unsafe_get o.ofields mid in + if cid < fid then + loop (mid + 1) max + else if cid > fid then + loop min mid + else + v + end else + match o.oproto with + | None -> VNull + | Some p -> get_field p fid + in + loop 0 (Array.length o.ofields) + +let set_field o fid v = + let rec loop min max = + let mid = (min + max) lsr 1 in + if min < max then begin + let cid, _ = Array.unsafe_get o.ofields mid in + if cid < fid then + loop (mid + 1) max + else if cid > fid then + loop min mid + else + Array.unsafe_set o.ofields mid (cid,v) + end else + let fields = Array.make (Array.length o.ofields + 1) (fid,v) in + Array.blit o.ofields 0 fields 0 mid; + Array.blit o.ofields mid fields (mid + 1) (Array.length o.ofields - mid); + o.ofields <- fields + in + loop 0 (Array.length o.ofields) + +let rec remove_field o fid = + let rec loop min max = + let mid = (min + max) lsr 1 in + if min < max then begin + let cid, v = Array.unsafe_get o.ofields mid in + if cid < fid then + loop (mid + 1) max + else if cid > fid then + loop min mid + else begin + let fields = Array.make (Array.length o.ofields - 1) (fid,VNull) in + Array.blit o.ofields 0 fields 0 mid; + Array.blit o.ofields (mid + 1) fields mid (Array.length o.ofields - mid - 1); + o.ofields <- fields; + true + end + end else + false + in + loop 0 (Array.length o.ofields) + +let rec get_field_opt o fid = + let rec loop min max = + if min < max then begin + let mid = (min + max) lsr 1 in + let cid, v = Array.unsafe_get o.ofields mid in + if cid < fid then + loop (mid + 1) max + else if cid > fid then + loop min mid + else + Some v + end else + match o.oproto with + | None -> None + | Some p -> get_field_opt p fid + in + loop 0 (Array.length o.ofields) + +let catch_errors ctx ?(final=(fun() -> ())) f = + let n = DynArray.length ctx.stack in + try + let v = f() in + final(); + Some v + with Runtime v -> + pop ctx (DynArray.length ctx.stack - n); + final(); + let rec loop o = + if o == ctx.error_proto then true else match o.oproto with None -> false | Some p -> loop p + in + (match v with + | VObject o when loop o -> + (match get_field o (hash "message"), get_field o (hash "pos") with + | VObject msg, VAbstract (APos pos) -> + (match get_field msg h_s with + | VString msg -> raise (Typecore.Error (Typecore.Custom msg,pos)) + | _ -> ()); + | _ -> ()); + | _ -> ()); + raise (Error (ctx.do_string v,List.map (fun s -> make_pos s.cpos) ctx.callstack)) + | Abort -> + pop ctx (DynArray.length ctx.stack - n); + final(); + None + +let make_library fl = + let h = Hashtbl.create 0 in + List.iter (fun (n,f) -> Hashtbl.add h n f) fl; + h + +(* ---------------------------------------------------------------------- *) +(* NEKO INTEROP *) + +type primitive = (string * Extc.value * int) + +type neko_context = { + load : string -> int -> primitive; + call : primitive -> value list -> value; +} + +let neko = + let is_win = Sys.os_type = "Win32" || Sys.os_type = "Cygwin" in + let neko = Extc.dlopen (if is_win then "neko.dll" else "libneko.so") in + let null = Extc.dlint 0 in + let neko = if Obj.magic neko == null && not is_win then Extc.dlopen "libneko.dylib" else neko in + if Obj.magic neko == null then + None + else + let load v = + let s = Extc.dlsym neko v in + if (Obj.magic s) == null then failwith ("Could not load neko." ^ v); + s + in + ignore(Extc.dlcall0 (load "neko_global_init")); + let vm = Extc.dlcall1 (load "neko_vm_alloc") null in + ignore(Extc.dlcall1 (load "neko_vm_select") vm); + let loader = Extc.dlcall2 (load "neko_default_loader") null null in + let loadprim = + let l1 = load "neko_val_field" in + let l2 = Extc.dlcall1 (load "neko_val_id") (Extc.dlstring "loadprim") in + Extc.dlcall2 (l1) loader (l2) in + + let callN = load "neko_val_callN" in + let callEx = load "neko_val_callEx" in + let copy_string = load "neko_copy_string" in + + let alloc_root = load "neko_alloc_root" in + let free_root = load "neko_free_root" in + + let alloc_root v = + let r = Extc.dlcall1 alloc_root (Extc.dlint 1) in + Extc.dlsetptr r v; + r + in + let free_root r = + ignore(Extc.dlcall1 free_root r) + in + + ignore(alloc_root vm); + ignore(alloc_root loader); + ignore(alloc_root loadprim); + + let alloc_string s = + Extc.dlcall2 copy_string (Extc.dlstring s) (Extc.dlint (String.length s)) + in + let alloc_int (i:int) : Extc.value = + Obj.magic i + in + let loadprim n args = + let exc = ref null in + let vargs = [|alloc_string n;alloc_int args|] in + let p = Extc.dlcall5 callEx loader loadprim (Obj.magic vargs) (Extc.dlint 2) (Obj.magic exc) in + if !exc != null then failwith ("Failed to load " ^ n ^ ":" ^ string_of_int args); + ignore(alloc_root p); + (n,p,args) + in + let call_raw_prim (_,p,nargs) (args:Extc.value array) = + Extc.dlcall3 callN p (Obj.magic args) (Extc.dlint nargs) + in + + (* a bit tricky since load "val_true" does not work as expected on Windows *) + let unser = try loadprim "std@unserialize" 2 with _ -> ("",null,0) in + + (* did we fail to load std.ndll ? *) + if (match unser with ("",_,_) -> true | _ -> false) then None else + + let val_true = call_raw_prim unser [|alloc_string "T";loader|] in + let val_false = call_raw_prim unser [|alloc_string "F";loader|] in + let val_null = call_raw_prim unser [|alloc_string "N";loader|] in + + let is_64 = call_raw_prim (loadprim "std@sys_is64" 0) [||] == val_true in + let alloc_i32, is_v2 = (try load "neko_alloc_int32", true with _ -> Obj.magic 0, false) in + let alloc_i32 = if is_v2 then + (fun i -> Extc.dlcall1 alloc_i32 (Extc.dlint32 i)) + else + (fun i -> alloc_int (Int32.to_int (if Int32.compare i Int32.zero < 0 then Int32.logand i 0x7FFFFFFFl else Int32.logor i 0x80000000l))) + in + let tag_bits = if is_v2 then 4 else 3 in + let tag_mask = (1 lsl tag_bits) - 1 in + let ptr_size = if is_64 then 8 else 4 in + let val_field v i = Extc.dladdr v ((i + 1) * ptr_size) in + let val_str v = Extc.dladdr v 4 in + let val_fun_env v = Extc.dladdr v (8 + ptr_size) in + + (* alloc support *) + + let alloc_function = load "neko_alloc_function" in + let alloc_array = load "neko_alloc_array" in + let alloc_float = load "neko_alloc_float" in + let alloc_object = load "neko_alloc_object" in + let alloc_field = load "neko_alloc_field" in + let alloc_abstract = load "neko_alloc_abstract" in + let val_gc = load "neko_val_gc" in + let val_field_name = load "neko_val_field_name" in + let val_iter_fields = load "neko_val_iter_fields" in + let gen_callback = Extc.dlcaml_callback 2 in + + (* roots *) + + let on_abstract_gc = Extc.dlcaml_callback 1 in + let root_index = ref 0 in + let roots = Hashtbl.create 0 in + Callback.register "dlcallb1" (fun a -> + let index : int = Obj.magic (Extc.dlptr (val_field a 1)) in + Hashtbl.remove roots index; + null + ); + + (* wrapping *) + + let copy_string v = + let head = Extc.dltoint (Extc.dlptr v) in + let size = head asr tag_bits in + let s = String.create size in + Extc.dlmemcpy (Extc.dlstring s) (val_str v) size; + s + in + + let buffers = ref [] in + + let rec value_neko ?(obj=VNull) = function + | VNull -> val_null + | VBool b -> if b then val_true else val_false + | VInt i -> alloc_int i + | VAbstract (ANekoAbstract a) -> a + | VAbstract (ANekoBuffer (VString buf)) -> + let v = value_neko (VString buf) in + buffers := (buf,v) :: !buffers; + v + | VString s -> + let v = alloc_string s in (* make a copy *) + ignore(copy_string v); + v + | VObject o as obj -> + let vo = Extc.dlcall1 alloc_object null in + Array.iter (fun (id,v) -> + ignore(Extc.dlcall3 alloc_field vo (Extc.dlint id) (value_neko ~obj v)) + ) o.ofields; + vo + | VClosure _ -> + failwith "Closure not supported" + | VFunction f -> + let callb = Extc.dlcall3 alloc_function gen_callback (Extc.dlint (-1)) (Obj.magic "") in + let index = !root_index in + incr root_index; + Hashtbl.add roots index (f,obj); + let a = Extc.dlcall2 alloc_abstract null (Obj.magic index) in + if Extc.dlptr (val_field a 1) != Obj.magic index then assert false; + ignore(Extc.dlcall2 val_gc a on_abstract_gc); + Extc.dlsetptr (val_fun_env callb) a; + callb + | VArray a -> + let va = Extc.dlcall1 alloc_array (Extc.dlint (Array.length a)) in + Array.iteri (fun i v -> + Extc.dlsetptr (val_field va i) (value_neko v) + ) a; + va + | VFloat f -> + Extc.dlcall1 alloc_float (Obj.magic f) + | VAbstract _ -> + failwith "Abstract not supported" + | VInt32 i -> + alloc_i32 i + in + let obj_r = ref [] in + let obj_fun = (fun v id -> obj_r := (v,id) :: !obj_r; val_null) in + let rec neko_value (v:Extc.value) = + if Obj.is_int (Obj.magic v) then + VInt (Obj.magic v) + else + let head = Extc.dltoint (Extc.dlptr v) in + match head land tag_mask with + | 0 -> VNull + | 2 -> VBool (v == val_true) + | 3 -> VString (copy_string v) + | 4 -> + ignore(Extc.dlcall3 val_iter_fields v (Extc.dlcallback 2) (Obj.magic obj_fun)); + let r = !obj_r in + obj_r := []; + let ctx = get_ctx() in + let fields = List.rev_map (fun (v,id) -> + let iid = Extc.dltoint id in + if not (Hashtbl.mem ctx.fields_cache iid) then begin + let name = copy_string (Extc.dlcall1 val_field_name id) in + ignore(hash_field ctx name); + end; + iid, neko_value v + ) r in + VObject { ofields = Array.of_list fields; oproto = None } + | 5 -> + VArray (Array.init (head asr tag_bits) (fun i -> neko_value (Extc.dlptr (val_field v i)))) + | 7 -> + let r = alloc_root v in + let a = ANekoAbstract v in + Gc.finalise (fun _ -> free_root r) a; + VAbstract a + | t -> + failwith ("Unsupported Neko value tag " ^ string_of_int t) + in + + Callback.register "dlcallb2" (fun args nargs -> + (* get back the VM env, which was set in value_neko *) + let env = Extc.dlptr (Extc.dladdr vm (2 * ptr_size)) in + (* extract the index stored in abstract data *) + let index : int = Obj.magic (Extc.dlptr (val_field env 1)) in + let f, obj = (try Hashtbl.find roots index with Not_found -> assert false) in + let nargs = Extc.dltoint nargs in + let rec loop i = + if i = nargs then [] else neko_value (Extc.dlptr (Extc.dladdr args (i * ptr_size))) :: loop (i + 1) + in + let v = (get_ctx()).do_call obj (VFunction f) (loop 0) { psource = ""; pline = 0; } in + value_neko v + ); + + let callprim (n,p,nargs) args = + let arr = Array.of_list (List.map value_neko args) in + let exc = ref null in + if Array.length arr <> nargs then failwith n; + let ret = Extc.dlcall5 callEx val_null p (Obj.magic arr) (Extc.dlint nargs) (Obj.magic exc) in + if !exc != null then raise (Runtime (neko_value !exc)); + (match !buffers with + | [] -> () + | l -> + buffers := []; + (* copy back data *) + List.iter (fun (buf,v) -> + Extc.dlmemcpy (Extc.dlstring buf) (val_str v) (String.length buf); + ) l); + neko_value ret + in + Some { + load = loadprim; + call = callprim; + } + +(* ---------------------------------------------------------------------- *) +(* BUILTINS *) + +let builtins = + let p = { psource = ""; pline = 0 } in + let error() = + raise Builtin_error + in + let vint = function + | VInt n -> n + | _ -> error() + in + let varray = function + | VArray a -> a + | _ -> error() + in + let vstring = function + | VString s -> s + | _ -> error() + in + let vobj = function + | VObject o -> o + | _ -> error() + in + let vfun = function + | VFunction f -> f + | VClosure (cl,f) -> FunVar (f cl) + | _ -> error() + in + let vhash = function + | VAbstract (AHash h) -> h + | _ -> error() + in + let build_stack sl = + let make p = + let p = make_pos p in + VArray [|VString p.Ast.pfile;VInt (Lexer.get_error_line p)|] + in + VArray (Array.of_list (List.map make sl)) + in + let do_closure args args2 = + match args with + | f :: obj :: args -> + (get_ctx()).do_call obj f (args @ args2) p + | _ -> + assert false + in + let funcs = [ + (* array *) + "array", FunVar (fun vl -> VArray (Array.of_list vl)); + "amake", Fun1 (fun v -> VArray (Array.create (vint v) VNull)); + "acopy", Fun1 (fun a -> VArray (Array.copy (varray a))); + "asize", Fun1 (fun a -> VInt (Array.length (varray a))); + "asub", Fun3 (fun a p l -> VArray (Array.sub (varray a) (vint p) (vint l))); + "ablit", Fun5 (fun dst dstp src p l -> + Array.blit (varray src) (vint p) (varray dst) (vint dstp) (vint l); + VNull + ); + "aconcat", Fun1 (fun arr -> + let arr = Array.map varray (varray arr) in + VArray (Array.concat (Array.to_list arr)) + ); + (* string *) + "string", Fun1 (fun v -> VString ((get_ctx()).do_string v)); + "smake", Fun1 (fun l -> VString (String.make (vint l) '\000')); + "ssize", Fun1 (fun s -> VInt (String.length (vstring s))); + "scopy", Fun1 (fun s -> VString (String.copy (vstring s))); + "ssub", Fun3 (fun s p l -> VString (String.sub (vstring s) (vint p) (vint l))); + "sget", Fun2 (fun s p -> + try VInt (int_of_char (String.get (vstring s) (vint p))) with Invalid_argument _ -> VNull + ); + "sset", Fun3 (fun s p c -> + let c = char_of_int ((vint c) land 0xFF) in + try + String.set (vstring s) (vint p) c; + VInt (int_of_char c) + with Invalid_argument _ -> VNull); + "sblit", Fun5 (fun dst dstp src p l -> + String.blit (vstring src) (vint p) (vstring dst) (vint dstp) (vint l); + VNull + ); + "sfind", Fun3 (fun src pos pat -> + try VInt (find_sub (vstring src) (vstring pat) (vint pos)) with Not_found -> VNull + ); + (* object *) + "new", Fun1 (fun o -> + match o with + | VNull -> VObject { ofields = [||]; oproto = None } + | VObject o -> VObject { ofields = Array.copy o.ofields; oproto = o.oproto } + | _ -> error() + ); + "objget", Fun2 (fun o f -> + match o with + | VObject o -> get_field o (vint f) + | _ -> VNull + ); + "objset", Fun3 (fun o f v -> + match o with + | VObject o -> set_field o (vint f) v; v + | _ -> VNull + ); + "objcall", Fun3 (fun o f pl -> + match o with + | VObject oo -> + (get_ctx()).do_call o (get_field oo (vint f)) (Array.to_list (varray pl)) p + | _ -> VNull + ); + "objfield", Fun2 (fun o f -> + match o with + | VObject o -> + let p = o.oproto in + o.oproto <- None; + let v = get_field_opt o (vint f) in + o.oproto <- p; + VBool (v <> None) + | _ -> VBool false + ); + "objremove", Fun2 (fun o f -> + VBool (remove_field (vobj o) (vint f)) + ); + "objfields", Fun1 (fun o -> + VArray (Array.map (fun (fid,_) -> VInt fid) (vobj o).ofields) + ); + "hash", Fun1 (fun v -> VInt (hash_field (get_ctx()) (vstring v))); + "fasthash", Fun1 (fun v -> VInt (hash (vstring v))); + "field", Fun1 (fun v -> + try VString (Hashtbl.find (get_ctx()).fields_cache (vint v)) with Not_found -> VNull + ); + "objsetproto", Fun2 (fun o p -> + let o = vobj o in + (match p with + | VNull -> o.oproto <- None + | VObject p -> o.oproto <- Some p + | _ -> error()); + VNull; + ); + "objgetproto", Fun1 (fun o -> + match (vobj o).oproto with + | None -> VNull + | Some p -> VObject p + ); + (* function *) + "nargs", Fun1 (fun f -> + VInt (nargs (vfun f)) + ); + "call", Fun3 (fun f o args -> + (get_ctx()).do_call o f (Array.to_list (varray args)) p + ); + "closure", FunVar (fun vl -> + match vl with + | VFunction f :: _ :: _ -> + VClosure (vl, do_closure) + | _ -> exc (VString "Can't create closure : value is not a function") + ); + "apply", FunVar (fun vl -> + match vl with + | f :: args -> + let f = vfun f in + VFunction (FunVar (fun args2 -> (get_ctx()).do_call VNull (VFunction f) (args @ args2) p)) + | _ -> exc (VString "Invalid closure arguments number") + ); + "varargs", Fun1 (fun f -> + match f with + | VFunction (FunVar _) | VFunction (Fun1 _) | VClosure _ -> + VFunction (FunVar (fun vl -> (get_ctx()).do_call VNull f [VArray (Array.of_list vl)] p)) + | _ -> + error() + ); + (* numbers *) + (* skip iadd, isub, idiv, imult *) + "isnan", Fun1 (fun f -> + match f with + | VFloat f -> VBool (f <> f) + | _ -> VBool false + ); + "isinfinite", Fun1 (fun f -> + match f with + | VFloat f -> VBool (f = infinity || f = neg_infinity) + | _ -> VBool false + ); + "int", Fun1 (fun v -> + match v with + | VInt _ | VInt32 _ -> v + | VFloat f -> best_int (to_int f) + | VString s -> (try parse_int s with _ -> VNull) + | _ -> VNull + ); + "float", Fun1 (fun v -> + match v with + | VInt i -> VFloat (float_of_int i) + | VInt32 i -> VFloat (Int32.to_float i) + | VFloat _ -> v + | VString s -> (try VFloat (parse_float s) with _ -> VNull) + | _ -> VNull + ); + (* abstract *) + "getkind", Fun1 (fun v -> + match v with + | VAbstract a -> VAbstract (AKind a) + | VInt32 _ -> VAbstract (AKind AInt32Kind) + | _ -> error() + ); + "iskind", Fun2 (fun v k -> + match v, k with + | VAbstract a, VAbstract (AKind k) -> VBool (Obj.tag (Obj.repr a) = Obj.tag (Obj.repr k)) + | VInt32 _, VAbstract (AKind AInt32Kind) -> VBool true + | _, VAbstract (AKind _) -> VBool false + | _ -> error() + ); + (* hash *) + "hkey", Fun1 (fun v -> VInt (Hashtbl.hash v)); + "hnew", Fun1 (fun v -> + VAbstract (AHash (match v with + | VNull -> Hashtbl.create 0 + | VInt n -> Hashtbl.create n + | _ -> error())) + ); + "hresize", Fun1 (fun v -> VNull); + "hget", Fun3 (fun h k cmp -> + if cmp <> VNull then assert false; + (try Hashtbl.find (vhash h) k with Not_found -> VNull) + ); + "hmem", Fun3 (fun h k cmp -> + if cmp <> VNull then assert false; + VBool (Hashtbl.mem (vhash h) k) + ); + "hremove", Fun3 (fun h k cmp -> + if cmp <> VNull then assert false; + let h = vhash h in + let old = Hashtbl.mem h k in + if old then Hashtbl.remove h k; + VBool old + ); + "hset", Fun4 (fun h k v cmp -> + if cmp <> VNull then assert false; + let h = vhash h in + let old = Hashtbl.mem h k in + Hashtbl.replace h k v; + VBool (not old); + ); + "hadd", Fun4 (fun h k v cmp -> + if cmp <> VNull then assert false; + let h = vhash h in + let old = Hashtbl.mem h k in + Hashtbl.add h k v; + VBool (not old); + ); + "hiter", Fun2 (fun h f -> Hashtbl.iter (fun k v -> ignore ((get_ctx()).do_call VNull f [k;v] p)) (vhash h); VNull); + "hcount", Fun1 (fun h -> VInt (Hashtbl.length (vhash h))); + "hsize", Fun1 (fun h -> VInt (Hashtbl.length (vhash h))); + (* misc *) + "print", FunVar (fun vl -> List.iter (fun v -> + let ctx = get_ctx() in + let com = ctx.curapi.get_com() in + com.print (ctx.do_string v) + ) vl; VNull); + "throw", Fun1 (fun v -> exc v); + "rethrow", Fun1 (fun v -> + let ctx = get_ctx() in + ctx.callstack <- List.rev (List.map (fun p -> { cpos = p; cthis = ctx.vthis; cstack = DynArray.length ctx.stack; cenv = ctx.venv }) ctx.exc) @ ctx.callstack; + exc v + ); + "istrue", Fun1 (fun v -> + match v with + | VNull | VInt 0 | VBool false | VInt32 0l -> VBool false + | _ -> VBool true + ); + "not", Fun1 (fun v -> + match v with + | VNull | VInt 0 | VBool false | VInt32 0l -> VBool true + | _ -> VBool false + ); + "typeof", Fun1 (fun v -> + VInt (match v with + | VNull -> 0 + | VInt _ | VInt32 _ -> 1 + | VFloat _ -> 2 + | VBool _ -> 3 + | VString _ -> 4 + | VObject _ -> 5 + | VArray _ -> 6 + | VFunction _ | VClosure _ -> 7 + | VAbstract _ -> 8) + ); + "compare", Fun2 (fun a b -> + match (get_ctx()).do_compare a b with + | CUndef -> VNull + | CEq -> VInt 0 + | CSup -> VInt 1 + | CInf -> VInt (-1) + ); + "pcompare", Fun2 (fun a b -> + assert false + ); + "excstack", Fun0 (fun() -> + build_stack (get_ctx()).exc + ); + "callstack", Fun0 (fun() -> + build_stack (List.map (fun s -> s.cpos) (get_ctx()).callstack) + ); + "version", Fun0 (fun() -> + VInt 200 + ); + (* extra *) + "use_neko_dll", Fun0 (fun() -> + VBool (neko <> None) + ); + ] in + let vals = [ + "tnull", VInt 0; + "tint", VInt 1; + "tfloat", VInt 2; + "tbool", VInt 3; + "tstring", VInt 4; + "tobject", VInt 5; + "tarray", VInt 6; + "tfunction", VInt 7; + "tabstract", VInt 8; + ] in + let h = Hashtbl.create 0 in + List.iter (fun (n,f) -> Hashtbl.add h n (VFunction f)) funcs; + List.iter (fun (n,v) -> Hashtbl.add h n v) vals; + h + +(* ---------------------------------------------------------------------- *) +(* STD LIBRARY *) + +let free_abstract a = + match a with + | VAbstract vp -> Obj.set_tag (Obj.repr vp) 0 (* this will mute it as Deallocated *) + | _ -> assert false + +let std_lib = + let p = { psource = ""; pline = 0 } in + let error() = + raise Builtin_error + in + let make_list l = + let rec loop acc = function + | [] -> acc + | x :: l -> loop (VArray [|x;acc|]) l + in + loop VNull (List.rev l) + in + let num = function + | VInt i -> float_of_int i + | VInt32 i -> Int32.to_float i + | VFloat f -> f + | _ -> error() + in + let make_date f = + VInt32 (Int32.of_float f) + in + let date = function + | VInt32 i -> Int32.to_float i + | VInt i -> float_of_int i + | _ -> error() + in + let make_i32 i = + VInt32 i + in + let int32 = function + | VInt i -> Int32.of_int i + | VInt32 i -> i + | _ -> error() + in + let vint = function + | VInt n -> n + | _ -> error() + in + let vstring = function + | VString s -> s + | _ -> error() + in + let int32_addr h = + let base = Int32.to_int (Int32.logand h 0xFFFFFFl) in + let str = Printf.sprintf "%ld.%d.%d.%d" (Int32.shift_right_logical h 24) (base lsr 16) ((base lsr 8) land 0xFF) (base land 0xFF) in + Unix.inet_addr_of_string str + in + let int32_op op = Fun2 (fun a b -> make_i32 (op (int32 a) (int32 b))) in + make_library ([ + (* math *) + "math_atan2", Fun2 (fun a b -> VFloat (atan2 (num a) (num b))); + "math_pow", Fun2 (fun a b -> VFloat ((num a) ** (num b))); + "math_abs", Fun1 (fun v -> + match v with + | VInt i -> VInt (abs i) + | VInt32 i -> VInt32 (Int32.abs i) + | VFloat f -> VFloat (abs_float f) + | _ -> error() + ); + "math_ceil", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (ceil (num v)))); + "math_floor", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (floor (num v)))); + "math_round", Fun1 (fun v -> match v with VInt _ | VInt32 _ -> v | _ -> best_int (to_int (floor (num v +. 0.5)))); + "math_pi", Fun0 (fun() -> VFloat (4.0 *. atan 1.0)); + "math_sqrt", Fun1 (fun v -> VFloat (sqrt (num v))); + "math_atan", Fun1 (fun v -> VFloat (atan (num v))); + "math_cos", Fun1 (fun v -> VFloat (cos (num v))); + "math_sin", Fun1 (fun v -> VFloat (sin (num v))); + "math_tan", Fun1 (fun v -> VFloat (tan (num v))); + "math_log", Fun1 (fun v -> VFloat (Pervasives.log (num v))); + "math_exp", Fun1 (fun v -> VFloat (exp (num v))); + "math_acos", Fun1 (fun v -> VFloat (acos (num v))); + "math_asin", Fun1 (fun v -> VFloat (asin (num v))); + "math_fceil", Fun1 (fun v -> VFloat (ceil (num v))); + "math_ffloor", Fun1 (fun v -> VFloat (floor (num v))); + "math_fround", Fun1 (fun v -> VFloat (floor (num v +. 0.5))); + "math_int", Fun1 (fun v -> + match v with + | VInt _ | VInt32 _ -> v + | VFloat f -> best_int (to_int (if f < 0. then ceil f else floor f)) + | _ -> error() + ); + (* buffer *) + "buffer_new", Fun0 (fun() -> + VAbstract (ABuffer (Buffer.create 0)) + ); + "buffer_add", Fun2 (fun b v -> + match b with + | VAbstract (ABuffer b) -> Buffer.add_string b ((get_ctx()).do_string v); VNull + | _ -> error() + ); + "buffer_add_char", Fun2 (fun b v -> + match b, v with + | VAbstract (ABuffer b), VInt n when n >= 0 && n < 256 -> Buffer.add_char b (char_of_int n); VNull + | _ -> error() + ); + "buffer_add_sub", Fun4 (fun b s p l -> + match b, s, p, l with + | VAbstract (ABuffer b), VString s, VInt p, VInt l -> (try Buffer.add_substring b s p l; VNull with _ -> error()) + | _ -> error() + ); + "buffer_string", Fun1 (fun b -> + match b with + | VAbstract (ABuffer b) -> VString (Buffer.contents b) + | _ -> error() + ); + "buffer_reset", Fun1 (fun b -> + match b with + | VAbstract (ABuffer b) -> Buffer.reset b; VNull; + | _ -> error() + ); + "buffer_get_length", Fun1 (fun b -> + match b with + | VAbstract (ABuffer b) -> VInt (Buffer.length b) + | _ -> error() + ); + (* date *) + "date_now", Fun0 (fun () -> + make_date (Unix.time()) + ); + "date_new", Fun1 (fun v -> + make_date (match v with + | VNull -> Unix.time() + | VString s -> + (match String.length s with + | 19 -> + let r = Str.regexp "^\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\) \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)$" in + if not (Str.string_match r s 0) then exc (VString ("Invalid date format : " ^ s)); + let t = Unix.localtime (Unix.time()) in + let t = { t with + tm_year = int_of_string (Str.matched_group 1 s) - 1900; + tm_mon = int_of_string (Str.matched_group 2 s) - 1; + tm_mday = int_of_string (Str.matched_group 3 s); + tm_hour = int_of_string (Str.matched_group 4 s); + tm_min = int_of_string (Str.matched_group 5 s); + tm_sec = int_of_string (Str.matched_group 6 s); + } in + fst (Unix.mktime t) + | 10 -> + assert false + | 8 -> + assert false + | _ -> + exc (VString ("Invalid date format : " ^ s))); + | _ -> error()) + ); + "date_set_hour", Fun4 (fun d h m s -> + let d = date d in + let t = Unix.localtime d in + make_date (fst (Unix.mktime { t with tm_hour = vint h; tm_min = vint m; tm_sec = vint s })) + ); + "date_set_day", Fun4 (fun d y m da -> + let d = date d in + let t = Unix.localtime d in + make_date (fst (Unix.mktime { t with tm_year = vint y - 1900; tm_mon = vint m - 1; tm_mday = vint da })) + ); + "date_format", Fun2 (fun d fmt -> + match fmt with + | VNull -> + let t = Unix.localtime (date d) in + VString (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) + | VString "%w" -> + (* week day *) + let t = Unix.localtime (date d) in + VString (string_of_int t.tm_wday) + | VString _ -> + exc (VString "Custom date format is not supported") (* use native Haxe implementation *) + | _ -> + error() + ); + "date_get_hour", Fun1 (fun d -> + let t = Unix.localtime (date d) in + let o = obj (hash_field (get_ctx())) [ + "h", VInt t.tm_hour; + "m", VInt t.tm_min; + "s", VInt t.tm_sec; + ] in + VObject o + ); + "date_get_day", Fun1 (fun d -> + let t = Unix.localtime (date d) in + let o = obj (hash_field (get_ctx())) [ + "d", VInt t.tm_mday; + "m", VInt (t.tm_mon + 1); + "y", VInt (t.tm_year + 1900); + ] in + VObject o + ); + (* string *) + "string_split", Fun2 (fun s d -> + make_list (match s, d with + | VString "", VString _ -> [VString ""] + | VString s, VString "" -> Array.to_list (Array.init (String.length s) (fun i -> VString (String.make 1 (String.get s i)))) + | VString s, VString d -> List.map (fun s -> VString s) (ExtString.String.nsplit s d) + | _ -> error()) + ); + "url_encode", Fun1 (fun s -> + let s = vstring s in + let b = Buffer.create 0 in + let hex = "0123456789ABCDEF" in + for i = 0 to String.length s - 1 do + let c = String.unsafe_get s i in + match c with + | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' | '-' | '.' -> + Buffer.add_char b c + | _ -> + Buffer.add_char b '%'; + Buffer.add_char b (String.unsafe_get hex (int_of_char c lsr 4)); + Buffer.add_char b (String.unsafe_get hex (int_of_char c land 0xF)); + done; + VString (Buffer.contents b) + ); + "url_decode", Fun1 (fun s -> + let s = vstring s in + let b = Buffer.create 0 in + let len = String.length s in + let decode c = + match c with + | '0'..'9' -> Some (int_of_char c - int_of_char '0') + | 'a'..'f' -> Some (int_of_char c - int_of_char 'a' + 10) + | 'A'..'F' -> Some (int_of_char c - int_of_char 'A' + 10) + | _ -> None + in + let rec loop i = + if i = len then () else + let c = String.unsafe_get s i in + match c with + | '%' -> + let p1 = (try decode (String.get s (i + 1)) with _ -> None) in + let p2 = (try decode (String.get s (i + 2)) with _ -> None) in + (match p1, p2 with + | Some c1, Some c2 -> + Buffer.add_char b (char_of_int ((c1 lsl 4) lor c2)); + loop (i + 3) + | _ -> + loop (i + 1)); + | '+' -> + Buffer.add_char b ' '; + loop (i + 1) + | c -> + Buffer.add_char b c; + loop (i + 1) + in + loop 0; + VString (Buffer.contents b) + ); + "base_encode", Fun2 (fun s b -> + match s, b with + | VString s, VString "0123456789abcdef" when String.length s = 16 -> + VString (Digest.to_hex s) + | VString s, VString b -> + if String.length b <> 64 then assert false; + let tbl = Array.init 64 (String.unsafe_get b) in + VString (Base64.str_encode ~tbl s) + | _ -> error() + ); + "base_decode", Fun2 (fun s b -> + let s = vstring s in + let b = vstring b in + if String.length b <> 64 then assert false; + let tbl = Array.init 64 (String.unsafe_get b) in + VString (Base64.str_decode ~tbl:(Base64.make_decoding_table tbl) s) + ); + "make_md5", Fun1 (fun s -> + VString (Digest.string (vstring s)) + ); + (* sprintf *) + (* int32 *) + "int32_new", Fun1 (fun v -> + match v with + | VInt32 _ -> v + | VInt i -> make_i32 (Int32.of_int i) + | VFloat f -> make_i32 (Int32.of_float f) + | _ -> error() + ); + "int32_to_int", Fun1 (fun v -> + let v = int32 v in + let i = Int32.to_int v in + if Int32.compare (Int32.of_int i) v <> 0 then error(); + VInt i + ); + "int32_to_float", Fun1 (fun v -> + VFloat (Int32.to_float (int32 v)) + ); + "int32_compare", Fun2 (fun a b -> + VInt (Int32.compare (int32 a) (int32 b)) + ); + "int32_add", int32_op Int32.add; + "int32_sub", int32_op Int32.sub; + "int32_mul", int32_op Int32.mul; + "int32_div", int32_op Int32.div; + "int32_shl", int32_op (fun a b -> Int32.shift_left a (Int32.to_int b)); + "int32_shr", int32_op (fun a b -> Int32.shift_right a (Int32.to_int b)); + "int32_ushr", int32_op (fun a b -> Int32.shift_right_logical a (Int32.to_int b)); + "int32_mod", int32_op Int32.rem; + "int32_or", int32_op Int32.logor; + "int32_and", int32_op Int32.logand; + "int32_xor", int32_op Int32.logxor; + "int32_neg", Fun1 (fun v -> make_i32 (Int32.neg (int32 v))); + "int32_complement", Fun1 (fun v -> make_i32 (Int32.lognot (int32 v))); + (* misc *) + "same_closure", Fun2 (fun a b -> + VBool (match a, b with + | VClosure (la,fa), VClosure (lb,fb) -> + fa == fb && List.length la = List.length lb && List.for_all2 (fun a b -> (get_ctx()).do_compare a b = CEq) la lb + | VFunction a, VFunction b -> a == b + | _ -> false) + ); + "double_bytes", Fun2 (fun f big -> + let f = (match f with VFloat f -> f | VInt i -> float_of_int i | _ -> error()) in + match big with + | VBool big -> + let ch = IO.output_string() in + if big then IO.BigEndian.write_double ch f else IO.write_double ch f; + VString (IO.close_out ch) + | _ -> + error() + ); + "float_bytes", Fun2 (fun f big -> + let f = (match f with VFloat f -> f | VInt i -> float_of_int i | _ -> error()) in + match big with + | VBool big -> + let ch = IO.output_string() in + let i = Int32.bits_of_float f in + if big then IO.BigEndian.write_real_i32 ch i else IO.write_real_i32 ch i; + VString (IO.close_out ch) + | _ -> + error() + ); + "double_of_bytes", Fun2 (fun s big -> + match s, big with + | VString s, VBool big when String.length s = 8 -> + let ch = IO.input_string s in + VFloat (if big then IO.BigEndian.read_double ch else IO.read_double ch) + | _ -> + error() + ); + "float_of_bytes", Fun2 (fun s big -> + match s, big with + | VString s, VBool big when String.length s = 4 -> + let ch = IO.input_string s in + VFloat (Int32.float_of_bits (if big then IO.BigEndian.read_real_i32 ch else IO.read_real_i32 ch)) + | _ -> + error() + ); + (* random *) + "random_new", Fun0 (fun() -> VAbstract (ARandom (ref (Random.State.make_self_init())))); + "random_set_seed", Fun2 (fun r s -> + match r, s with + | VAbstract (ARandom r), VInt seed -> r := Random.State.make [|seed|]; VNull + | VAbstract (ARandom r), VInt32 seed -> r := Random.State.make [|Int32.to_int seed|]; VNull + | _ -> error() + ); + "random_int", Fun2 (fun r s -> + match r, s with + | VAbstract (ARandom r), VInt max -> VInt (Random.State.int (!r) (if max <= 0 then 1 else max)) + | _ -> error() + ); + "random_float", Fun1 (fun r -> + match r with + | VAbstract (ARandom r) -> VFloat (Random.State.float (!r) 1.0) + | _ -> error() + ); + (* file *) + "file_open", Fun2 (fun f r -> + match f, r with + | VString f, VString r -> + let perms = 0o666 in + VAbstract (match r with + | "r" -> AFRead (open_in_gen [Open_rdonly] 0 f,ref false) + | "rb" -> AFRead (open_in_gen [Open_rdonly;Open_binary] 0 f,ref false) + | "w" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc] perms f) + | "wb" -> AFWrite (open_out_gen [Open_wronly;Open_creat;Open_trunc;Open_binary] perms f) + | "a" -> AFWrite (open_out_gen [Open_append] perms f) + | "ab" -> AFWrite (open_out_gen [Open_append;Open_binary] perms f) + | _ -> error()) + | _ -> error() + ); + "file_close", Fun1 (fun vf -> + (match vf with + | VAbstract (AFRead (f,_)) -> close_in f; free_abstract vf; + | VAbstract (AFWrite f) -> close_out f; free_abstract vf; + | _ -> error()); + VNull + ); + (* file_name *) + "file_write", Fun4 (fun f s p l -> + match f, s, p, l with + | VAbstract (AFWrite f), VString s, VInt p, VInt l -> output f s p l; VInt l + | _ -> error() + ); + "file_read", Fun4 (fun f s p l -> + match f, s, p, l with + | VAbstract (AFRead (f,r)), VString s, VInt p, VInt l -> + let n = input f s p l in + if n = 0 then begin + r := true; + exc (VArray [|VString "file_read"|]); + end; + VInt n + | _ -> error() + ); + "file_write_char", Fun2 (fun f c -> + match f, c with + | VAbstract (AFWrite f), VInt c -> output_char f (char_of_int c); VNull + | _ -> error() + ); + "file_read_char", Fun1 (fun f -> + match f with + | VAbstract (AFRead (f,r)) -> VInt (int_of_char (try input_char f with _ -> r := true; exc (VArray [|VString "file_read_char"|]))) + | _ -> error() + ); + "file_seek", Fun3 (fun f pos mode -> + match f, pos, mode with + | VAbstract (AFRead (f,r)), VInt pos, VInt mode -> + r := false; + seek_in f (match mode with 0 -> pos | 1 -> pos_in f + pos | 2 -> in_channel_length f + pos | _ -> error()); + VNull; + | VAbstract (AFWrite f), VInt pos, VInt mode -> + seek_out f (match mode with 0 -> pos | 1 -> pos_out f + pos | 2 -> out_channel_length f + pos | _ -> error()); + VNull; + | _ -> error() + ); + "file_tell", Fun1 (fun f -> + match f with + | VAbstract (AFRead (f,_)) -> VInt (pos_in f) + | VAbstract (AFWrite f) -> VInt (pos_out f) + | _ -> error() + ); + "file_eof", Fun1 (fun f -> + match f with + | VAbstract (AFRead (f,r)) -> + VBool !r + | _ -> error() + ); + "file_flush", Fun1 (fun f -> + (match f with + | VAbstract (AFWrite f) -> flush f + | _ -> error()); + VNull + ); + "file_contents", Fun1 (fun f -> + match f with + | VString f -> VString (Std.input_file ~bin:true f) + | _ -> error() + ); + "file_stdin", Fun0 (fun() -> VAbstract (AFRead (Pervasives.stdin, ref false))); + "file_stdout", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stdout)); + "file_stderr", Fun0 (fun() -> VAbstract (AFWrite Pervasives.stderr)); + (* serialize *) + (* TODO *) + (* socket *) + "socket_init", Fun0 (fun() -> VNull); + "socket_new", Fun1 (fun v -> + match v with + | VBool b -> VAbstract (ASocket (Unix.socket PF_INET (if b then SOCK_DGRAM else SOCK_STREAM) 0)); + | _ -> error() + ); + "socket_close", Fun1 (fun vs -> + match vs with + | VAbstract (ASocket s) -> Unix.close s; free_abstract vs; VNull + | _ -> error() + ); + "socket_send_char", Fun2 (fun s c -> + match s, c with + | VAbstract (ASocket s), VInt c when c >= 0 && c <= 255 -> + ignore(Unix.send s (String.make 1 (char_of_int c)) 0 1 []); + VNull + | _ -> error() + ); + "socket_send", Fun4 (fun s buf pos len -> + match s, buf, pos, len with + | VAbstract (ASocket s), VString buf, VInt pos, VInt len -> VInt (Unix.send s buf pos len []) + | _ -> error() + ); + "socket_recv", Fun4 (fun s buf pos len -> + match s, buf, pos, len with + | VAbstract (ASocket s), VString buf, VInt pos, VInt len -> VInt (Unix.recv s buf pos len []) + | _ -> error() + ); + "socket_recv_char", Fun1 (fun s -> + match s with + | VAbstract (ASocket s) -> + let buf = String.make 1 '\000' in + ignore(Unix.recv s buf 0 1 []); + VInt (int_of_char (String.unsafe_get buf 0)) + | _ -> error() + ); + "socket_write", Fun2 (fun s str -> + match s, str with + | VAbstract (ASocket s), VString str -> + let pos = ref 0 in + let len = ref (String.length str) in + while !len > 0 do + let k = Unix.send s str (!pos) (!len) [] in + pos := !pos + k; + len := !len - k; + done; + VNull + | _ -> error() + ); + "socket_read", Fun1 (fun s -> + match s with + | VAbstract (ASocket s) -> + let tmp = String.make 1024 '\000' in + let buf = Buffer.create 0 in + let rec loop() = + let k = (try Unix.recv s tmp 0 1024 [] with Unix_error _ -> 0) in + if k > 0 then begin + Buffer.add_substring buf tmp 0 k; + loop(); + end + in + loop(); + VString (Buffer.contents buf) + | _ -> error() + ); + "host_resolve", Fun1 (fun s -> + let h = (try Unix.gethostbyname (vstring s) with Not_found -> error()) in + let addr = Unix.string_of_inet_addr h.h_addr_list.(0) in + let a, b, c, d = Scanf.sscanf addr "%d.%d.%d.%d" (fun a b c d -> a,b,c,d) in + VInt32 (Int32.logor (Int32.shift_left (Int32.of_int a) 24) (Int32.of_int (d lor (c lsl 8) lor (b lsl 16)))) + ); + "host_to_string", Fun1 (fun h -> + match h with + | VInt32 h -> VString (Unix.string_of_inet_addr (int32_addr h)); + | _ -> error() + ); + "host_reverse", Fun1 (fun h -> + match h with + | VInt32 h -> VString (gethostbyaddr (int32_addr h)).h_name + | _ -> error() + ); + "host_local", Fun0 (fun() -> + VString (Unix.gethostname()) + ); + "socket_connect", Fun3 (fun s h p -> + match s, h, p with + | VAbstract (ASocket s), VInt32 h, VInt p -> + Unix.connect s (ADDR_INET (int32_addr h,p)); + VNull + | _ -> error() + ); + "socket_listen", Fun2 (fun s l -> + match s, l with + | VAbstract (ASocket s), VInt l -> + Unix.listen s l; + VNull + | _ -> error() + ); + "socket_set_timeout", Fun2 (fun s t -> + match s with + | VAbstract (ASocket s) -> + let t = (match t with VNull -> 0. | VInt t -> float_of_int t | VFloat f -> f | _ -> error()) in + Unix.setsockopt_float s SO_RCVTIMEO t; + Unix.setsockopt_float s SO_SNDTIMEO t; + VNull + | _ -> error() + ); + "socket_shutdown", Fun3 (fun s r w -> + match s, r, w with + | VAbstract (ASocket s), VBool r, VBool w -> + Unix.shutdown s (match r, w with true, true -> SHUTDOWN_ALL | true, false -> SHUTDOWN_RECEIVE | false, true -> SHUTDOWN_SEND | _ -> error()); + VNull + | _ -> error() + ); + (* TODO : select, bind, accept, peer, host *) + (* poll_alloc, poll : not planned *) + (* system *) + "get_env", Fun1 (fun v -> + try VString (Unix.getenv (vstring v)) with _ -> VNull + ); + "put_env", Fun2 (fun e v -> + Unix.putenv (vstring e) (vstring v); + VNull + ); + "sys_sleep", Fun1 (fun f -> + match f with + | VFloat f -> ignore(Unix.select [] [] [] f); VNull + | _ -> error() + ); + "set_time_locale", Fun1 (fun l -> + match l with + | VString s -> VBool false (* always fail *) + | _ -> error() + ); + "get_cwd", Fun0 (fun() -> + let dir = Unix.getcwd() in + let l = String.length dir in + VString (if l = 0 then "./" else match dir.[l - 1] with '/' | '\\' -> dir | _ -> dir ^ "/") + ); + "set_cwd", Fun1 (fun s -> + Unix.chdir (vstring s); + VNull; + ); + "sys_string", ( + let cached_sys_name = ref None in + Fun0 (fun() -> + VString (match Sys.os_type with + | "Unix" -> + (match !cached_sys_name with + | Some n -> n + | None -> + let ic = Unix.open_process_in "uname" in + let uname = (match input_line ic with + | "Darwin" -> "Mac" + | n -> n + ) in + close_in ic; + cached_sys_name := Some uname; + uname) + | "Win32" | "Cygwin" -> "Windows" + | s -> s) + ) + ); + "sys_is64", Fun0 (fun() -> + VBool (Sys.word_size = 64) + ); + "sys_command", Fun1 (fun cmd -> + VInt (((get_ctx()).curapi.get_com()).run_command (vstring cmd)) + ); + "sys_exit", Fun1 (fun code -> + if (get_ctx()).curapi.use_cache() then raise (Typecore.Fatal_error ("",Ast.null_pos)); + raise (Sys_exit(vint code)); + ); + "sys_exists", Fun1 (fun file -> + VBool (Sys.file_exists (vstring file)) + ); + "file_delete", Fun1 (fun file -> + Sys.remove (vstring file); + VNull; + ); + "sys_rename", Fun2 (fun file target -> + Sys.rename (vstring file) (vstring target); + VNull; + ); + "sys_stat", Fun1 (fun file -> + let s = Unix.stat (vstring file) in + VObject (obj (hash_field (get_ctx())) [ + "gid", VInt s.st_gid; + "uid", VInt s.st_uid; + "atime", VInt32 (Int32.of_float s.st_atime); + "mtime", VInt32 (Int32.of_float s.st_mtime); + "ctime", VInt32 (Int32.of_float s.st_ctime); + "dev", VInt s.st_dev; + "ino", VInt s.st_ino; + "nlink", VInt s.st_nlink; + "rdev", VInt s.st_rdev; + "size", VInt s.st_size; + "mode", VInt s.st_perm; + ]) + ); + "sys_file_type", Fun1 (fun file -> + VString (match (Unix.stat (vstring file)).st_kind with + | S_REG -> "file" + | S_DIR -> "dir" + | S_CHR -> "char" + | S_BLK -> "block" + | S_LNK -> "symlink" + | S_FIFO -> "fifo" + | S_SOCK -> "sock") + ); + "sys_create_dir", Fun2 (fun dir mode -> + Unix.mkdir (vstring dir) (vint mode); + VNull + ); + "sys_remove_dir", Fun1 (fun dir -> + Unix.rmdir (vstring dir); + VNull; + ); + "sys_time", Fun0 (fun() -> + VFloat (Unix.gettimeofday()) + ); + "sys_cpu_time", Fun0 (fun() -> + VFloat (Sys.time()) + ); + "sys_read_dir", Fun1 (fun dir -> + let d = Sys.readdir (vstring dir) in + let rec loop acc i = + if i < 0 then + acc + else + loop (VArray [|VString d.(i);acc|]) (i - 1) + in + loop VNull (Array.length d - 1) + ); + "file_full_path", Fun1 (fun file -> + VString (try Extc.get_full_path (vstring file) with _ -> error()) + ); + "sys_exe_path", Fun0 (fun() -> + VString (Sys.argv.(0)) + ); + "sys_env", Fun0 (fun() -> + let env = Unix.environment() in + let rec loop acc i = + if i < 0 then + acc + else + let e, v = ExtString.String.split env.(i) "=" in + loop (VArray [|VString e;VString v;acc|]) (i - 1) + in + loop VNull (Array.length env - 1) + ); + "sys_getch", Fun1 (fun echo -> + match echo with + | VBool b -> VInt (Extc.getch b) + | _ -> error() + ); + "sys_get_pid", Fun0 (fun() -> + VInt (Unix.getpid()) + ); + (* utf8 *) + "utf8_buf_alloc", Fun1 (fun v -> + VAbstract (AUtf8 (UTF8.Buf.create (vint v))) + ); + "utf8_buf_add", Fun2 (fun b c -> + match b with + | VAbstract (AUtf8 buf) -> UTF8.Buf.add_char buf (UChar.chr_of_uint (vint c)); VNull + | _ -> error() + ); + "utf8_buf_content", Fun1 (fun b -> + match b with + | VAbstract (AUtf8 buf) -> VString (UTF8.Buf.contents buf); + | _ -> error() + ); + "utf8_buf_length", Fun1 (fun b -> + match b with + | VAbstract (AUtf8 buf) -> VInt (UTF8.length (UTF8.Buf.contents buf)); + | _ -> error() + ); + "utf8_buf_size", Fun1 (fun b -> + match b with + | VAbstract (AUtf8 buf) -> VInt (String.length (UTF8.Buf.contents buf)); + | _ -> error() + ); + "utf8_validate", Fun1 (fun s -> + VBool (try UTF8.validate (vstring s); true with UTF8.Malformed_code -> false) + ); + "utf8_length", Fun1 (fun s -> + VInt (UTF8.length (vstring s)) + ); + "utf8_sub", Fun3 (fun s p l -> + let buf = UTF8.Buf.create 0 in + let pos = ref (-1) in + let p = vint p and l = vint l in + UTF8.iter (fun c -> + incr pos; + if !pos >= p && !pos < p + l then UTF8.Buf.add_char buf c; + ) (vstring s); + VString (UTF8.Buf.contents buf) + ); + "utf8_get", Fun2 (fun s p -> + VInt (UChar.uint_code (try UTF8.get (vstring s) (vint p) with _ -> error())) + ); + "utf8_iter", Fun2 (fun s f -> + let ctx = get_ctx() in + UTF8.iter (fun c -> + ignore(ctx.do_call VNull f [VInt (UChar.uint_code c)] p); + ) (vstring s); + VNull; + ); + "utf8_compare", Fun2 (fun s1 s2 -> + VInt (UTF8.compare (vstring s1) (vstring s2)) + ); + (* thread *) + "thread_create", Fun2 (fun f p -> + exc (VString "Can't create thread from within a macro"); + ); + "tls_create", Fun0 (fun() -> + VAbstract (ATls (ref VNull)) + ); + "tls_get", Fun1 (fun t -> + match t with + | VAbstract (ATls r) -> !r + | _ -> error(); + ); + "tls_set", Fun2 (fun t v -> + match t with + | VAbstract (ATls r) -> r := v; VNull + | _ -> error(); + ); + (* lock, mutex, deque : not implemented *) + (* process *) + "process_run", (Fun2 (fun p args -> + match p, args with + | VString p, VArray args -> VAbstract (AProcess (Process.run p (Array.map vstring args))) + | _ -> error() + )); + "process_stdout_read", (Fun4 (fun p str pos len -> + match p, str, pos, len with + | VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.read_stdout p str pos len) + | _ -> error() + )); + "process_stderr_read", (Fun4 (fun p str pos len -> + match p, str, pos, len with + | VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.read_stderr p str pos len) + | _ -> error() + )); + "process_stdin_write", (Fun4 (fun p str pos len -> + match p, str, pos, len with + | VAbstract (AProcess p), VString str, VInt pos, VInt len -> VInt (Process.write_stdin p str pos len) + | _ -> error() + )); + "process_stdin_close", (Fun1 (fun p -> + match p with + | VAbstract (AProcess p) -> Process.close_stdin p; VNull + | _ -> error() + )); + "process_exit", (Fun1 (fun p -> + match p with + | VAbstract (AProcess p) -> VInt (Process.exit p) + | _ -> error() + )); + "process_pid", (Fun1 (fun p -> + match p with + | VAbstract (AProcess p) -> VInt (Process.pid p) + | _ -> error() + )); + "process_close", (Fun1 (fun vp -> + match vp with + | VAbstract (AProcess p) -> Process.close p; free_abstract vp; VNull + | _ -> error() + )); + (* xml *) + "parse_xml", (match neko with + | None -> Fun2 (fun str o -> + match str, o with + | VString str, VObject events -> + let ctx = get_ctx() in + let p = { psource = "parse_xml"; pline = 0 } in + let xml = get_field events (hash "xml") in + let don = get_field events (hash "done") in + let pcdata = get_field events (hash "pcdata") in + (* + + Since we use the Xml parser, we don't have support for + - CDATA + - comments, prolog, doctype (allowed but skipped) + + let cdata = get_field events (hash "cdata") in + let comment = get_field events (hash "comment") in + *) + let rec loop = function + | Xml.Element (node, attribs, children) -> + ignore(ctx.do_call o xml [VString node;VObject (obj (hash_field ctx) (List.map (fun (a,v) -> a, VString v) attribs))] p); + List.iter loop children; + ignore(ctx.do_call o don [] p); + | Xml.PCData s -> + ignore(ctx.do_call o pcdata [VString s] p); + in + let x = XmlParser.make() in + XmlParser.check_eof x false; + loop (try + XmlParser.parse x (XmlParser.SString str) + with Xml.Error e -> failwith ("Parser failure (" ^ Xml.error e ^ ")") + | e -> failwith ("Parser failure (" ^ Printexc.to_string e ^ ")")); + VNull + | _ -> error()) + | Some neko -> + let parse_xml = neko.load "std@parse_xml" 2 in + Fun2 (fun str o -> neko.call parse_xml [str;o]) + ); + (* memory, module : not planned *) + ] + (* process *) + @ (match neko with + | None -> [] + | Some neko -> + let win_ec = (try Some (neko.load "std@win_env_changed" 0) with _ -> None) in + [ + "win_env_changed", (Fun0 (fun() -> match win_ec with None -> error() | Some f -> neko.call f [])); + ])) + + +(* ---------------------------------------------------------------------- *) +(* REGEXP LIBRARY *) + +let reg_lib = + let error() = + raise Builtin_error + in + (* try to load regexp first : we might fail if pcre is not installed *) + let neko = (match neko with + | None -> None + | Some neko -> + (try ignore(neko.load "regexp@regexp_new_options" 2); Some neko with _ -> None) + ) in + match neko with + | None -> + make_library [ + (* regexp_new : deprecated *) + "regexp_new_options", Fun2 (fun str opt -> + match str, opt with + | VString str, VString opt -> + let case_sensitive = ref true in + List.iter (function + | 'm' -> () (* always ON ? *) + | 'i' -> case_sensitive := false + | c -> failwith ("Unsupported regexp option '" ^ String.make 1 c ^ "'") + ) (ExtString.String.explode opt); + let buf = Buffer.create 0 in + let rec loop prev esc = function + | [] -> () + | c :: l when esc -> + (match c with + | 'n' -> Buffer.add_char buf '\n' + | 'r' -> Buffer.add_char buf '\r' + | 't' -> Buffer.add_char buf '\t' + | 'd' -> Buffer.add_string buf "[0-9]" + | '\\' -> Buffer.add_string buf "\\\\" + | '(' | ')' -> Buffer.add_char buf c + | '1'..'9' | '+' | '$' | '^' | '*' | '?' | '.' | '[' | ']' -> + Buffer.add_char buf '\\'; + Buffer.add_char buf c; + | _ -> failwith ("Unsupported escaped char '" ^ String.make 1 c ^ "'")); + loop c false l + | c :: l -> + match c with + | '\\' -> loop prev true l + | '(' | '|' | ')' -> + Buffer.add_char buf '\\'; + Buffer.add_char buf c; + loop c false l + | '?' when prev = '(' && (match l with ':' :: _ -> true | _ -> false) -> + failwith "Non capturing groups '(?:' are not supported in macros" + | '?' when prev = '*' -> + failwith "Ungreedy *? are not supported in macros" + | _ -> + Buffer.add_char buf c; + loop c false l + in + loop '\000' false (ExtString.String.explode str); + let str = Buffer.contents buf in + let r = { + r = if !case_sensitive then Str.regexp str else Str.regexp_case_fold str; + r_string = ""; + r_groups = [||]; + } in + VAbstract (AReg r) + | _ -> error() + ); + "regexp_match", Fun4 (fun r str pos len -> + match r, str, pos, len with + | VAbstract (AReg r), VString str, VInt pos, VInt len -> + let nstr, npos, delta = (if len = String.length str - pos then str, pos, 0 else String.sub str pos len, 0, pos) in + (try + ignore(Str.search_forward r.r nstr npos); + let rec loop n = + if n = 9 then + [] + else try + (Some (Str.group_beginning n + delta, Str.group_end n + delta)) :: loop (n + 1) + with Not_found -> + None :: loop (n + 1) + | Invalid_argument _ -> + [] + in + r.r_string <- str; + r.r_groups <- Array.of_list (loop 0); + VBool true; + with Not_found -> + VBool false) + | _ -> error() + ); + "regexp_matched", Fun2 (fun r n -> + match r, n with + | VAbstract (AReg r), VInt n -> + (match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with + | None -> VNull + | Some (pos,pend) -> VString (String.sub r.r_string pos (pend - pos))) + | _ -> error() + ); + "regexp_matched_pos", Fun2 (fun r n -> + match r, n with + | VAbstract (AReg r), VInt n -> + (match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with + | None -> VNull + | Some (pos,pend) -> VObject (obj (hash_field (get_ctx())) ["pos",VInt pos;"len",VInt (pend - pos)])) + | _ -> error() + ); + (* regexp_replace : not used by Haxe *) + (* regexp_replace_all : not used by Haxe *) + (* regexp_replace_fun : not used by Haxe *) + ] + | Some neko -> + let regexp_new_options = neko.load "regexp@regexp_new_options" 2 in + let regexp_match = neko.load "regexp@regexp_match" 4 in + let regexp_matched = neko.load "regexp@regexp_matched" 2 in + let regexp_matched_pos = neko.load "regexp@regexp_matched_pos" 2 in + make_library [ + "regexp_new_options", Fun2 (fun str opt -> neko.call regexp_new_options [str;opt]); + "regexp_match", Fun4 (fun r str pos len -> neko.call regexp_match [r;str;pos;len]); + "regexp_matched", Fun2 (fun r n -> neko.call regexp_matched [r;n]); + "regexp_matched_pos", Fun2 (fun r n -> neko.call regexp_matched_pos [r;n]); + ] + + +(* ---------------------------------------------------------------------- *) +(* ZLIB LIBRARY *) + +let z_lib = + let error() = + raise Builtin_error + in + make_library [ + "inflate_init", Fun1 (fun f -> + let z = Extc.zlib_inflate_init2 (match f with VNull -> 15 | VInt i -> i | _ -> error()) in + VAbstract (AZipI { z = z; z_flush = Extc.Z_NO_FLUSH }) + ); + "deflate_init", Fun1 (fun f -> + let z = Extc.zlib_deflate_init (match f with VInt i -> i | _ -> error()) in + VAbstract (AZipD { z = z; z_flush = Extc.Z_NO_FLUSH }) + ); + "deflate_end", Fun1 (fun vz -> + match vz with + | VAbstract (AZipD z) -> Extc.zlib_deflate_end z.z; free_abstract vz; VNull; + | _ -> error() + ); + "inflate_end", Fun1 (fun vz -> + match vz with + | VAbstract (AZipI z) -> Extc.zlib_inflate_end z.z; free_abstract vz; VNull; + | _ -> error() + ); + "set_flush_mode", Fun2 (fun z f -> + match z, f with + | VAbstract (AZipI z | AZipD z), VString s -> + z.z_flush <- (match s with + | "NO" -> Extc.Z_NO_FLUSH + | "SYNC" -> Extc.Z_SYNC_FLUSH + | "FULL" -> Extc.Z_FULL_FLUSH + | "FINISH" -> Extc.Z_FINISH + | "BLOCK" -> Extc.Z_PARTIAL_FLUSH + | _ -> error()); + VNull; + | _ -> error() + ); + "inflate_buffer", Fun5 (fun z src pos dst dpos -> + match z, src, pos, dst, dpos with + | VAbstract (AZipI z), VString src, VInt pos, VString dst, VInt dpos -> + let r = Extc.zlib_inflate z.z src pos (String.length src - pos) dst dpos (String.length dst - dpos) z.z_flush in + VObject (obj (hash_field (get_ctx())) [ + "done", VBool r.Extc.z_finish; + "read", VInt r.Extc.z_read; + "write", VInt r.Extc.z_wrote; + ]) + | _ -> error() + ); + "deflate_buffer", Fun5 (fun z src pos dst dpos -> + match z, src, pos, dst, dpos with + | VAbstract (AZipD z), VString src, VInt pos, VString dst, VInt dpos -> + let r = Extc.zlib_deflate z.z src pos (String.length src - pos) dst dpos (String.length dst - dpos) z.z_flush in + VObject (obj (hash_field (get_ctx())) [ + "done", VBool r.Extc.z_finish; + "read", VInt r.Extc.z_read; + "write", VInt r.Extc.z_wrote; + ]) + | _ -> error() + ); + "deflate_bound", Fun2 (fun z size -> + match z, size with + | VAbstract (AZipD z), VInt size -> VInt (size + 1024) + | _ -> error() + ); + ] + +(* ---------------------------------------------------------------------- *) +(* MACRO LIBRARY *) + +(* convert float value to haxe expression, handling inf/-inf/nan *) +let haxe_float f p = + let std = (Ast.EConst (Ast.Ident "std"), p) in + let math = (Ast.EField (std, "Math"), p) in + if (f = infinity) then + (Ast.EField (math, "POSITIVE_INFINITY"), p) + else if (f = neg_infinity) then + (Ast.EField (math, "NEGATIVE_INFINITY"), p) + else if (f <> f) then + (Ast.EField (math, "NaN"), p) + else + (Ast.EConst (Ast.Float (float_repres f)), p) + +let macro_lib = + let error() = + raise Builtin_error + in + let ccom() = + (get_ctx()).curapi.get_com() + in + make_library [ + "curpos", Fun0 (fun() -> VAbstract (APos (get_ctx()).curapi.pos)); + "error", Fun2 (fun msg p -> + match msg, p with + | VString s, VAbstract (APos p) -> + (ccom()).Common.error s p; + raise Abort + | _ -> error() + ); + "fatal_error", Fun2 (fun msg p -> + match msg, p with + | VString s, VAbstract (APos p) -> + raise (Typecore.Fatal_error (s,p)) + | _ -> error() + ); + "warning", Fun2 (fun msg p -> + match msg, p with + | VString s, VAbstract (APos p) -> + (ccom()).warning s p; + VNull; + | _ -> error() + ); + "class_path", Fun0 (fun() -> + VArray (Array.of_list (List.map (fun s -> VString s) (ccom()).class_path)); + ); + "resolve", Fun1 (fun file -> + match file with + | VString s -> VString (try Common.find_file (ccom()) s with Not_found -> failwith ("File not found '" ^ s ^ "'")) + | _ -> error(); + ); + "define", Fun1 (fun s -> + match s with + | VString s -> Common.raw_define (ccom()) s; VNull + | _ -> error(); + ); + "defined", Fun1 (fun s -> + match s with + | VString s -> VBool (Common.raw_defined (ccom()) s) + | _ -> error(); + ); + "defined_value", Fun1 (fun s -> + match s with + | VString s -> (try VString (Common.raw_defined_value (ccom()) s) with Not_found -> VNull) + | _ -> error(); + ); + "get_defines", Fun0 (fun() -> + let defines = (ccom()).defines in + let h = Hashtbl.create 0 in + PMap.iter (fun n v -> Hashtbl.replace h (VString n) (VString v)) defines; + enc_hash h + ); + "get_type", Fun1 (fun s -> + match s with + | VString s -> + (match (get_ctx()).curapi.get_type s with + | None -> failwith ("Type not found '" ^ s ^ "'") + | Some t -> encode_type t) + | _ -> error() + ); + "get_module", Fun1 (fun s -> + match s with + | VString s -> + enc_array (List.map encode_type ((get_ctx()).curapi.get_module s)) + | _ -> error() + ); + "on_generate", Fun1 (fun f -> + match f with + | VFunction (Fun1 _) -> + let ctx = get_ctx() in + ctx.curapi.on_generate (fun tl -> + ignore(catch_errors ctx (fun() -> ctx.do_call VNull f [enc_array (List.map encode_type tl)] null_pos)); + ); + VNull + | _ -> error() + ); + "after_generate", Fun1 (fun f -> + match f with + | VFunction (Fun0 _) -> + let ctx = get_ctx() in + ctx.curapi.after_generate (fun () -> + ignore(catch_errors ctx (fun() -> ctx.do_call VNull f [] null_pos)); + ); + VNull + | _ -> error() + ); + "on_type_not_found", Fun1 (fun f -> + match f with + | VFunction (Fun1 _) -> + let ctx = get_ctx() in + ctx.curapi.on_type_not_found (fun path -> + match catch_errors ctx (fun () -> ctx.do_call VNull f [enc_string path] null_pos) with + | Some v -> v + | None -> VNull + ); + VNull + | _ -> error() + ); + "parse", Fun3 (fun s p b -> + match s, p, b with + | VString s, VAbstract (APos p), VBool b when s <> "" -> + (try encode_expr ((get_ctx()).curapi.parse_string s p b) with Invalid_expr -> error()) + | _ -> error() + ); + "make_expr", Fun2 (fun v p -> + match p with + | VAbstract (APos p) -> + let h_enum = hash "__enum__" and h_et = hash "__et__" and h_ct = hash "__ct__" in + let h_tag = hash "tag" and h_args = hash "args" in + let h_length = hash "length" in + let ctx = get_ctx() in + let error v = failwith ("Unsupported value " ^ ctx.do_string v) in + let make_path t = + let rec loop = function + | [] -> assert false + | [name] -> (Ast.EConst (Ast.Ident name),p) + | name :: l -> (Ast.EField (loop l,name),p) + in + let t = t_infos t in + loop (List.rev (if t.mt_module.m_path = t.mt_path then fst t.mt_path @ [snd t.mt_path] else fst t.mt_module.m_path @ [snd t.mt_module.m_path;snd t.mt_path])) + in + let rec loop = function + | VNull -> (Ast.EConst (Ast.Ident "null"),p) + | VBool b -> (Ast.EConst (Ast.Ident (if b then "true" else "false")),p) + | VInt i -> (Ast.EConst (Ast.Int (string_of_int i)),p) + | VInt32 i -> (Ast.EConst (Ast.Int (Int32.to_string i)),p) + | VFloat f -> haxe_float f p + | VAbstract (APos p) -> + (Ast.EObjectDecl ( + ("fileName" , (Ast.EConst (Ast.String p.Ast.pfile) , p)) :: + ("lineNumber" , (Ast.EConst (Ast.Int (string_of_int (Lexer.get_error_line p))),p)) :: + ("className" , (Ast.EConst (Ast.String ("")),p)) :: + [] + ), p) + | VString _ | VArray _ | VAbstract _ | VFunction _ | VClosure _ as v -> error v + | VObject o as v -> + match o.oproto with + | None -> + (match get_field_opt o h_ct with + | Some (VAbstract (ATDecl t)) -> + make_path t + | _ -> + let fields = List.fold_left (fun acc (fid,v) -> (field_name ctx fid, loop v) :: acc) [] (Array.to_list o.ofields) in + (Ast.EObjectDecl fields, p)) + | Some proto -> + match get_field_opt proto h_enum, get_field_opt o h_a, get_field_opt o h_s, get_field_opt o h_length with + | _, Some (VArray a), _, Some (VInt len) -> + (Ast.EArrayDecl (List.map loop (Array.to_list (Array.sub a 0 len))),p) + | _, _, Some (VString s), _ -> + (Ast.EConst (Ast.String s),p) + | Some (VObject en), _, _, _ -> + (match get_field en h_et, get_field o h_tag with + | VAbstract (ATDecl t), VString tag -> + let e = (Ast.EField (make_path t,tag),p) in + (match get_field_opt o h_args with + | Some (VArray args) -> + let args = List.map loop (Array.to_list args) in + (Ast.ECall (e,args),p) + | _ -> e) + | _ -> + error v) + | _ -> + error v + in + encode_expr (loop v) + | _ -> error() + ); + "signature", Fun1 (fun v -> + let cache = ref [] in + let cache_count = ref 0 in + let hfiles = Hashtbl.create 0 in + let get_file f = + try + Hashtbl.find hfiles f + with Not_found -> + let ff = Common.unique_full_path f in + Hashtbl.add hfiles f ff; + ff + in + let do_cache (v:value) (v2:value) = + (* + tricky : we need to have a quick not-linear cache based on objects address + but we can't use address since the GC might be triggered here. + Instead let's mutate the object temporary. + *) + let vt = Obj.repr v in + let old = Obj.tag vt in + let old_val = Obj.field vt 0 in + let abstract_tag = 7 in + Obj.set_tag vt abstract_tag; + Obj.set_field vt 0 (Obj.repr (ACacheRef v2)); + cache := (vt,old,old_val) :: !cache; + incr cache_count + in + let rec loop v = + match v with + | VNull | VBool _ | VInt _ | VFloat _ | VString _ | VInt32 _ -> v + | VObject o -> + let o2 = { ofields = [||]; oproto = None } in + let v2 = VObject o2 in + do_cache v v2; + Array.iter (fun (f,v) -> if f <> h_class then set_field o2 f (loop v)) o.ofields; + (match o.oproto with + | None -> () + | Some p -> (match loop (VObject p) with VObject p2 -> o2.oproto <- Some p2 | _ -> assert false)); + v2 + | VArray a -> + let a2 = Array.create (Array.length a) VNull in + let v2 = VArray a2 in + do_cache v v2; + for i = 0 to Array.length a - 1 do + a2.(i) <- loop a.(i); + done; + v2 + | VFunction f -> + let v2 = VFunction (Obj.magic !cache_count) in + do_cache v v2; + v2 + | VClosure (vl,f) -> + let rl = ref [] in + let v2 = VClosure (Obj.magic rl, Obj.magic !cache_count) in + (* in ocaml 4.0+ it was reported some stack overflow, related to vl being GC'ed or mutated in do_cache. + let's make sure to have a real pointer to it first. The fix will trigger an alloc which might have simply moved the problem away *) + let vl = VNull :: vl in + do_cache v v2; + rl := List.map loop vl; + v2 + | VAbstract (APos p) -> VAbstract (APos { p with Ast.pfile = get_file p.Ast.pfile }) + | VAbstract (ACacheRef v) -> v + | VAbstract (AHash h) -> + let h2 = Hashtbl.create 0 in + let v2 = VAbstract (AHash h2) in + do_cache v v2; + Hashtbl.iter (fun k v -> Hashtbl.add h2 k (loop v)) h2; + v2 + | VAbstract _ -> + let v2 = VAbstract (Obj.magic !cache_count) in + do_cache v v2; + v2 + in + let v = loop v in + (* restore *) + List.iter (fun (vt,tag,field) -> + Obj.set_tag vt tag; + Obj.set_field vt 0 field; + ) !cache; + VString (Digest.to_hex (Digest.string (Marshal.to_string v [Marshal.Closures]))) + ); + "to_complex", Fun1 (fun v -> + try encode_complex_type (make_complex_type (decode_type v)) + with Exit -> VNull + ); + "unify", Fun2 (fun t1 t2 -> + let e1 = mk (TObjectDecl []) (decode_type t1) Ast.null_pos in + try ignore(((get_ctx()).curapi.cast_or_unify) (decode_type t2) e1 Ast.null_pos); VBool true + with Typecore.Error (Typecore.Unify _,_) -> VBool false + ); + "typeof", Fun1 (fun v -> + encode_type ((get_ctx()).curapi.type_expr (decode_expr v)).etype + ); + "type_expr", Fun1 (fun v -> + encode_texpr ((get_ctx()).curapi.type_expr (decode_expr v)) + ); + "s_type", Fun1 (fun v -> + VString (Type.s_type (print_context()) (decode_type v)) + ); + "s_expr", Fun2 (fun v b -> + let f = match b with VBool true -> Type.s_expr_pretty "" | _ -> Type.s_expr_ast true "" in + VString (f (Type.s_type (print_context())) (decode_texpr v)) + ); + "is_fmt_string", Fun1 (fun v -> + match v with + | VAbstract (APos p) -> VBool(Lexer.is_fmt_string p) + | _ -> VNull + ); + "format_string", Fun2 (fun s p -> + match s,p with + | VString(s),VAbstract(APos p) -> encode_expr ((get_ctx()).curapi.format_string s p) + | _ -> VNull + ); + "display", Fun1 (fun v -> + match v with + | VString s -> + VString ((get_ctx()).curapi.get_display s) + | _ -> + error() + ); + "allow_package", Fun1 (fun v -> + match v with + | VString s -> + (get_ctx()).curapi.allow_package s; + VNull + | _ -> error()); + "type_patch", Fun4 (fun t f s v -> + let p = (get_ctx()).curapi.type_patch in + (match t, f, s, v with + | VString t, VString f, VBool s, VString v -> p t f s (Some v) + | VString t, VString f, VBool s, VNull -> p t f s None + | _ -> error()); + VNull + ); + "meta_patch", Fun4 (fun m t f s -> + let p = (get_ctx()).curapi.meta_patch in + (match m, t, f, s with + | VString m, VString t, VString f, VBool s -> p m t (Some f) s + | VString m, VString t, VNull, VBool s -> p m t None s + | _ -> error()); + VNull + ); + "add_global_metadata", Fun5 (fun v1 v2 v3 v4 v5 -> + match v1,v2,v3,v4,v5 with + | VString s1,VString s2,VBool b1,VBool b2,VBool b3 -> + (get_ctx()).curapi.add_global_metadata s1 s2 (b1,b2,b3); + VNull + | _ -> + error() + ); + "custom_js", Fun1 (fun f -> + match f with + | VFunction (Fun1 _) -> + let ctx = get_ctx() in + ctx.curapi.set_js_generator (fun api -> + ignore(catch_errors ctx (fun() -> ctx.do_call VNull f [api] null_pos)); + ); + VNull + | _ -> error() + ); + "get_pos_infos", Fun1 (fun p -> + match p with + | VAbstract (APos p) -> VObject (obj (hash_field (get_ctx())) ["min",VInt p.Ast.pmin;"max",VInt p.Ast.pmax;"file",VString p.Ast.pfile]) + | _ -> error() + ); + "make_pos", Fun3 (fun min max file -> + match min, max, file with + | VInt min, VInt max, VString file -> VAbstract (APos { Ast.pmin = min; Ast.pmax = max; Ast.pfile = file }) + | _ -> error() + ); + "add_resource", Fun2 (fun name data -> + match name, data with + | VString name, VString data -> + Hashtbl.replace (ccom()).resources name data; + let m = (get_ctx()).curapi.current_module() in + m.m_extra.m_binded_res <- PMap.add name data m.m_extra.m_binded_res; + VNull + | _ -> error() + ); + "get_resources", Fun0 (fun() -> + let res = (ccom()).resources in + let h = Hashtbl.create 0 in + Hashtbl.iter (fun n v -> Hashtbl.replace h (VString n) (VString v)) res; + enc_hash h + ); + "local_module", Fun0 (fun() -> + let m = (get_ctx()).curapi.current_module() in + VString (Ast.s_type_path m.m_path); + ); + "local_type", Fun0 (fun() -> + match (get_ctx()).curapi.get_local_type() with + | None -> VNull + | Some t -> encode_type t + ); + "expected_type", Fun0 (fun() -> + match (get_ctx()).curapi.get_expected_type() with + | None -> VNull + | Some t -> encode_type t + ); + "call_arguments", Fun0 (fun() -> + match (get_ctx()).curapi.get_call_arguments() with + | None -> VNull + | Some el -> enc_array (List.map encode_expr el) + ); + "local_method", Fun0 (fun() -> + VString ((get_ctx()).curapi.get_local_method()) + ); + "local_using", Fun0 (fun() -> + enc_array (List.map encode_clref ((get_ctx()).curapi.get_local_using())) + ); + "local_vars", Fun1 (fun as_var -> + let as_var = match as_var with + | VNull | VBool false -> false + | VBool true -> true + | _ -> error() + in + let vars = (get_ctx()).curapi.get_local_vars() in + let h = Hashtbl.create 0 in + if as_var then + PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_tvar v)) vars + else + PMap.iter (fun n v -> Hashtbl.replace h (VString n) (encode_type v.v_type)) vars; + enc_hash h + ); + "follow", Fun2 (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 -> + (!f)() + in + encode_type (match once with VNull | VBool false -> follow t | VBool true -> follow_once t | _ -> error()) + ); + "build_fields", Fun0 (fun() -> + (get_ctx()).curapi.get_build_fields() + ); + "define_type", Fun1 (fun v -> + (get_ctx()).curapi.define_type v; + VNull + ); + "define_module", Fun4 (fun p v i u -> + match p, v, i, u with + | VString path, VArray vl, VArray ui, VArray ul -> + (get_ctx()).curapi.define_module path (Array.to_list vl) (List.map decode_import (Array.to_list ui)) (List.map decode_path (Array.to_list ul)); + VNull + | _ -> + error() + ); + "add_class_path", Fun1 (fun v -> + match v with + | VString cp -> + let com = ccom() in + com.class_path <- (Common.normalize_path cp) :: com.class_path; + Hashtbl.clear com.file_lookup_cache; + VNull + | _ -> + error() + ); + "add_native_lib", Fun1 (fun v -> + match v with + | VString file -> + let com = ccom() in + (match com.platform with + | Flash -> Genswf.add_swf_lib com file false + | Java -> Genjava.add_java_lib com file false + | Cs -> + let file, is_std = match ExtString.String.nsplit file "@" with + | [file] -> + file,false + | [file;"std"] -> + file,true + | _ -> failwith ("unsupported file@`std` format: " ^ file) + in + Gencs.add_net_lib com file is_std + | _ -> failwith "Unsupported platform"); + VNull + | _ -> + error() + ); + "add_native_arg", Fun1 (fun v -> + match v with + | VString arg -> + let com = ccom() in + (match com.platform with + | Java | Cs | Cpp -> + com.c_args <- arg :: com.c_args + | _ -> failwith "Unsupported platform"); + VNull + | _ -> + error() + ); + "module_dependency", Fun2 (fun m file -> + match m, file with + | VString m, VString file -> + (get_ctx()).curapi.module_dependency m file false; + VNull + | _ -> error() + ); + "module_reuse_call", Fun2 (fun m mcall -> + match m, mcall with + | VString m, VString mcall -> + (get_ctx()).curapi.module_dependency m mcall true; + VNull + | _ -> error() + ); + "get_typed_expr", Fun1 (fun e -> + let e = decode_texpr e in + encode_expr (make_ast e) + ); + "store_typed_expr", Fun1 (fun e -> + let e = try decode_texpr e with Invalid_expr -> error() in + encode_expr ((get_ctx()).curapi.store_typed_expr e) + ); + "get_output", Fun0 (fun() -> + VString (ccom()).file + ); + "set_output", Fun1 (fun s -> + match s with + | VString s -> (ccom()).file <- s; VNull + | _ -> error() + ); + "get_display_pos", Fun0 (fun() -> + let p = !Parser.resume_display in + if p = Ast.null_pos then + VNull + else + VObject (obj (hash_field (get_ctx())) ["file",VString p.Ast.pfile;"pos",VInt p.Ast.pmin]) + ); + "pattern_locals", Fun2 (fun e t -> + let loc = (get_ctx()).curapi.get_pattern_locals (decode_expr e) (decode_type t) in + let h = Hashtbl.create 0 in + PMap.iter (fun n (v,_) -> Hashtbl.replace h (VString n) (encode_type v.v_type)) loc; + enc_hash h + ); + "macro_context_reused", Fun1 (fun c -> + match c with + | VFunction (Fun0 _) -> + let ctx = get_ctx() in + ctx.on_reused <- (fun() -> catch_errors ctx (fun() -> ctx.do_call VNull c [] null_pos) = Some (VBool true)) :: ctx.on_reused; + VNull + | _ -> error() + ); + "apply_params", Fun3 (fun tpl tl t -> + let tpl = List.map (fun v -> + match v with + | VObject o -> + let name = match get_field o (hash "name") with VString s -> s | _ -> assert false in + let t = decode_type (get_field o (hash "t")) in + name,t + | _ -> assert false + ) (dec_array tpl) in + let tl = List.map decode_type (dec_array tl) in + let rec map t = match t with + | TInst({cl_kind = KTypeParameter _},_) -> + begin try + (* use non-physical equality check here to make apply_params work *) + snd (List.find (fun (_,t2) -> type_iseq t t2) tpl) + with Not_found -> + Type.map map t + end + | _ -> Type.map map t + in + encode_type (apply_params tpl tl (map (decode_type t))) + ); + ] + +(* ---------------------------------------------------------------------- *) +(* EVAL *) + +let throw ctx p msg = + ctx.callstack <- { cpos = p; cthis = ctx.vthis; cstack = DynArray.length ctx.stack; cenv = ctx.venv } :: ctx.callstack; + exc (VString msg) + +let declare ctx var = + ctx.locals_map <- PMap.add var ctx.locals_count ctx.locals_map; + ctx.locals_count <- ctx.locals_count + 1 + +let save_locals ctx = + let old, oldcount = ctx.locals_map, ctx.locals_count in + (fun() -> + let n = ctx.locals_count - oldcount in + ctx.locals_count <- oldcount; + ctx.locals_map <- old; + n; + ) + +let get_ident ctx s = + try + let index = PMap.find s ctx.locals_map in + if index >= ctx.locals_barrier then + AccLocal (ctx.locals_count - index) + else (try + AccEnv (DynArray.index_of (fun s2 -> s = s2) ctx.locals_env) + with Not_found -> + let index = DynArray.length ctx.locals_env in + DynArray.add ctx.locals_env s; + AccEnv index + ) + with Not_found -> try + AccGlobal (PMap.find s ctx.globals) + with Not_found -> + let g = ref VNull in + ctx.globals <- PMap.add s g ctx.globals; + AccGlobal g + +let no_env = [||] + +let rec eval ctx (e,p) = + match e with + | EConst c -> + (match c with + | True -> (fun() -> VBool true) + | False -> (fun() -> VBool false) + | Null -> (fun() -> VNull) + | This -> (fun() -> ctx.vthis) + | Int i -> (fun() -> VInt i) + | Int32 i -> (fun() -> VInt32 i) + | Float f -> + let f = float_of_string f in + (fun() -> VFloat f) + | String s -> (fun() -> VString s) + | Builtin "loader" -> + (fun() -> ctx.loader) + | Builtin "exports" -> + (fun() -> ctx.exports) + | Builtin s -> + let b = (try Hashtbl.find builtins s with Not_found -> throw ctx p ("Builtin not found '" ^ s ^ "'")) in + (fun() -> b) + | Ident s -> + acc_get ctx p (get_ident ctx s)) + | EBlock el -> + let old = save_locals ctx in + let el = List.map (eval ctx) el in + let n = old() in + let rec loop = function + | [] -> VNull + | [e] -> e() + | e :: l -> + ignore(e()); + loop l + in + (fun() -> + let v = loop el in + pop ctx n; + v) + | EParenthesis e -> + eval ctx e + | EField (e,f) -> + let e = eval ctx e in + let h = hash_field ctx f in + (fun() -> + match e() with + | VObject o -> get_field o h + | _ -> throw ctx p ("Invalid field access : " ^ f) + ) + | ECall ((EConst (Builtin "mk_pos"),_),[(ECall (_,[EConst (String file),_]),_);(EConst (Int min),_);(EConst (Int max),_)]) -> + let pos = VAbstract (APos { Ast.pfile = file; Ast.pmin = min; Ast.pmax = max }) in + (fun() -> pos) + | ECall ((EConst (Builtin "typewrap"),_),[t]) -> + (fun() -> VAbstract (ATDecl (Obj.magic t))) + | ECall ((EConst (Builtin "delay_call"),_),[EConst (Int index),_]) -> + let f = ctx.curapi.delayed_macro index in + let fbuild = ref None in + let old = { ctx with gen = ctx.gen } in + let compile_delayed_call() = + let oldl, oldc, oldb, olde = ctx.locals_map, ctx.locals_count, ctx.locals_barrier, ctx.locals_env in + ctx.locals_map <- old.locals_map; + ctx.locals_count <- old.locals_count; + ctx.locals_barrier <- old.locals_barrier; + ctx.locals_env <- DynArray.copy old.locals_env; + let save = save_locals ctx in + let e = f() in + let n = save() in + let e = if DynArray.length ctx.locals_env = DynArray.length old.locals_env then + e + else + let n = DynArray.get ctx.locals_env (DynArray.length ctx.locals_env - 1) in + (fun() -> exc (VString ("Macro-in-macro call can't access to closure variable '" ^ n ^ "'"))) + in + ctx.locals_map <- oldl; + ctx.locals_count <- oldc; + ctx.locals_barrier <- oldb; + ctx.locals_env <- olde; + (fun() -> + let v = e() in + pop ctx n; + v + ) + in + (fun() -> + let e = (match !fbuild with + | Some e -> e + | None -> + let e = compile_delayed_call() in + fbuild := Some e; + e + ) in + e()) + | ECall (e,el) -> + let el = List.map (eval ctx) el in + (match fst e with + | EField (e,f) -> + let e = eval ctx e in + let h = hash_field ctx f in + (fun() -> + let pl = List.map (fun f -> f()) el in + let o = e() in + let f = (match o with + | VObject o -> get_field o h + | _ -> throw ctx p ("Invalid field access : " ^ f) + ) in + call ctx o f pl p + ) + | _ -> + let e = eval ctx e in + (fun() -> + let pl = List.map (fun f -> f()) el in + call ctx ctx.vthis (e()) pl p + )) + | EArray (e1,e2) -> + let e1 = eval ctx e1 in + let e2 = eval ctx e2 in + let acc = AccArray (e1,e2) in + acc_get ctx p acc + | EVars vl -> + let vl = List.map (fun (v,eo) -> + let eo = (match eo with None -> (fun() -> VNull) | Some e -> eval ctx e) in + declare ctx v; + eo + ) vl in + (fun() -> + List.iter (fun e -> push ctx (e())) vl; + VNull + ) + | EWhile (econd,e,NormalWhile) -> + let econd = eval ctx econd in + let e = eval ctx e in + let rec loop st = + match econd() with + | VBool true -> + let v = (try + ignore(e()); None + with + | Continue -> pop ctx (DynArray.length ctx.stack - st); None + | Break v -> pop ctx (DynArray.length ctx.stack - st); Some v + ) in + (match v with + | None -> loop st + | Some v -> v) + | _ -> + VNull + in + (fun() -> try loop (DynArray.length ctx.stack) with Sys.Break -> throw ctx p "Ctrl+C") + | EWhile (econd,e,DoWhile) -> + let e = eval ctx e in + let econd = eval ctx econd in + let rec loop st = + let v = (try + ignore(e()); None + with + | Continue -> pop ctx (DynArray.length ctx.stack - st); None + | Break v -> pop ctx (DynArray.length ctx.stack - st); Some v + ) in + match v with + | Some v -> v + | None -> + match econd() with + | VBool true -> loop st + | _ -> VNull + in + (fun() -> loop (DynArray.length ctx.stack)) + | EIf (econd,eif,eelse) -> + let econd = eval ctx econd in + let eif = eval ctx eif in + let eelse = (match eelse with None -> (fun() -> VNull) | Some e -> eval ctx e) in + (fun() -> + match econd() with + | VBool true -> eif() + | _ -> eelse() + ) + | ETry (e,exc,ecatch) -> + let old = save_locals ctx in + let e = eval ctx e in + let n1 = old() in + declare ctx exc; + let ecatch = eval ctx ecatch in + let n2 = old() in + (fun() -> + let vthis = ctx.vthis in + let venv = ctx.venv in + let stack = ctx.callstack in + let csize = ctx.callsize in + let size = DynArray.length ctx.stack in + try + pop_ret ctx e n1 + with Runtime v -> + let rec loop n l = + if n = 0 then List.map (fun s -> s.cpos) l else + match l with + | [] -> [] + | _ :: l -> loop (n - 1) l + in + ctx.exc <- loop (List.length stack) (List.rev ctx.callstack); + ctx.callstack <- stack; + ctx.callsize <- csize; + ctx.vthis <- vthis; + ctx.venv <- venv; + pop ctx (DynArray.length ctx.stack - size); + push ctx v; + pop_ret ctx ecatch n2 + ) + | EFunction (pl,e) -> + let old = save_locals ctx in + let oldb, oldenv = ctx.locals_barrier, ctx.locals_env in + ctx.locals_barrier <- ctx.locals_count; + ctx.locals_env <- DynArray.create(); + List.iter (declare ctx) pl; + let e = eval ctx e in + ignore(old()); + let env = ctx.locals_env in + ctx.locals_barrier <- oldb; + ctx.locals_env <- oldenv; + let env = DynArray.to_array (DynArray.map (fun s -> + acc_get ctx p (get_ident ctx s)) env + ) in + let init_env = if Array.length env = 0 then + (fun() -> no_env) + else + (fun() -> Array.map (fun e -> e()) env) + in + (match pl with + | [] -> + (fun() -> + let env = init_env() in + VFunction (Fun0 (fun() -> + ctx.venv <- env; + e()))) + | [a] -> + (fun() -> + let env = init_env() in + VFunction (Fun1 (fun v -> + ctx.venv <- env; + push ctx v; + e(); + ))) + | [a;b] -> + (fun() -> + let env = init_env() in + VFunction (Fun2 (fun va vb -> + ctx.venv <- env; + push ctx va; + push ctx vb; + e(); + ))) + | [a;b;c] -> + (fun() -> + let env = init_env() in + VFunction (Fun3 (fun va vb vc -> + ctx.venv <- env; + push ctx va; + push ctx vb; + push ctx vc; + e(); + ))) + | [a;b;c;d] -> + (fun() -> + let env = init_env() in + VFunction (Fun4 (fun va vb vc vd -> + ctx.venv <- env; + push ctx va; + push ctx vb; + push ctx vc; + push ctx vd; + e(); + ))) + | [a;b;c;d;pe] -> + (fun() -> + let env = init_env() in + VFunction (Fun5 (fun va vb vc vd ve -> + ctx.venv <- env; + push ctx va; + push ctx vb; + push ctx vc; + push ctx vd; + push ctx ve; + e(); + ))) + | _ -> + (fun() -> + let env = init_env() in + VFunction (FunVar (fun vl -> + if List.length vl != List.length pl then exc (VString "Invalid call"); + ctx.venv <- env; + List.iter (push ctx) vl; + e(); + ))) + ) + | EBinop (op,e1,e2) -> + eval_op ctx op e1 e2 p + | EReturn None -> + (fun() -> raise (Return VNull)) + | EReturn (Some e) -> + let e = eval ctx e in + (fun() -> raise (Return (e()))) + | EBreak None -> + (fun() -> raise (Break VNull)) + | EBreak (Some e) -> + let e = eval ctx e in + (fun() -> raise (Break (e()))) + | EContinue -> + (fun() -> raise Continue) + | ENext (e1,e2) -> + let e1 = eval ctx e1 in + let e2 = eval ctx e2 in + (fun() -> ignore(e1()); e2()) + | EObject fl -> + let fl = List.map (fun (f,e) -> hash_field ctx f, eval ctx e) fl in + let fields = Array.of_list (List.map (fun (f,_) -> f,VNull) fl) in + Array.sort (fun (f1,_) (f2,_) -> compare f1 f2) fields; + (fun() -> + let o = { + ofields = Array.copy fields; + oproto = None; + } in + List.iter (fun (f,e) -> set_field o f (e())) fl; + VObject o + ) + | ELabel l -> + assert false + | ESwitch (e1,el,eo) -> + let e1 = eval ctx e1 in + let el = List.map (fun (cond,e) -> cond, eval ctx cond, eval ctx e) el in + let eo = (match eo with None -> (fun() -> VNull) | Some e -> eval ctx e) in + let cases = (try + let max = ref (-1) in + let ints = List.map (fun (cond,_,e) -> + match fst cond with + | EConst (Int i) -> if i < 0 then raise Exit; if i > !max then max := i; i, e + | _ -> raise Exit + ) el in + let a = Array.create (!max + 1) eo in + List.iter (fun (i,e) -> a.(i) <- e) (List.rev ints); + Some a; + with + Exit -> None + ) in + let def v = + let rec loop = function + | [] -> eo() + | (_,c,e) :: l -> + if ctx.do_compare v (c()) = CEq then e() else loop l + in + loop el + in + (match cases with + | None -> (fun() -> def (e1())) + | Some t -> + (fun() -> + match e1() with + | VInt i -> if i >= 0 && i < Array.length t then t.(i)() else eo() + | v -> def v + )) + | ENeko _ -> + throw ctx p "Inline neko code unsupported" + +and eval_oop ctx p o field (params:value list) = + match get_field_opt o field with + | None -> None + | Some f -> Some (call ctx (VObject o) f params p) + +and eval_access ctx (e,p) = + match e with + | EField (e,f) -> + let v = eval ctx e in + AccField (v,f) + | EArray (e,eindex) -> + let v = eval ctx e in + let idx = eval ctx eindex in + AccArray (v,idx) + | EConst (Ident s) -> + get_ident ctx s + | EConst This -> + AccThis + | _ -> + throw ctx p "Invalid assign" + +and eval_access_get_set ctx (e,p) = + match e with + | EField (e,f) -> + let v = eval ctx e in + let cache = ref VNull in + AccField ((fun() -> cache := v(); !cache),f), AccField((fun() -> !cache), f) + | EArray (e,eindex) -> + let v = eval ctx e in + let idx = eval ctx eindex in + let vcache = ref VNull and icache = ref VNull in + AccArray ((fun() -> vcache := v(); !vcache),(fun() -> icache := idx(); !icache)), AccArray ((fun() -> !vcache),(fun() -> !icache)) + | EConst (Ident s) -> + let acc = get_ident ctx s in + acc, acc + | EConst This -> + AccThis, AccThis + | _ -> + throw ctx p "Invalid assign" + +and acc_get ctx p = function + | AccField (v,f) -> + let h = hash_field ctx f in + (fun() -> + match v() with + | VObject o -> get_field o h + | _ -> throw ctx p ("Invalid field access : " ^ f)) + | AccArray (e,index) -> + (fun() -> + let e = e() in + let index = index() in + (match index, e with + | VInt i, VArray a -> (try Array.get a i with _ -> VNull) + | VInt32 _, VArray _ -> VNull + | _, VObject o -> + (match eval_oop ctx p o h_get [index] with + | None -> throw ctx p "Invalid array access" + | Some v -> v) + | _ -> throw ctx p "Invalid array access")) + | AccLocal i -> + (fun() -> DynArray.get ctx.stack (DynArray.length ctx.stack - i)) + | AccGlobal g -> + (fun() -> !g) + | AccThis -> + (fun() -> ctx.vthis) + | AccEnv i -> + (fun() -> ctx.venv.(i)) + +and acc_set ctx p acc value = + match acc with + | AccField (v,f) -> + let h = hash_field ctx f in + (fun() -> + let v = v() in + let value = value() in + match v with + | VObject o -> set_field o h value; value + | _ -> throw ctx p ("Invalid field access : " ^ f)) + | AccArray (e,index) -> + (fun() -> + let e = e() in + let index = index() in + let value = value() in + (match index, e with + | VInt i, VArray a -> (try Array.set a i value; value with _ -> value) + | VInt32 _, VArray _ -> value + | _, VObject o -> + (match eval_oop ctx p o h_set [index;value] with + | None -> throw ctx p "Invalid array access" + | Some _ -> value); + | _ -> throw ctx p "Invalid array access")) + | AccLocal i -> + (fun() -> + let value = value() in + DynArray.set ctx.stack (DynArray.length ctx.stack - i) value; + value) + | AccGlobal g -> + (fun() -> + let value = value() in + g := value; + value) + | AccThis -> + (fun() -> + let value = value() in + ctx.vthis <- value; + value) + | AccEnv i -> + (fun() -> + let value = value() in + ctx.venv.(i) <- value; + value) + +and number_op ctx p sop iop fop oop rop v1 v2 = + (fun() -> + let v1 = v1() in + let v2 = v2() in + exc_number_op ctx p sop iop fop oop rop v1 v2) + +and exc_number_op ctx p sop iop fop oop rop v1 v2 = + match v1, v2 with + | VInt a, VInt b -> best_int (iop (Int32.of_int a) (Int32.of_int b)) + | VInt32 a, VInt b -> best_int (iop a (Int32.of_int b)) + | VInt a, VInt32 b -> best_int (iop (Int32.of_int a) b) + | VFloat a, VInt b -> VFloat (fop a (float_of_int b)) + | VFloat a, VInt32 b -> VFloat (fop a (Int32.to_float b)) + | VInt a, VFloat b -> VFloat (fop (float_of_int a) b) + | VInt32 a, VFloat b -> VFloat (fop (Int32.to_float a) b) + | VFloat a, VFloat b -> VFloat (fop a b) + | VInt32 a, VInt32 b -> best_int (iop a b) + | VObject o, _ -> + (match eval_oop ctx p o oop [v2] with + | Some v -> v + | None -> + match v2 with + | VObject o -> + (match eval_oop ctx p o rop [v1] with + | Some v -> v + | None -> throw ctx p sop) + | _ -> + throw ctx p sop) + | _ , VObject o -> + (match eval_oop ctx p o rop [v1] with + | Some v -> v + | None -> throw ctx p sop) + | _ -> + throw ctx p sop + +and int_op ctx p op iop v1 v2 = + (fun() -> + let v1 = v1() in + let v2 = v2() in + match v1, v2 with + | VInt a, VInt b -> best_int (iop (Int32.of_int a) (Int32.of_int b)) + | VInt32 a, VInt b -> best_int (iop a (Int32.of_int b)) + | VInt a, VInt32 b -> best_int (iop (Int32.of_int a) b) + | VInt32 a, VInt32 b -> best_int (iop a b) + | _ -> throw ctx p op) + +and base_op ctx op v1 v2 p = + match op with + | "+" -> + (fun() -> + let v1 = v1() in + let v2 = v2() in + match v1, v2 with + | (VInt _ | VInt32 _), (VInt _ | VInt32 _) | (VInt _ | VInt32 _), VFloat _ | VFloat _ , (VInt _ | VInt32 _) | VFloat _ , VFloat _ | VObject _ , _ | _ , VObject _ -> exc_number_op ctx p op Int32.add (+.) h_add h_radd v1 v2 + | VString a, _ -> VString (a ^ ctx.do_string v2) + | _, VString b -> VString (ctx.do_string v1 ^ b) + | _ -> throw ctx p op) + | "-" -> + number_op ctx p op Int32.sub (-.) h_sub h_rsub v1 v2 + | "*" -> + number_op ctx p op Int32.mul ( *. ) h_mult h_rmult v1 v2 + | "/" -> + (fun() -> + let v1 = v1() in + let v2 = v2() in + match v1, v2 with + | VInt i, VInt j -> VFloat ((float_of_int i) /. (float_of_int j)) + | VInt i, VInt32 j -> VFloat ((float_of_int i) /. (Int32.to_float j)) + | VInt32 i, VInt j -> VFloat ((Int32.to_float i) /. (float_of_int j)) + | VInt32 i, VInt32 j -> VFloat ((Int32.to_float i) /. (Int32.to_float j)) + | _ -> exc_number_op ctx p op Int32.div (/.) h_div h_rdiv v1 v2) + | "%" -> + number_op ctx p op (fun x y -> if y = 0l then throw ctx p op; Int32.rem x y) mod_float h_mod h_rmod v1 v2 + | "&" -> + int_op ctx p op Int32.logand v1 v2 + | "|" -> + int_op ctx p op Int32.logor v1 v2 + | "^" -> + int_op ctx p op Int32.logxor v1 v2 + | "<<" -> + int_op ctx p op (fun x y -> Int32.shift_left x (Int32.to_int y)) v1 v2 + | ">>" -> + int_op ctx p op (fun x y -> Int32.shift_right x (Int32.to_int y)) v1 v2 + | ">>>" -> + int_op ctx p op (fun x y -> Int32.shift_right_logical x (Int32.to_int y)) v1 v2 + | _ -> + throw ctx p op + +and eval_op ctx op e1 e2 p = + match op with + | "=" -> + let acc = eval_access ctx e1 in + let v = eval ctx e2 in + acc_set ctx p acc v + | "==" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CEq -> VBool true + | _ -> VBool false) + | "!=" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CEq -> VBool false + | _ -> VBool true) + | ">" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CSup -> VBool true + | _ -> VBool false) + | ">=" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CSup | CEq -> VBool true + | _ -> VBool false) + | "<" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CInf -> VBool true + | _ -> VBool false) + | "<=" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + (fun() -> + let v1 = v1() in + let v2 = v2() in + match ctx.do_compare v1 v2 with + | CInf | CEq -> VBool true + | _ -> VBool false) + | "+" | "-" | "*" | "/" | "%" | "|" | "&" | "^" | "<<" | ">>" | ">>>" -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + base_op ctx op v1 v2 p + | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | ">>>=" | "|=" | "&=" | "^=" -> + let aset, aget = eval_access_get_set ctx e1 in + let v1 = acc_get ctx p aget in + let v2 = eval ctx e2 in + let v = base_op ctx (String.sub op 0 (String.length op - 1)) v1 v2 p in + acc_set ctx p aset v + | "&&" -> + let e1 = eval ctx e1 in + let e2 = eval ctx e2 in + (fun() -> + match e1() with + | VBool false as v -> v + | _ -> e2()) + | "||" -> + let e1 = eval ctx e1 in + let e2 = eval ctx e2 in + (fun() -> + match e1() with + | VBool true as v -> v + | _ -> e2()) + | "++=" | "--=" -> + let aset, aget = eval_access_get_set ctx e1 in + let v1 = acc_get ctx p aget in + let v2 = eval ctx e2 in + let vcache = ref VNull in + let v = base_op ctx (String.sub op 0 1) (fun() -> vcache := v1(); !vcache) v2 p in + let set = acc_set ctx p aset v in + (fun() -> ignore(set()); !vcache) + | _ -> + throw ctx p ("Unsupported " ^ op) + +and call ctx vthis vfun pl p = + let oldthis = ctx.vthis in + let stackpos = DynArray.length ctx.stack in + let oldstack = ctx.callstack in + let oldsize = ctx.callsize in + let oldenv = ctx.venv in + ctx.vthis <- vthis; + ctx.callstack <- { cpos = p; cthis = oldthis; cstack = stackpos; cenv = oldenv } :: ctx.callstack; + ctx.callsize <- oldsize + 1; + if oldsize > 600 then exc (VString "Stack overflow"); + let ret = (try + (match vfun with + | VClosure (vl,f) -> + f vl pl + | VFunction f -> + (match pl, f with + | [], Fun0 f -> f() + | [a], Fun1 f -> f a + | [a;b], Fun2 f -> f a b + | [a;b;c], Fun3 f -> f a b c + | [a;b;c;d], Fun4 f -> f a b c d + | [a;b;c;d;e], Fun5 f -> f a b c d e + | _, FunVar f -> f pl + | _ -> exc (VString (Printf.sprintf "Invalid call (%d args instead of %d)" (List.length pl) (nargs f)))) + | VAbstract (ALazyType f) -> + encode_type ((!f)()) + | _ -> + exc (VString "Invalid call")) + with Return v -> v + | Stack_overflow -> exc (VString "Compiler Stack overflow") + | Sys_error msg | Failure msg -> exc (VString msg) + | Unix.Unix_error (_,cmd,msg) -> exc (VString ("Error " ^ cmd ^ " " ^ msg)) + (* | Invalid_expr -> exc (VString "Invalid input value") *) + | Builtin_error | Invalid_argument _ -> exc (VString "Invalid call")) in + ctx.vthis <- oldthis; + ctx.venv <- oldenv; + ctx.callstack <- oldstack; + ctx.callsize <- oldsize; + pop ctx (DynArray.length ctx.stack - stackpos); + ret + +(* ---------------------------------------------------------------------- *) +(* OTHERS *) + +let rec to_string ctx n v = + if n > 5 then + "<...>" + else let n = n + 1 in + match v with + | VNull -> "null" + | VBool true -> "true" + | VBool false -> "false" + | VInt i -> string_of_int i + | VInt32 i -> Int32.to_string i + | VFloat f -> + let s = float_repres f in + let len = String.length s in + if String.unsafe_get s (len - 1) = '.' then String.sub s 0 (len - 1) else s + | VString s -> s + | VArray vl -> "[" ^ String.concat "," (Array.to_list (Array.map (to_string ctx n) vl)) ^ "]" + | VAbstract a -> + (match a with + | APos p -> "#pos(" ^ Lexer.get_error_pos (Printf.sprintf "%s:%d:") p ^ ")" + | _ -> "#abstract") + | VFunction f -> "#function:" ^ string_of_int (nargs f) + | VClosure _ -> "#function:-1" + | VObject o -> + match eval_oop ctx null_pos o h_string [] with + | Some (VString s) -> s + | _ -> + let b = Buffer.create 0 in + let first = ref true in + Buffer.add_char b '{'; + Array.iter (fun (f,v) -> + if !first then begin + Buffer.add_char b ' '; + first := false; + end else + Buffer.add_string b ", "; + Buffer.add_string b (field_name ctx f); + Buffer.add_string b " => "; + Buffer.add_string b (to_string ctx n v); + ) o.ofields; + Buffer.add_string b (if !first then "}" else " }"); + Buffer.contents b + +let rec compare ctx a b = + let fcmp (a:float) b = if a = b then CEq else if a < b then CInf else CSup in + let scmp (a:string) b = if a = b then CEq else if a < b then CInf else CSup in + let icmp (a:int32) b = let l = Int32.compare a b in if l = 0 then CEq else if l < 0 then CInf else CSup in + match a, b with + | VNull, VNull -> CEq + | VInt a, VInt b -> if a = b then CEq else if a < b then CInf else CSup + | VInt32 a, VInt32 b -> icmp a b + | VInt a, VInt32 b -> icmp (Int32.of_int a) b + | VInt32 a, VInt b -> icmp a (Int32.of_int b) + | VFloat a, VFloat b -> fcmp a b + | VFloat a, VInt b -> fcmp a (float_of_int b) + | VFloat a, VInt32 b -> fcmp a (Int32.to_float b) + | VInt a, VFloat b -> fcmp (float_of_int a) b + | VInt32 a, VFloat b -> fcmp (Int32.to_float a) b + | VBool a, VBool b -> if a = b then CEq else if a then CSup else CInf + | VString a, VString b -> scmp a b + | VInt _ , VString s + | VInt32 _, VString s + | VFloat _ , VString s + | VBool _ , VString s -> scmp (to_string ctx 0 a) s + | VString s, VInt _ + | VString s, VInt32 _ + | VString s, VFloat _ + | VString s, VBool _ -> scmp s (to_string ctx 0 b) + | VObject oa, VObject ob -> + if oa == ob then CEq else + (match eval_oop ctx null_pos oa h_compare [b] with + | Some (VInt i) -> if i = 0 then CEq else if i < 0 then CInf else CSup + | _ -> CUndef) + | VAbstract a, VAbstract b -> + if a == b then CEq else CUndef + | VArray a, VArray b -> + if a == b then CEq else CUndef + | VFunction a, VFunction b -> + if a == b then CEq else CUndef + | VClosure (la,fa), VClosure (lb,fb) -> + if la == lb && fa == fb then CEq else CUndef + | _ -> + CUndef + +let select ctx = + get_ctx_ref := (fun() -> ctx) + +let load_prim ctx f n = + match f, n with + | VString f, VInt n -> + let lib, fname = (try ExtString.String.split f "@" with _ -> "", f) in + (try + let f = (match lib with + | "std" -> Hashtbl.find std_lib fname + | "macro" -> Hashtbl.find macro_lib fname + | "regexp" -> Hashtbl.find reg_lib fname + | "zlib" -> Hashtbl.find z_lib fname + | _ -> failwith ("You cannot use the library '" ^ lib ^ "' inside a macro"); + ) in + if nargs f <> n then raise Not_found; + VFunction f + with Not_found -> + VFunction (FunVar (fun _ -> exc (VString ("Primitive not found " ^ f ^ ":" ^ string_of_int n))))) + | _ -> + exc (VString "Invalid call") + +let create com api = + let loader = obj hash [ + "args",VArray (Array.of_list (List.map (fun s -> VString s) com.sys_args)); + "loadprim",VFunction (Fun2 (fun a b -> (get_ctx()).do_loadprim a b)); + "loadmodule",VFunction (Fun2 (fun a b -> assert false)); + ] in + let ctx = { + gen = Genneko.new_context com 2 true; + types = Hashtbl.create 0; + error = false; + error_proto = { ofields = [||]; oproto = None }; + prototypes = Hashtbl.create 0; + enums = [||]; + (* eval *) + locals_map = PMap.empty; + locals_count = 0; + locals_barrier = 0; + locals_env = DynArray.create(); + globals = PMap.empty; + (* runtime *) + callstack = []; + callsize = 0; + stack = DynArray.create(); + exc = []; + vthis = VNull; + venv = [||]; + fields_cache = Hashtbl.copy constants; + (* api *) + do_call = Obj.magic(); + do_string = Obj.magic(); + do_loadprim = Obj.magic(); + do_compare = Obj.magic(); + (* context *) + curapi = api; + loader = VObject loader; + on_reused = []; + is_reused = true; + exports = VObject { ofields = [||]; oproto = None }; + } in + ctx.do_call <- call ctx; + ctx.do_string <- to_string ctx 0; + ctx.do_loadprim <- load_prim ctx; + ctx.do_compare <- compare ctx; + select ctx; + List.iter (fun e -> ignore((eval ctx e)())) (Genneko.header()); + ctx + + + +let do_reuse ctx api = + ctx.is_reused <- false; + ctx.curapi <- api + +let can_reuse ctx types = + let has_old_version t = + let inf = Type.t_infos t in + try + Hashtbl.find ctx.types inf.mt_path <> inf.mt_module.m_id + with Not_found -> + false + in + if List.exists has_old_version types then + false + else if ctx.is_reused then + true + else if not (List.for_all (fun f -> f()) ctx.on_reused) then + false + else begin + ctx.is_reused <- true; + true; + end + +let add_types ctx types ready = + let types = List.filter (fun t -> + let path = Type.t_path t in + if Hashtbl.mem ctx.types path then false else begin + Hashtbl.add ctx.types path (Type.t_infos t).mt_module.m_id; + true; + end + ) types in + List.iter ready types; + let e = (EBlock (Genneko.build ctx.gen types), null_pos) in + ignore(catch_errors ctx (fun() -> ignore((eval ctx e)()))) + +let eval_expr ctx e = + let e = Genneko.gen_expr ctx.gen e in + catch_errors ctx (fun() -> (eval ctx e)()) + +let get_path ctx path p = + let rec loop = function + | [] -> assert false + | [x] -> (EConst (Ident x),p) + | x :: l -> (EField (loop l,x),p) + in + (eval ctx (loop (List.rev path)))() + +let set_error ctx e = + ctx.error <- e + +let call_path ctx path f vl api = + if ctx.error then + None + else let old = ctx.curapi in + ctx.curapi <- api; + let p = Genneko.pos ctx.gen api.pos in + catch_errors ctx ~final:(fun() -> ctx.curapi <- old) (fun() -> + match get_path ctx path p with + | VObject o -> + let f = get_field o (hash f) in + call ctx (VObject o) f vl p + | _ -> assert false + ) + +(* ---------------------------------------------------------------------- *) +(* EXPR ENCODING *) + +type enum_index = + | IExpr + | IBinop + | IUnop + | IConst + | ITParam + | ICType + | IField + | IType + | IFieldKind + | IMethodKind + | IVarAccess + | IAccess + | IClassKind + | ITypedExpr + | ITConstant + | IModuleType + | IFieldAccess + | IAnonStatus + +let enum_name = function + | IExpr -> "ExprDef" + | IBinop -> "Binop" + | IUnop -> "Unop" + | IConst -> "Constant" + | ITParam -> "TypeParam" + | ICType -> "ComplexType" + | IField -> "FieldType" + | IType -> "Type" + | IFieldKind -> "FieldKind" + | IMethodKind -> "MethodKind" + | IVarAccess -> "VarAccess" + | IAccess -> "Access" + | IClassKind -> "ClassKind" + | ITypedExpr -> "TypedExprDef" + | ITConstant -> "TConstant" + | IModuleType -> "ModuleType" + | IFieldAccess -> "FieldAccess" + | IAnonStatus -> "AnonStatus" + +let init ctx = + let enums = [IExpr;IBinop;IUnop;IConst;ITParam;ICType;IField;IType;IFieldKind;IMethodKind;IVarAccess;IAccess;IClassKind;ITypedExpr;ITConstant;IModuleType;IFieldAccess;IAnonStatus] in + let get_enum_proto e = + match get_path ctx ["haxe";"macro";enum_name e] null_pos with + | VObject e -> + (match get_field e h_constructs with + | VObject cst -> + (match get_field cst h_a with + | VArray a -> + Array.map (fun s -> + match s with + | VObject s -> (match get_field s h_s with VString s -> get_field e (hash s),s | _ -> assert false) + | _ -> assert false + ) a + | _ -> assert false) + | _ -> assert false) + | _ -> failwith ("haxe.macro." ^ enum_name e ^ " does not exists") + in + ctx.enums <- Array.of_list (List.map get_enum_proto enums); + ctx.error_proto <- (match get_path ctx ["haxe";"macro";"Error";"prototype"] null_pos with VObject p -> p | _ -> failwith ("haxe.macro.Error does not exists")) + +open Ast + +let null f = function + | None -> VNull + | Some v -> f v + +let encode_pos p = + VAbstract (APos p) + +let enc_inst path fields = + let ctx = get_ctx() in + let p = (try Hashtbl.find ctx.prototypes path with Not_found -> try + (match get_path ctx (path@["prototype"]) Nast.null_pos with + | VObject o -> Hashtbl.add ctx.prototypes path o; o + | _ -> raise (Runtime VNull)) + with Runtime _ -> + failwith ("Prototype not found " ^ String.concat "." path) + ) in + let o = obj hash fields in + o.oproto <- Some p; + VObject o + +let enc_array l = + let a = Array.of_list l in + enc_inst ["Array"] [ + "__a", VArray a; + "length", VInt (Array.length a); + ] + +let enc_string s = + enc_inst ["String"] [ + "__s", VString s; + "length", VInt (String.length s) + ] + +let enc_hash h = + enc_inst ["haxe";"ds";"StringMap"] [ + "h", VAbstract (AHash h); + ] + +let enc_obj l = VObject (obj hash l) + +let enc_enum (i:enum_index) index pl = + let eindex : int = Obj.magic i in + let edef = (get_ctx()).enums.(eindex) in + if pl = [] then + fst edef.(index) + else + enc_inst ["haxe";"macro";enum_name i] [ + "tag", VString (snd edef.(index)); + "index", VInt index; + "args", VArray (Array.of_list pl); + ] + +let compiler_error msg pos = + exc (enc_inst ["haxe";"macro";"Error"] [("message",enc_string msg);("pos",encode_pos pos)]) + +let encode_const c = + let tag, pl = match c with + | Int s -> 0, [enc_string s] + | Float s -> 1, [enc_string s] + | String s -> 2, [enc_string s] + | Ident s -> 3, [enc_string s] + | Regexp (s,opt) -> 4, [enc_string s;enc_string opt] + in + enc_enum IConst tag pl + +let rec encode_binop op = + let tag, pl = match op with + | OpAdd -> 0, [] + | OpMult -> 1, [] + | OpDiv -> 2, [] + | OpSub -> 3, [] + | OpAssign -> 4, [] + | OpEq -> 5, [] + | OpNotEq -> 6, [] + | OpGt -> 7, [] + | OpGte -> 8, [] + | OpLt -> 9, [] + | OpLte -> 10, [] + | OpAnd -> 11, [] + | OpOr -> 12, [] + | OpXor -> 13, [] + | OpBoolAnd -> 14, [] + | OpBoolOr -> 15, [] + | OpShl -> 16, [] + | OpShr -> 17, [] + | OpUShr -> 18, [] + | OpMod -> 19, [] + | OpAssignOp op -> 20, [encode_binop op] + | OpInterval -> 21, [] + | OpArrow -> 22, [] + in + enc_enum IBinop tag pl + +let encode_unop op = + let tag = match op with + | Increment -> 0 + | Decrement -> 1 + | Not -> 2 + | Neg -> 3 + | NegBits -> 4 + in + enc_enum IUnop tag [] + +let rec encode_path t = + let fields = [ + "pack", enc_array (List.map enc_string t.tpackage); + "name", enc_string t.tname; + "params", enc_array (List.map encode_tparam t.tparams); + ] in + enc_obj (match t.tsub with + | None -> fields + | Some s -> ("sub", enc_string s) :: fields) + +and encode_tparam = function + | TPType t -> enc_enum ITParam 0 [encode_ctype t] + | TPExpr e -> enc_enum ITParam 1 [encode_expr e] + +and encode_access a = + let tag = match a with + | APublic -> 0 + | APrivate -> 1 + | AStatic -> 2 + | AOverride -> 3 + | ADynamic -> 4 + | AInline -> 5 + | AMacro -> 6 + in + enc_enum IAccess tag [] + +and encode_meta_entry (m,ml,p) = + enc_obj [ + "name", enc_string (fst (MetaInfo.to_string m)); + "params", enc_array (List.map encode_expr ml); + "pos", encode_pos p; + ] + +and encode_meta_content m = + enc_array (List.map encode_meta_entry m) + +and encode_field (f:class_field) = + let tag, pl = match f.cff_kind with + | FVar (t,e) -> 0, [null encode_ctype t; null encode_expr e] + | FFun f -> 1, [encode_fun f] + | FProp (get,set, t, e) -> 2, [enc_string get; enc_string set; null encode_ctype t; null encode_expr e] + in + enc_obj [ + "name",enc_string f.cff_name; + "doc", null enc_string f.cff_doc; + "pos", encode_pos f.cff_pos; + "kind", enc_enum IField tag pl; + "meta", encode_meta_content f.cff_meta; + "access", enc_array (List.map encode_access f.cff_access); + ] + +and encode_ctype t = + let tag, pl = match t with + | CTPath p -> + 0, [encode_path p] + | CTFunction (pl,r) -> + 1, [enc_array (List.map encode_ctype pl);encode_ctype r] + | CTAnonymous fl -> + 2, [enc_array (List.map encode_field fl)] + | CTParent t -> + 3, [encode_ctype t] + | CTExtend (tl,fields) -> + 4, [enc_array (List.map encode_path tl); enc_array (List.map encode_field fields)] + | CTOptional t -> + 5, [encode_ctype t] + in + enc_enum ICType tag pl + +and encode_tparam_decl tp = + enc_obj [ + "name", enc_string tp.tp_name; + "params", enc_array (List.map encode_tparam_decl tp.tp_params); + "constraints", enc_array (List.map encode_ctype tp.tp_constraints); + ] + +and encode_fun f = + enc_obj [ + "params", enc_array (List.map encode_tparam_decl f.f_params); + "args", enc_array (List.map (fun (n,opt,t,e) -> + enc_obj [ + "name", enc_string n; + "opt", VBool opt; + "type", null encode_ctype t; + "value", null encode_expr e; + ] + ) f.f_args); + "ret", null encode_ctype f.f_type; + "expr", null encode_expr f.f_expr + ] + +and encode_expr e = + let rec loop (e,p) = + let tag, pl = match e with + | EConst c -> + 0, [encode_const c] + | EArray (e1,e2) -> + 1, [loop e1;loop e2] + | EBinop (op,e1,e2) -> + 2, [encode_binop op;loop e1;loop e2] + | EField (e,f) -> + 3, [loop e;enc_string f] + | EParenthesis e -> + 4, [loop e] + | EObjectDecl fl -> + 5, [enc_array (List.map (fun (f,e) -> enc_obj [ + "field",enc_string f; + "expr",loop e; + ]) fl)] + | EArrayDecl el -> + 6, [enc_array (List.map loop el)] + | ECall (e,el) -> + 7, [loop e;enc_array (List.map loop el)] + | ENew (p,el) -> + 8, [encode_path p; enc_array (List.map loop el)] + | EUnop (op,flag,e) -> + 9, [encode_unop op; VBool (match flag with Prefix -> false | Postfix -> true); loop e] + | EVars vl -> + 10, [enc_array (List.map (fun (v,t,eo) -> + enc_obj [ + "name",enc_string v; + "type",null encode_ctype t; + "expr",null loop eo; + ] + ) vl)] + | EFunction (name,f) -> + 11, [null enc_string name; encode_fun f] + | EBlock el -> + 12, [enc_array (List.map loop el)] + | EFor (e,eloop) -> + 13, [loop e;loop eloop] + | EIn (e1,e2) -> + 14, [loop e1;loop e2] + | EIf (econd,e,eelse) -> + 15, [loop econd;loop e;null loop eelse] + | EWhile (econd,e,flag) -> + 16, [loop econd;loop e;VBool (match flag with NormalWhile -> true | DoWhile -> false)] + | ESwitch (e,cases,eopt) -> + 17, [loop e;enc_array (List.map (fun (ecl,eg,e) -> + enc_obj [ + "values",enc_array (List.map loop ecl); + "guard",null loop eg; + "expr",null loop e + ] + ) cases);null encode_null_expr eopt] + | ETry (e,catches) -> + 18, [loop e;enc_array (List.map (fun (v,t,e) -> + enc_obj [ + "name",enc_string v; + "type",encode_ctype t; + "expr",loop e + ] + ) catches)] + | EReturn eo -> + 19, [null loop eo] + | EBreak -> + 20, [] + | EContinue -> + 21, [] + | EUntyped e -> + 22, [loop e] + | EThrow e -> + 23, [loop e] + | ECast (e,t) -> + 24, [loop e; null encode_ctype t] + | EDisplay (e,flag) -> + 25, [loop e; VBool flag] + | EDisplayNew t -> + 26, [encode_path t] + | ETernary (econd,e1,e2) -> + 27, [loop econd;loop e1;loop e2] + | ECheckType (e,t) -> + 28, [loop e; encode_ctype t] + | EMeta (m,e) -> + 29, [encode_meta_entry m;loop e] + in + enc_obj [ + "pos", encode_pos p; + "expr", enc_enum IExpr tag pl; + ] + in + loop e + +and encode_null_expr e = + match e with + | None -> + enc_obj ["pos", VNull;"expr",VNull] + | Some e -> + encode_expr e + +(* ---------------------------------------------------------------------- *) +(* EXPR DECODING *) + +let opt f v = + match v with + | VNull -> None + | _ -> Some (f v) + +let opt_list f v = + match v with + | VNull -> [] + | _ -> f v + +let decode_pos = function + | VAbstract (APos p) -> p + | _ -> raise Invalid_expr + +let field v f = + match v with + | VObject o -> get_field o (hash f) + | _ -> raise Invalid_expr + +let decode_enum v = + match field v "index", field v "args" with + | VInt i, VNull -> i, [] + | VInt i, VArray a -> i, Array.to_list a + | _ -> raise Invalid_expr + +let dec_bool = function + | VBool b -> b + | _ -> raise Invalid_expr + +let dec_string v = + match field v "__s" with + | VString s -> s + | _ -> raise Invalid_expr + +let dec_array v = + match field v "__a", field v "length" with + | VArray a, VInt l -> Array.to_list (if Array.length a = l then a else Array.sub a 0 l) + | _ -> raise Invalid_expr + +let decode_const c = + match decode_enum c with + | 0, [s] -> Int (dec_string s) + | 1, [s] -> Float (dec_string s) + | 2, [s] -> String (dec_string s) + | 3, [s] -> Ident (dec_string s) + | 4, [s;opt] -> Regexp (dec_string s, dec_string opt) + | 5, [s] -> Ident (dec_string s) (** deprecated CType, keep until 3.0 release **) + | _ -> raise Invalid_expr + +let rec decode_op op = + match decode_enum op with + | 0, [] -> OpAdd + | 1, [] -> OpMult + | 2, [] -> OpDiv + | 3, [] -> OpSub + | 4, [] -> OpAssign + | 5, [] -> OpEq + | 6, [] -> OpNotEq + | 7, [] -> OpGt + | 8, [] -> OpGte + | 9, [] -> OpLt + | 10, [] -> OpLte + | 11, [] -> OpAnd + | 12, [] -> OpOr + | 13, [] -> OpXor + | 14, [] -> OpBoolAnd + | 15, [] -> OpBoolOr + | 16, [] -> OpShl + | 17, [] -> OpShr + | 18, [] -> OpUShr + | 19, [] -> OpMod + | 20, [op] -> OpAssignOp (decode_op op) + | 21, [] -> OpInterval + | 22,[] -> OpArrow + | _ -> raise Invalid_expr + +let decode_unop op = + match decode_enum op with + | 0, [] -> Increment + | 1, [] -> Decrement + | 2, [] -> Not + | 3, [] -> Neg + | 4, [] -> NegBits + | _ -> raise Invalid_expr + +let decode_import_mode t = + match decode_enum t with + | 0, [] -> INormal + | 1, [alias] -> IAsName (dec_string alias) + | 2, [] -> IAll + | _ -> raise Invalid_expr + +let decode_import t = (List.map (fun o -> ((dec_string (field o "name")), (decode_pos (field o "pos")))) (dec_array (field t "path")), decode_import_mode (field t "mode")) + +let rec decode_path t = + { + tpackage = List.map dec_string (dec_array (field t "pack")); + tname = dec_string (field t "name"); + tparams = (match field t "params" with VNull -> [] | a -> List.map decode_tparam (dec_array a)); + tsub = opt dec_string (field t "sub"); + } + +and decode_tparam v = + match decode_enum v with + | 0,[t] -> TPType (decode_ctype t) + | 1,[e] -> TPExpr (decode_expr e) + | _ -> raise Invalid_expr + +and decode_tparams = function + | VNull -> [] + | a -> List.map decode_tparam_decl (dec_array a) + +and decode_tparam_decl v = + { + tp_name = dec_string (field v "name"); + tp_constraints = (match field v "constraints" with VNull -> [] | a -> List.map decode_ctype (dec_array a)); + tp_params = decode_tparams (field v "params"); + } + +and decode_fun v = + { + f_params = decode_tparams (field v "params"); + f_args = List.map (fun o -> + (dec_string (field o "name"),(match field o "opt" with VNull -> false | v -> dec_bool v),opt decode_ctype (field o "type"),opt decode_expr (field o "value")) + ) (dec_array (field v "args")); + f_type = opt decode_ctype (field v "ret"); + f_expr = opt decode_expr (field v "expr"); + } + +and decode_access v = + match decode_enum v with + | 0, [] -> APublic + | 1, [] -> APrivate + | 2, [] -> AStatic + | 3, [] -> AOverride + | 4, [] -> ADynamic + | 5, [] -> AInline + | 6, [] -> AMacro + | _ -> raise Invalid_expr + +and decode_meta_entry v = + MetaInfo.from_string (dec_string (field v "name")), (match field v "params" with VNull -> [] | a -> List.map decode_expr (dec_array a)), decode_pos (field v "pos") + +and decode_meta_content = function + | VNull -> [] + | v -> List.map decode_meta_entry (dec_array v) + +and decode_field v = + let fkind = match decode_enum (field v "kind") with + | 0, [t;e] -> + FVar (opt decode_ctype t, opt decode_expr e) + | 1, [f] -> + FFun (decode_fun f) + | 2, [get;set; t; e] -> + FProp (dec_string get, dec_string set, opt decode_ctype t, opt decode_expr e) + | _ -> + raise Invalid_expr + in + { + cff_name = dec_string (field v "name"); + cff_doc = opt dec_string (field v "doc"); + cff_pos = decode_pos (field v "pos"); + cff_kind = fkind; + cff_access = List.map decode_access (opt_list dec_array (field v "access")); + cff_meta = opt_list decode_meta_content (field v "meta"); + } + +and decode_ctype t = + match decode_enum t with + | 0, [p] -> + CTPath (decode_path p) + | 1, [a;r] -> + CTFunction (List.map decode_ctype (dec_array a), decode_ctype r) + | 2, [fl] -> + CTAnonymous (List.map decode_field (dec_array fl)) + | 3, [t] -> + CTParent (decode_ctype t) + | 4, [tl;fl] -> + CTExtend (List.map decode_path (dec_array tl), List.map decode_field (dec_array fl)) + | 5, [t] -> + CTOptional (decode_ctype t) + | _ -> + raise Invalid_expr + +let rec decode_expr v = + let rec loop v = + (decode (field v "expr"), decode_pos (field v "pos")) + and decode e = + match decode_enum e with + | 0, [c] -> + EConst (decode_const c) + | 1, [e1;e2] -> + EArray (loop e1, loop e2) + | 2, [op;e1;e2] -> + EBinop (decode_op op, loop e1, loop e2) + | 3, [e;f] -> + EField (loop e, dec_string f) + | 4, [e] -> + EParenthesis (loop e) + | 5, [a] -> + EObjectDecl (List.map (fun o -> + (dec_string (field o "field"), loop (field o "expr")) + ) (dec_array a)) + | 6, [a] -> + EArrayDecl (List.map loop (dec_array a)) + | 7, [e;el] -> + ECall (loop e,List.map loop (dec_array el)) + | 8, [t;el] -> + ENew (decode_path t,List.map loop (dec_array el)) + | 9, [op;VBool f;e] -> + EUnop (decode_unop op,(if f then Postfix else Prefix),loop e) + | 10, [vl] -> + EVars (List.map (fun v -> + (dec_string (field v "name"),opt decode_ctype (field v "type"),opt loop (field v "expr")) + ) (dec_array vl)) + | 11, [fname;f] -> + EFunction (opt dec_string fname,decode_fun f) + | 12, [el] -> + EBlock (List.map loop (dec_array el)) + | 13, [e1;e2] -> + EFor (loop e1, loop e2) + | 14, [e1;e2] -> + EIn (loop e1, loop e2) + | 15, [e1;e2;e3] -> + EIf (loop e1, loop e2, opt loop e3) + | 16, [e1;e2;VBool flag] -> + EWhile (loop e1,loop e2,if flag then NormalWhile else DoWhile) + | 17, [e;cases;eo] -> + let cases = List.map (fun c -> + (List.map loop (dec_array (field c "values")),opt loop (field c "guard"),opt loop (field c "expr")) + ) (dec_array cases) in + ESwitch (loop e,cases,opt decode_null_expr eo) + | 18, [e;catches] -> + let catches = List.map (fun c -> + (dec_string (field c "name"),decode_ctype (field c "type"),loop (field c "expr")) + ) (dec_array catches) in + ETry (loop e, catches) + | 19, [e] -> + EReturn (opt loop e) + | 20, [] -> + EBreak + | 21, [] -> + EContinue + | 22, [e] -> + EUntyped (loop e) + | 23, [e] -> + EThrow (loop e) + | 24, [e;t] -> + ECast (loop e,opt decode_ctype t) + | 25, [e;f] -> + EDisplay (loop e,dec_bool f) + | 26, [t] -> + EDisplayNew (decode_path t) + | 27, [e1;e2;e3] -> + ETernary (loop e1,loop e2,loop e3) + | 28, [e;t] -> + ECheckType (loop e, decode_ctype t) + | 29, [m;e] -> + EMeta (decode_meta_entry m,loop e) + | 30, [e;f] -> + EField (loop e, dec_string f) (*** deprecated EType, keep until haxe 3 **) + | _ -> + raise Invalid_expr + in + try + loop v + with Stack_overflow -> + raise Invalid_expr + +and decode_null_expr v = + match field v "expr" with + | VNull -> None + | _ -> Some (decode_expr v) + + +(* ---------------------------------------------------------------------- *) +(* TYPE ENCODING *) + +let encode_ref v convert tostr = + enc_obj [ + "get", VFunction (Fun0 (fun() -> convert v)); + "__string", VFunction (Fun0 (fun() -> VString (tostr()))); + "toString", VFunction (Fun0 (fun() -> enc_string (tostr()))); + "$", VAbstract (AUnsafe (Obj.repr v)); + ] + +let decode_ref v : 'a = + match field v "$" with + | VAbstract (AUnsafe t) -> Obj.obj t + | _ -> raise Invalid_expr + +let encode_pmap convert m = + let h = Hashtbl.create 0 in + PMap.iter (fun k v -> Hashtbl.add h (VString k) (convert v)) m; + enc_hash h + +let encode_pmap_array convert m = + let l = ref [] in + PMap.iter (fun _ v -> l := !l @ [(convert v)]) m; + enc_array !l + +let encode_array convert l = + enc_array (List.map convert l) + +let encode_meta m set = + let meta = ref m in + enc_obj [ + "get", VFunction (Fun0 (fun() -> + encode_meta_content (!meta) + )); + "add", VFunction (Fun3 (fun k vl p -> + (try + let el = List.map decode_expr (dec_array vl) in + meta := (MetaInfo.from_string (dec_string k), el, decode_pos p) :: !meta; + set (!meta) + with Invalid_expr -> + failwith "Invalid expression"); + VNull + )); + "extract", VFunction (Fun1 (fun k -> + let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in + encode_array encode_meta_entry (List.filter (fun (m,_,_) -> m = k) (!meta)) + )); + "remove", VFunction (Fun1 (fun k -> + let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in + meta := List.filter (fun (m,_,_) -> m <> k) (!meta); + set (!meta); + VNull + )); + "has", VFunction (Fun1 (fun k -> + let k = MetaInfo.from_string (try dec_string k with Invalid_expr -> raise Builtin_error) in + VBool (List.exists (fun (m,_,_) -> m = k) (!meta)); + )); + ] + +let rec encode_mtype t fields = + let i = t_infos t in + enc_obj ([ + "__t", VAbstract (ATDecl t); + "pack", enc_array (List.map enc_string (fst i.mt_path)); + "name", enc_string (snd i.mt_path); + "pos", encode_pos i.mt_pos; + "module", enc_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 enc_string i.mt_doc; + "params", encode_type_params i.mt_params; + ] @ fields) + +and encode_type_params tl = + enc_array (List.map (fun (n,t) -> enc_obj ["name",enc_string n;"t",encode_type t]) tl) + +and encode_tenum e = + encode_mtype (TEnumDecl e) [ + "isExtern", VBool e.e_extern; + "exclude", VFunction (Fun0 (fun() -> e.e_extern <- true; VNull)); + "constructs", encode_pmap encode_efield e.e_constrs; + "names", enc_array (List.map enc_string e.e_names); + ] + +and encode_tabstract a = + encode_mtype (TAbstractDecl a) [ + "type", encode_type a.a_this; + "impl", (match a.a_impl with None -> VNull | Some c -> encode_clref c); + "binops", enc_array (List.map (fun (op,cf) -> enc_obj [ "op",encode_binop op; "field",encode_cfield cf]) a.a_ops); + "unops", enc_array (List.map (fun (op,postfix,cf) -> enc_obj [ "op",encode_unop op; "isPostfix",VBool (match postfix with Postfix -> true | Prefix -> false); "field",encode_cfield cf]) a.a_unops); + "from", enc_array ((List.map (fun t -> enc_obj [ "t",encode_type t; "field",VNull]) a.a_from) @ (List.map (fun (t,cf) -> enc_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_from_field)); + "to", enc_array ((List.map (fun t -> enc_obj [ "t",encode_type t; "field",VNull]) a.a_to) @ (List.map (fun (t,cf) -> enc_obj [ "t",encode_type t; "field",encode_cfield cf]) a.a_to_field)); + "array", enc_array (List.map encode_cfield a.a_array); + ] + +and encode_efield f = + enc_obj [ + "name", enc_string f.ef_name; + "type", encode_type f.ef_type; + "pos", encode_pos f.ef_pos; + "index", VInt f.ef_index; + "meta", encode_meta f.ef_meta (fun m -> f.ef_meta <- m); + "doc", null enc_string f.ef_doc; + "params", encode_type_params f.ef_params; + ] + +and encode_cfield f = + enc_obj [ + "name", enc_string f.cf_name; + "type", (match f.cf_kind with Method _ -> encode_lazy_type f.cf_type | _ -> encode_type f.cf_type); + "isPublic", VBool f.cf_public; + "params", encode_type_params f.cf_params; + "meta", encode_meta f.cf_meta (fun m -> f.cf_meta <- m); + "expr", (VFunction (Fun0 (fun() -> ignore(follow f.cf_type); (match f.cf_expr with None -> VNull | Some e -> encode_texpr e)))); + "kind", encode_field_kind f.cf_kind; + "pos", encode_pos f.cf_pos; + "doc", null enc_string f.cf_doc; + ] + +and encode_field_kind k = + let tag, pl = (match k with + | Type.Var v -> 0, [encode_var_access v.v_read; encode_var_access v.v_write] + | Method m -> 1, [encode_method_kind m] + ) in + enc_enum IFieldKind tag pl + +and encode_var_access a = + let tag, pl = (match a with + | AccNormal -> 0, [] + | AccNo -> 1, [] + | AccNever -> 2, [] + | AccResolve -> 3, [] + | AccCall -> 4, [] + | AccInline -> 5, [] + | AccRequire (s,msg) -> 6, [enc_string s; null enc_string msg] + ) in + enc_enum IVarAccess tag pl + +and encode_method_kind m = + let tag, pl = (match m with + | MethNormal -> 0, [] + | MethInline -> 1, [] + | MethDynamic -> 2, [] + | MethMacro -> 3, [] + ) in + enc_enum IMethodKind tag pl + +and encode_class_kind k = + let tag, pl = (match k with + | KNormal -> 0, [] + | KTypeParameter pl -> 1, [encode_tparams pl] + | KExtension (cl, params) -> 2, [encode_clref cl; encode_tparams params] + | KExpr e -> 3, [encode_expr e] + | KGeneric -> 4, [] + | KGenericInstance (cl, params) -> 5, [encode_clref cl; encode_tparams params] + | KMacroType -> 6, [] + | KAbstractImpl a -> 7, [encode_abref a] + | KGenericBuild cfl -> 8, [] + ) in + enc_enum IClassKind tag pl + +and encode_tclass c = + ignore(c.cl_build()); + encode_mtype (TClassDecl c) [ + "kind", encode_class_kind c.cl_kind; + "isExtern", VBool c.cl_extern; + "exclude", VFunction (Fun0 (fun() -> c.cl_extern <- true; c.cl_init <- None; VNull)); + "isInterface", VBool c.cl_interface; + "superClass", (match c.cl_super with + | None -> VNull + | Some (c,pl) -> enc_obj ["t",encode_clref c;"params",encode_tparams pl] + ); + "interfaces", enc_array (List.map (fun (c,pl) -> enc_obj ["t",encode_clref c;"params",encode_tparams pl]) c.cl_implements); + "fields", encode_ref c.cl_ordered_fields (encode_array encode_cfield) (fun() -> "class fields"); + "statics", encode_ref c.cl_ordered_statics (encode_array encode_cfield) (fun() -> "class fields"); + "constructor", (match c.cl_constructor with None -> VNull | Some cf -> encode_cfref cf); + "init", (match c.cl_init with None -> VNull | Some e -> encode_texpr e); + "overrides", (enc_array (List.map encode_cfref c.cl_overrides)) + ] + +and encode_ttype t = + encode_mtype (TTypeDecl t) [ + "isExtern", VBool false; + "exclude", VFunction (Fun0 (fun() -> VNull)); + "type", encode_type t.t_type; + ] + +and encode_tanon a = + enc_obj [ + "fields", encode_pmap_array encode_cfield a.a_fields; + "status", encode_anon_status !(a.a_status); + ] + +and encode_anon_status s = + let tag, pl = (match s with + | Closed -> 0, [] + | Opened -> 1, [] + | Type.Const -> 2, [] + | Extend tl -> 3, [encode_ref tl (fun tl -> enc_array (List.map encode_type tl)) (fun() -> "")] + | Statics cl -> 4, [encode_clref cl] + | EnumStatics en -> 5, [encode_enref en] + | AbstractStatics ab -> 6, [encode_abref ab] + ) + in + enc_enum IAnonStatus tag pl + +and encode_tparams pl = + enc_array (List.map encode_type pl) + +and encode_clref c = + encode_ref c encode_tclass (fun() -> s_type_path c.cl_path) + +and encode_enref en = + encode_ref en encode_tenum (fun() -> s_type_path en.e_path) + +and encode_cfref cf = + encode_ref cf encode_cfield (fun() -> cf.cf_name) + +and encode_abref ab = + encode_ref ab encode_tabstract (fun() -> s_type_path ab.a_path) + +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() -> "")] + | Some t -> loop t) + | TEnum (e, pl) -> + 1 , [encode_ref e encode_tenum (fun() -> s_type_path e.e_path); encode_tparams pl] + | TInst (c, pl) -> + 2 , [encode_clref c; encode_tparams pl] + | TType (t,pl) -> + 3 , [encode_ref t encode_ttype (fun() -> s_type_path t.t_path); encode_tparams pl] + | TFun (pl,ret) -> + let pl = List.map (fun (n,o,t) -> + enc_obj [ + "name",enc_string n; + "opt",VBool o; + "t",encode_type t + ] + ) pl in + 4 , [enc_array pl; encode_type ret] + | TAnon a -> + 5, [encode_ref a encode_tanon (fun() -> "")] + | TDynamic tsub as t -> + if t == t_dynamic then + 6, [VNull] + else + 6, [encode_type tsub] + | TLazy f -> + loop (!f()) + | TAbstract (a, pl) -> + 8, [encode_abref a; encode_tparams pl] + in + let tag, pl = loop t in + enc_enum IType tag pl + +and encode_lazy_type t = + let rec loop = function + | TMono r -> + (match !r with + | Some t -> loop t + | _ -> encode_type t) + | TLazy f -> + enc_enum IType 7 [VAbstract (ALazyType f)] + | _ -> + encode_type t + in + loop t + +and decode_type t = + match decode_enum t with + | 0, [r] -> TMono (decode_ref r) + | 1, [e; pl] -> TEnum (decode_ref e, List.map decode_type (dec_array pl)) + | 2, [c; pl] -> TInst (decode_ref c, List.map decode_type (dec_array pl)) + | 3, [t; pl] -> TType (decode_ref t, List.map decode_type (dec_array pl)) + | 4, [pl; r] -> TFun (List.map (fun p -> dec_string (field p "name"), dec_bool (field p "opt"), decode_type (field p "t")) (dec_array pl), decode_type r) + | 5, [a] -> TAnon (decode_ref a) + | 6, [VNull] -> t_dynamic + | 6, [t] -> TDynamic (decode_type t) + | 7, [VAbstract (ALazyType f)] -> TLazy f + | 8, [a; pl] -> TAbstract (decode_ref a, List.map decode_type (dec_array pl)) + | _ -> raise Invalid_expr + +let decode_tdecl v = + match v with + | VObject o -> + (match get_field o (hash "__t") with + | VAbstract (ATDecl t) -> t + | _ -> raise Invalid_expr) + | _ -> raise Invalid_expr + +(* ---------------------------------------------------------------------- *) +(* TEXPR Encoding *) + +let vopt f v = match v with + | None -> VNull + | Some v -> f v + +let rec encode_tconst c = + let tag, pl = match c with + | TInt i -> 0,[best_int i] + | TFloat f -> 1,[enc_string f] + | TString s -> 2,[enc_string s] + | TBool b -> 3,[VBool b] + | TNull -> 4,[] + | TThis -> 5,[] + | TSuper -> 6,[] + in + enc_enum ITConstant tag pl + +and encode_tvar v = + let f_extra (pl,e) = + enc_obj [ + "params",encode_type_params pl; + "expr",vopt encode_texpr e + ] + in + enc_obj [ + "id", VInt v.v_id; + "name", enc_string v.v_name; + "t", encode_type v.v_type; + "capture", VBool v.v_capture; + "extra", vopt f_extra v.v_extra; + "meta", encode_meta_content v.v_meta; + "$", VAbstract (AUnsafe (Obj.repr v)); + ] + +and encode_module_type mt = + let tag,pl = match mt with + | TClassDecl c -> 0,[encode_clref c] + | TEnumDecl e -> 1,[encode_enref e] + | TTypeDecl t -> 2,[encode_ref t encode_ttype (fun () -> s_type_path t.t_path)] + | TAbstractDecl a -> 3,[encode_abref a] + in + enc_enum IModuleType tag pl + +and encode_tfunc func = + enc_obj [ + "args",enc_array (List.map (fun (v,c) -> + enc_obj [ + "v",encode_tvar v; + "value",match c with None -> VNull | Some c -> encode_tconst c + ] + ) func.tf_args); + "t",encode_type func.tf_type; + "expr",encode_texpr func.tf_expr + ] + +and encode_field_access fa = + let encode_instance c tl = + enc_obj [ + "c",encode_clref c; + "params",encode_tparams tl + ] + in + let tag,pl = match fa with + | FInstance(c,tl,cf) -> 0,[encode_clref c;encode_tparams tl;encode_cfref cf] + | FStatic(c,cf) -> 1,[encode_clref c;encode_cfref cf] + | FAnon(cf) -> 2,[encode_cfref cf] + | FDynamic(s) -> 3,[enc_string s] + | FClosure(co,cf) -> 4,[(match co with Some (c,tl) -> encode_instance c tl | None -> VNull);encode_cfref cf] + | FEnum(en,ef) -> 5,[encode_enref en;encode_efield ef] + in + enc_enum IFieldAccess tag pl + +and encode_texpr e = + let rec loop e = + let tag, pl = match e.eexpr with + | TConst c -> 0,[encode_tconst c] + | TLocal v -> 1,[encode_tvar v] + | TArray(e1,e2) -> 2,[loop e1; loop e2] + | TBinop(op,e1,e2) -> 3,[encode_binop op;loop e1;loop e2] + | TField(e1,fa) -> 4,[loop e1;encode_field_access fa] + | TTypeExpr mt -> 5,[encode_module_type mt] + | TParenthesis e1 -> 6,[loop e1] + | TObjectDecl fl -> 7, [enc_array (List.map (fun (f,e) -> + enc_obj [ + "name",enc_string f; + "expr",loop e; + ]) fl)] + | TArrayDecl el -> 8,[encode_texpr_list el] + | TCall(e1,el) -> 9,[loop e1;encode_texpr_list el] + | TNew(c,pl,el) -> 10,[encode_clref c;encode_tparams pl;encode_texpr_list el] + | TUnop(op,flag,e1) -> 11,[encode_unop op;VBool (flag = Postfix);loop e1] + | TFunction func -> 12,[encode_tfunc func] + | TVar (v,eo) -> 13,[encode_tvar v;vopt encode_texpr eo] + | TBlock el -> 14,[encode_texpr_list el] + | TFor(v,e1,e2) -> 15,[encode_tvar v;loop e1;loop e2] + | TIf(eif,ethen,eelse) -> 16,[loop eif;loop ethen;vopt encode_texpr eelse] + | TWhile(econd,e1,flag) -> 17,[loop econd;loop e1;VBool (flag = NormalWhile)] + | TSwitch(e1,cases,edef) -> 18,[ + loop e1; + enc_array (List.map (fun (el,e) -> enc_obj ["values",encode_texpr_list el;"expr",loop e]) cases); + vopt encode_texpr edef + ] + | TTry(e1,catches) -> 19,[ + loop e1; + enc_array (List.map (fun (v,e) -> + enc_obj [ + "v",encode_tvar v; + "expr",loop e + ]) catches + )] + | TReturn e1 -> 20,[vopt encode_texpr e1] + | TBreak -> 21,[] + | TContinue -> 22,[] + | TThrow e1 -> 23,[loop e1] + | TCast(e1,mt) -> 24,[loop e1;match mt with None -> VNull | Some mt -> encode_module_type mt] + | TMeta(m,e1) -> 25,[encode_meta_entry m;loop e1] + | TEnumParameter(e1,ef,i) -> 26,[loop e1;encode_efield ef;VInt i] + in + enc_obj [ + "pos", encode_pos e.epos; + "expr", enc_enum ITypedExpr tag pl; + "t", encode_type e.etype + ] + in + loop e + +and encode_texpr_list el = + enc_array (List.map encode_texpr el) + +(* ---------------------------------------------------------------------- *) +(* TEXPR Decoding *) + +let decode_tconst c = + match decode_enum c with + | 0, [s] -> TInt (match s with VInt i -> Int32.of_int i | VInt32 i -> i | _ -> raise Invalid_expr) + | 1, [s] -> TFloat (dec_string s) + | 2, [s] -> TString (dec_string s) + | 3, [s] -> TBool (dec_bool s) + | 4, [] -> TNull + | 5, [] -> TThis + | 6, [] -> TSuper + | _ -> raise Invalid_expr + +let decode_type_params v = + List.map (fun v -> dec_string (field v "name"),decode_type (field v "t")) (dec_array v) + +let decode_tvar v = + match field v "$" with + | VAbstract (AUnsafe t) -> Obj.obj t + | _ -> raise Invalid_expr + +let decode_var_access v = + match decode_enum v with + | 0, [] -> AccNormal + | 1, [] -> AccNo + | 2, [] -> AccNever + | 3, [] -> AccResolve + | 4, [] -> AccCall + | 5, [] -> AccInline + | 6, [s1;s2] -> AccRequire(dec_string s1, opt dec_string s2) + | _ -> raise Invalid_expr + +let decode_method_kind v = + match decode_enum v with + | 0, [] -> MethNormal + | 1, [] -> MethInline + | 2, [] -> MethDynamic + | 3, [] -> MethMacro + | _ -> raise Invalid_expr + +let decode_field_kind v = + match decode_enum v with + | 0, [vr;vw] -> Type.Var({v_read = decode_var_access vr; v_write = decode_var_access vw}) + | 1, [m] -> Method (decode_method_kind m) + | _ -> raise Invalid_expr + +let decode_cfield v = + { + cf_name = dec_string (field v "name"); + cf_type = decode_type (field v "type"); + cf_public = dec_bool (field v "isPublic"); + cf_pos = decode_pos (field v "pos"); + cf_doc = opt dec_string (field v "doc"); + cf_meta = []; (* TODO *) + cf_kind = decode_field_kind (field v "kind"); + cf_params = decode_type_params (field v "params"); + cf_expr = None; + cf_overloads = []; + } + +let decode_efield v = + { + ef_name = dec_string (field v "name"); + ef_type = decode_type (field v "type"); + ef_pos = decode_pos (field v "pos"); + ef_index = (match field v "index" with VInt i -> i | _ -> raise Invalid_expr); + ef_meta = []; (* TODO *) + ef_doc = opt dec_string (field v "doc"); + ef_params = decode_type_params (field v "params") + } + +let decode_field_access v = + match decode_enum v with + | 0, [c;tl;cf] -> + let c = decode_ref c in + FInstance(c,List.map decode_type (dec_array tl),decode_ref cf) + | 1, [c;cf] -> FStatic(decode_ref c,decode_ref cf) + | 2, [cf] -> FAnon(decode_ref cf) + | 3, [s] -> FDynamic(dec_string s) + | 4, [co;cf] -> + let co = match co with + | VNull -> None + | _ -> Some (decode_ref (field co "c"),List.map decode_type (dec_array (field co "params"))) + in + FClosure(co,decode_ref cf) + | 5, [e;ef] -> FEnum(decode_ref e,decode_efield ef) + | _ -> raise Invalid_expr + +let decode_module_type v = + match decode_enum v with + | 0, [c] -> TClassDecl (decode_ref c) + | 1, [en] -> TEnumDecl (decode_ref en) + | 2, [t] -> TTypeDecl (decode_ref t) + | 3, [a] -> TAbstractDecl (decode_ref a) + | _ -> raise Invalid_expr + +let decode_tfunc v = + { + tf_args = List.map (fun v -> decode_tvar (field v "v"),opt decode_tconst (field v "value")) (dec_array (field v "args")); + tf_type = decode_type (field v "t"); + tf_expr = decode_texpr (field v "expr") + } + +let rec decode_texpr v = + let rec loop v = + mk (decode (field v "expr")) (decode_type (field v "t")) (decode_pos (field v "pos")) + and decode e = + match decode_enum e with + | 0, [c] -> TConst(decode_tconst c) + | 1, [v] -> TLocal(decode_tvar v) + | 2, [v1;v2] -> TArray(loop v1,loop v2) + | 3, [op;v1;v2] -> TBinop(decode_op op,loop v1,loop v2) + | 4, [v1;fa] -> TField(loop v1,decode_field_access fa) + | 5, [mt] -> TTypeExpr(decode_module_type mt) + | 6, [v1] -> TParenthesis(loop v1) + | 7, [v] -> TObjectDecl(List.map (fun v -> dec_string (field v "name"),loop (field v "expr")) (dec_array v)) + | 8, [vl] -> TArrayDecl(List.map loop (dec_array vl)) + | 9, [v1;vl] -> TCall(loop v1,List.map loop (dec_array vl)) + | 10, [c;tl;vl] -> TNew(decode_ref c,List.map decode_type (dec_array tl),List.map loop (dec_array vl)) + | 11, [op;pf;v1] -> TUnop(decode_unop op,(if dec_bool pf then Postfix else Prefix),loop v1) + | 12, [f] -> TFunction(decode_tfunc f) + | 13, [v;eo] -> TVar(decode_tvar v,opt loop eo) + | 14, [vl] -> TBlock(List.map loop (dec_array vl)) + | 15, [v;v1;v2] -> TFor(decode_tvar v,loop v1,loop v2) + | 16, [vif;vthen;velse] -> TIf(loop vif,loop vthen,opt loop velse) + | 17, [vcond;v1;b] -> TWhile(loop vcond,loop v1,if dec_bool b then NormalWhile else DoWhile) + | 18, [v1;cl;vdef] -> TSwitch(loop v1,List.map (fun v -> List.map loop (dec_array (field v "values")),loop (field v "expr")) (dec_array cl),opt loop vdef) + | 19, [v1;cl] -> TTry(loop v1,List.map (fun v -> decode_tvar (field v "v"),loop (field v "expr")) (dec_array cl)) + | 20, [vo] -> TReturn(opt loop vo) + | 21, [] -> TBreak + | 22, [] -> TContinue + | 23, [v1] -> TThrow(loop v1) + | 24, [v1;mto] -> TCast(loop v1,opt decode_module_type mto) + | 25, [m;v1] -> TMeta(decode_meta_entry m,loop v1) + | 26, [v1;ef;i] -> TEnumParameter(loop v1,decode_efield ef,match i with VInt i -> i | _ -> raise Invalid_expr) + | i,el -> Printf.printf "%i %i\n" i (List.length el); raise Invalid_expr + in + try + loop v + with Stack_overflow -> + raise Invalid_expr + +(* ---------------------------------------------------------------------- *) +(* TYPE DEFINITION *) + +let decode_type_def v = + let pack = List.map dec_string (dec_array (field v "pack")) in + let name = dec_string (field v "name") in + let meta = decode_meta_content (field v "meta") in + let pos = decode_pos (field v "pos") in + let isExtern = (match field v "isExtern" with VNull -> false | v -> dec_bool v) in + let fields = List.map decode_field (dec_array (field v "fields")) in + let mk fl dl = + { + d_name = name; + d_doc = None; + d_params = decode_tparams (field v "params"); + d_meta = meta; + d_flags = fl; + d_data = dl; + } + in + let tdef = (match decode_enum (field v "kind") with + | 0, [] -> + let conv f = + let loop (n,opt,t,_) = + match t with + | None -> raise Invalid_expr + | Some t -> n, opt, t + in + let args, params, t = (match f.cff_kind with + | FVar (t,None) -> [], [], t + | FFun f -> List.map loop f.f_args, f.f_params, f.f_type + | _ -> raise Invalid_expr + ) in + { + ec_name = f.cff_name; + ec_doc = f.cff_doc; + ec_meta = f.cff_meta; + ec_pos = f.cff_pos; + ec_args = args; + ec_params = params; + ec_type = t; + } + in + EEnum (mk (if isExtern then [EExtern] else []) (List.map conv fields)) + | 1, [] -> + ETypedef (mk (if isExtern then [EExtern] else []) (CTAnonymous fields)) + | 2, [ext;impl;interf] -> + let flags = if isExtern then [HExtern] else [] in + let flags = (match interf with VNull | VBool false -> flags | VBool true -> HInterface :: flags | _ -> raise Invalid_expr) in + let flags = (match opt decode_path ext with None -> flags | Some t -> HExtends t :: flags) in + let flags = (match opt (fun v -> List.map decode_path (dec_array v)) impl with None -> flags | Some l -> List.map (fun t -> HImplements t) l @ flags) in + EClass (mk flags fields) + | 3, [t] -> + ETypedef (mk (if isExtern then [EExtern] else []) (decode_ctype t)) + | 4, [tthis;tfrom;tto] -> + let flags = match opt dec_array tfrom with None -> [] | Some ta -> List.map (fun t -> AFromType (decode_ctype t)) ta in + let flags = match opt dec_array tto with None -> flags | Some ta -> (List.map (fun t -> AToType (decode_ctype t)) ta) @ flags in + let flags = match opt decode_ctype tthis with None -> flags | Some t -> (AIsType t) :: flags in + EAbstract(mk flags fields) + | _ -> + raise Invalid_expr + ) in + (* if our package ends with an uppercase letter, then it's the module name *) + let pack,name = (match List.rev pack with + | last :: l when not (is_lower_ident last) -> List.rev l, last + | _ -> pack, name + ) in + (pack, name), tdef, pos + +(* ---------------------------------------------------------------------- *) +(* VALUE-TO-CONSTANT *) + +let rec make_const e = + match e.eexpr with + | TConst c -> + (match c with + | TInt i -> best_int i + | TFloat s -> VFloat (float_of_string s) + | TString s -> enc_string s + | TBool b -> VBool b + | TNull -> VNull + | TThis | TSuper -> raise Exit) + | TParenthesis e | TMeta(_,e) -> + make_const e + | TObjectDecl el -> + VObject (obj (hash_field (get_ctx())) (List.map (fun (f,e) -> f, make_const e) el)) + | TArrayDecl al -> + enc_array (List.map make_const al) + | _ -> + raise Exit + +(* ---------------------------------------------------------------------- *) +(* TEXPR-TO-AST-EXPR *) + +open Ast + +let tpath p mp pl = + if snd mp = snd p then + CTPath { + tpackage = fst p; + tname = snd p; + tparams = List.map (fun t -> TPType t) pl; + tsub = None; + } + else CTPath { + tpackage = fst mp; + tname = snd mp; + tparams = List.map (fun t -> TPType t) pl; + tsub = Some (snd p); + } + +let rec make_type = function + | TMono r -> + (match !r with + | None -> raise Exit + | Some t -> make_type t) + | TEnum (e,pl) -> + tpath e.e_path e.e_module.m_path (List.map make_type pl) + | TInst({cl_kind = KTypeParameter _} as c,pl) -> + tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map make_type pl) + | TInst (c,pl) -> + tpath c.cl_path c.cl_module.m_path (List.map make_type pl) + | TType (t,pl) as tf -> + (* recurse on type-type *) + if (snd t.t_path).[0] = '#' then make_type (follow tf) else tpath t.t_path t.t_module.m_path (List.map make_type pl) + | TAbstract (a,pl) -> + tpath a.a_path a.a_module.m_path (List.map make_type pl) + | TFun (args,ret) -> + CTFunction (List.map (fun (_,_,t) -> make_type t) args, make_type ret) + | TAnon a -> + begin match !(a.a_status) with + | Statics c -> tpath ([],"Class") ([],"Class") [tpath c.cl_path c.cl_path []] + | EnumStatics e -> tpath ([],"Enum") ([],"Enum") [tpath e.e_path e.e_path []] + | _ -> + CTAnonymous (PMap.foldi (fun _ f acc -> + { + cff_name = f.cf_name; + cff_kind = FVar (mk_ot f.cf_type,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 [make_type t2]) + | TLazy f -> + make_type ((!f)()) + +and mk_ot t = + match follow t with + | TMono _ -> None + | _ -> (try Some (make_type t) with Exit -> None) + +let rec make_ast 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 (pack,name) p = + match List.rev pack with + | [] -> (EConst (Ident name),p) + | pl -> + let rec loop = function + | [] -> assert false + | [n] -> (EConst (Ident n),p) + | n :: l -> (EField (loop l, n),p) + in + (EField (loop pl,name),p) + in + let mk_const = function + | TInt i -> Int (Int32.to_string i) + | TFloat s -> Float s + | TString s -> String s + | TBool b -> Ident (if b then "true" else "false") + | TNull -> Ident "null" + | TThis -> Ident "this" + | TSuper -> Ident "super" + in + let mk_ident = function + | "`trace" -> Ident "trace" + | n -> Ident n + in + let eopt = function None -> None | Some e -> Some (make_ast e) in + ((match e.eexpr with + | TConst c -> + EConst (mk_const c) + | TLocal v -> EConst (mk_ident v.v_name) + | TArray (e1,e2) -> EArray (make_ast e1,make_ast e2) + | TBinop (op,e1,e2) -> EBinop (op, make_ast e1, make_ast e2) + | TField (e,f) -> EField (make_ast e, Type.field_name f) + | TTypeExpr t -> fst (mk_path (full_type_path t) e.epos) + | TParenthesis e -> EParenthesis (make_ast e) + | TObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> f, make_ast e) fl) + | TArrayDecl el -> EArrayDecl (List.map make_ast el) + | TCall (e,el) -> ECall (make_ast e,List.map make_ast el) + | TNew (c,pl,el) -> ENew ((match (try make_type (TInst (c,pl)) with Exit -> make_type (TInst (c,[]))) with CTPath p -> p | _ -> assert false),List.map make_ast el) + | TUnop (op,p,e) -> EUnop (op,p,make_ast e) + | TFunction f -> + let arg (v,c) = v.v_name, false, mk_ot v.v_type, (match c with None -> None | Some c -> Some (EConst (mk_const c),e.epos)) in + EFunction (None,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_ot f.tf_type; f_expr = Some (make_ast f.tf_expr) }) + | TVar (v,eo) -> + EVars ([v.v_name, mk_ot v.v_type, eopt eo]) + | TBlock el -> EBlock (List.map make_ast el) + | TFor (v,it,e) -> + let ein = (EIn ((EConst (Ident v.v_name),it.epos),make_ast it),it.epos) in + EFor (ein,make_ast e) + | TIf (e,e1,e2) -> EIf (make_ast e,make_ast e1,eopt e2) + | TWhile (e1,e2,flag) -> EWhile (make_ast e1, make_ast e2, flag) + | TSwitch (e,cases,def) -> + let cases = List.map (fun (vl,e) -> + List.map make_ast vl,None,(match e.eexpr with TBlock [] -> None | _ -> Some (make_ast e)) + ) cases in + let def = match eopt def with None -> None | Some (EBlock [],_) -> Some None | e -> Some e in + ESwitch (make_ast e,cases,def) + | TEnumParameter _ -> + (* these are considered complex, so the AST is handled in TMeta(Meta.Ast) *) + assert false + | TTry (e,catches) -> ETry (make_ast e,List.map (fun (v,e) -> v.v_name, (try make_type v.v_type with Exit -> assert false), make_ast e) catches) + | TReturn e -> EReturn (eopt e) + | TBreak -> EBreak + | TContinue -> EContinue + | TThrow e -> EThrow (make_ast 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 make_type t with Exit -> assert false) + ) in + ECast (make_ast e,t) + | TMeta ((Meta.Ast,[e1,_],_),_) -> e1 + | TMeta (m,e) -> EMeta(m,make_ast e)) + ,e.epos) + +;; +make_ast_ref := make_ast; +make_complex_type_ref := make_type; +encode_complex_type_ref := encode_ctype; +enc_array_ref := enc_array; +dec_array_ref := dec_array; +encode_type_ref := encode_type; +decode_type_ref := decode_type; +encode_expr_ref := encode_expr; +decode_expr_ref := decode_expr; +encode_clref_ref := encode_clref; +enc_string_ref := enc_string; +enc_hash_ref := enc_hash; +encode_texpr_ref := encode_texpr; +decode_texpr_ref := decode_texpr; +encode_tvar_ref := encode_tvar; +decode_path_ref := decode_path; +decode_import_ref := decode_import; diff --git a/lexer.mll b/lexer.mll old mode 100755 new mode 100644 index 9b09028a663a63d77c0acb4ab6b1d3aa39754d0f..7ce94570e308142f18b27b2dcbc12a4e0abccb4b --- a/lexer.mll +++ b/lexer.mll @@ -29,6 +29,7 @@ type error_msg = | Unterminated_string | Unterminated_regexp | Unclosed_comment + | Unclosed_code | Invalid_escape | Invalid_option @@ -40,6 +41,7 @@ let error_msg = function | Unterminated_string -> "Unterminated string" | Unterminated_regexp -> "Unterminated regular expression" | Unclosed_comment -> "Unclosed comment" + | Unclosed_code -> "Unclosed code string" | Invalid_escape -> "Invalid escape sequence" | Invalid_option -> "Invalid regular expression option" @@ -83,10 +85,10 @@ let keywords = Inline;Using;Null;True;False;Abstract;Macro]; h -let init file = +let init file do_add = let f = make_file file in cur := f; - Hashtbl.replace all_files file f + if do_add then Hashtbl.replace all_files file f let save() = !cur @@ -148,9 +150,36 @@ let find_line p f = in loop 0 (Array.length f.lalines) +(* resolve a position within a non-haxe file by counting newlines *) +let resolve_pos file = + let ch = open_in_bin file in + let f = make_file file in + let rec loop p = + let inc i () = + f.lline <- f.lline + 1; + f.llines <- (p + i,f.lline) :: f.llines; + i + in + let i = match input_char ch with + | '\n' -> inc 1 + | '\r' -> + ignore(input_char ch); + inc 2 + | _ -> fun () -> 1 + in + loop (p + i()) + in + try + loop 0 + with End_of_file -> + close_in ch; + f + +let find_file file = + try Hashtbl.find all_files file with Not_found -> try resolve_pos file with Sys_error _ -> make_file file + let find_pos p = - let file = (try Hashtbl.find all_files p.pfile with Not_found -> make_file p.pfile) in - find_line p.pmin file + find_line p.pmin (find_file p.pfile) let get_error_line p = let l, _ = find_pos p in @@ -160,7 +189,7 @@ let get_error_pos printer p = if p.pmin = -1 then "(unknown)" else - let file = (try Hashtbl.find all_files p.pfile with Not_found -> make_file p.pfile) in + let file = find_file p.pfile in let l1, p1 = find_line p.pmin file in let l2, p2 = find_line p.pmax file in if l1 = l2 then begin @@ -191,6 +220,7 @@ let invalid_char lexbuf = let ident = ('_'* ['a'-'z'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']* | '_'+ | '_'+ ['0'-'9'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']* ) let idtype = '_'* ['A'-'Z'] ['_' 'a'-'z' 'A'-'Z' '0'-'9']* +let integer = ['1'-'9'] ['0'-'9']* | '0' rule skip_header = parse | "\239\187\191" { skip_header lexbuf } @@ -203,12 +233,12 @@ and token = parse | "\r\n" { newline lexbuf; token lexbuf } | '\n' | '\r' { newline lexbuf; token lexbuf } | "0x" ['0'-'9' 'a'-'f' 'A'-'F']+ { mk lexbuf (Const (Int (lexeme lexbuf))) } - | ['0'-'9']+ { mk lexbuf (Const (Int (lexeme lexbuf))) } - | ['0'-'9']+ '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } + | integer { mk lexbuf (Const (Int (lexeme lexbuf))) } + | integer '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } | '.' ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } - | ['0'-'9']+ ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } - | ['0'-'9']+ '.' ['0'-'9']* ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } - | ['0'-'9']+ "..." { + | integer ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } + | integer '.' ['0'-'9']* ['e' 'E'] ['+' '-']? ['0'-'9']+ { mk lexbuf (Const (Float (lexeme lexbuf))) } + | integer "..." { let s = lexeme lexbuf in mk lexbuf (IntInterval (String.sub s 0 (String.length s - 3))) } @@ -330,7 +360,42 @@ and string2 = parse | "\\\\" { store lexbuf; string2 lexbuf } | "\\'" { store lexbuf; string2 lexbuf } | "'" { lexeme_end lexbuf } - | [^'\'' '\\' '\r' '\n']+ { store lexbuf; string2 lexbuf } + | "$$" | "\\$" | '$' { store lexbuf; string2 lexbuf } + | "${" { + let pmin = lexeme_start lexbuf in + store lexbuf; + (try code_string lexbuf with Exit -> error Unclosed_code pmin); + string2 lexbuf; + } + | [^'\'' '\\' '\r' '\n' '$']+ { store lexbuf; string2 lexbuf } + +and code_string = parse + | eof { raise Exit } + | '\n' | '\r' | "\r\n" { newline lexbuf; store lexbuf; code_string lexbuf } + | '{' | '/' { store lexbuf; code_string lexbuf } + | '}' { store lexbuf; (* stop *) } + | '"' { + add "\""; + let pmin = lexeme_start lexbuf in + (try ignore(string lexbuf) with Exit -> error Unterminated_string pmin); + add "\""; + code_string lexbuf; + } + | "'" { + add "'"; + let pmin = lexeme_start lexbuf in + let pmax = (try string2 lexbuf with Exit -> error Unterminated_string pmin) in + add "'"; + fast_add_fmt_string { pfile = !cur.lfile; pmin = pmin; pmax = pmax }; + code_string lexbuf; + } + | "/*" { + let pmin = lexeme_start lexbuf in + (try ignore(comment lexbuf) with Exit -> error Unclosed_comment pmin); + code_string lexbuf; + } + | "//" [^'\n' '\r']* { store lexbuf; code_string lexbuf; } + | [^'/' '"' '\'' '{' '}' '\n' '\r']+ { store lexbuf; code_string lexbuf; } and regexp = parse | eof | '\n' | '\r' { raise Exit } diff --git a/libs/Makefile b/libs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d0e8b2f05549d15b9911ba63eb34f42bb9a65c1a --- /dev/null +++ b/libs/Makefile @@ -0,0 +1,22 @@ +OCAMLOPT = ocamlopt +OCAMLC = ocamlc +TARGET_FLAG = all +LIBS=extlib extc neko javalib ilib ziplib swflib xml-light ttflib objsize + +all: $(LIBS) +$(LIBS): + make -C $@ OCAMLOPT=$(OCAMLOPT) OCAMLC=$(OCAMLC) $(TARGET_FLAG) + +clean: + make -C extlib clean + make -C extc clean + make -C neko clean + make -C ziplib clean + make -C javalib clean + make -C swflib clean + make -C xml-light clean + make -C ttflib clean + +.PHONY: all clean $(LIBS) + +Makefile: ; diff --git a/libs/extc/Makefile b/libs/extc/Makefile index 82c841bd8ef08a7923594a08b4f1ac03d877c302..2fd95ed1fe28f32bcbab5eebf5124ba964aeda56 100644 --- a/libs/extc/Makefile +++ b/libs/extc/Makefile @@ -1,17 +1,34 @@ CFLAGS = -I zlib LIBS = -I ../extlib +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +SRC = extc.ml process.ml extc_stubs.c process_stubs.c all: bytecode native -bytecode: extc_stubs.obj - ocamlc -a -o extc.cma $(LIBS) extc.ml +bytecode: extc.cma -native: extc_stubs.obj - ocamlopt -a -o extc.cmxa $(LIBS) extc.ml +native: extc.cmxa -extc_stubs.obj: extc_stubs.c - ocamlc $(CFLAGS) extc_stubs.c +extc.cma: extc_stubs.o process_stubs.o extc.ml process.ml + $(OCAMLC) -a -o extc.cma $(LIBS) extc.ml process.ml +extc.cmxa: extc.ml process.ml extc_stubs.o process_stubs.o + $(OCAMLOPT) -a -o extc.cmxa $(LIBS) extc.ml process.ml + +extc_stubs.o: extc_stubs.c + $(OCAMLC) $(CFLAGS) extc_stubs.c + +process_stubs.o: process_stubs.c + $(OCAMLC) $(CFLAGS) process_stubs.c + clean: - rm -f extc.cma extc.cmi extc.cmx extc.cmxa extc.o extc.obj extc.lib extc_stubs.obj extc_stubs.o - rm -f extc.a libextc.a libextc.lib extc.cmo + rm -f extc.cma extc.cmi extc.cmx extc.cmxa extc.o extc.obj extc.lib extc_stubs.obj extc_stubs.o process.cmx process.obj process.cmi process_stubs.obj process_stubs.o + rm -f extc.a libextc.a libextc.lib extc.cmo process.cmo + +test: native + ocamlopt -o test.exe -I ../extLib extLib.cmxa zlib/zlib.lib extc_stubs.obj process_stubs.obj extc.cmxa test.ml + +.PHONY: all bytecode native clean +Makefile: ; +$(SRC): ; diff --git a/libs/extc/extc_stubs.c b/libs/extc/extc_stubs.c index 07f174958042f980e2d91707406595a6ae7cf674..012fe1b2494d25702e1b66b3323544545ecafc28 100644 --- a/libs/extc/extc_stubs.c +++ b/libs/extc/extc_stubs.c @@ -201,53 +201,58 @@ CAMLprim value get_full_path( value f ) { #endif } -#ifdef _WIN32 -static void copyAscii( char *to, const char *from, int len ) { - while( len-- > 0 ) { - unsigned char c = *from; - if( c < 128 ) - *to = c; - to++; - from++; - } -} -#endif - CAMLprim value get_real_path( value path ) { #ifdef _WIN32 - value path2 = caml_copy_string(String_val(path)); - char *cur = String_val(path2); - if( cur[0] == '\\' && cur[1] == '\\' ) { - cur = strchr(cur,'\\'); - if( cur != NULL ) cur++; - } else if( cur[0] != 0 && cur[1] == ':' ) { - char c = cur[0]; - if( c >= 'a' && c <= 'z' ) - cur[0] = c - 'a' + 'A'; - cur += 2; - if( cur[0] == '\\' ) - cur++; + const char sep = '\\'; + size_t len, i, last; + WIN32_FIND_DATA data; + HANDLE handle; + char out[MAX_PATH]; + + // this will ensure the full class path with proper casing + if( GetFullPathName(String_val(path),MAX_PATH,out,NULL) == 0 ) + failwith("get_real_path"); + + len = strlen(out); + i = 0; + + if (len >= 2 && out[1] == ':') { + // convert drive letter to uppercase + if (out[0] >= 'a' && out[0] <= 'z') + out[0] += 'A' - 'a'; + if (len >= 3 && out[2] == sep) + i = 3; + else + i = 2; } - while( cur ) { - char *next = strchr(cur,'\\'); - SHFILEINFOA infos; - if( next != NULL ) - *next = 0; - else if( *cur == 0 ) - break; - if( SHGetFileInfoA( String_val(path2), 0, &infos, sizeof(infos), SHGFI_DISPLAYNAME ) != 0 ) { - // some special names might be expended to their localized name, so make sure we only - // change the casing and not the whole content - if( strcmpi(infos.szDisplayName,cur) == 0 ) - copyAscii(cur,infos.szDisplayName,strlen(infos.szDisplayName)+1); + + last = i; + + while (i < len) { + // skip until separator + while (i < len && out[i] != sep) + i++; + + // temporarily strip string to last found component + out[i] = 0; + + // get actual file/dir name with proper case + if ((handle = FindFirstFile(out, &data)) != INVALID_HANDLE_VALUE) { + // replace the component with proper case + memcpy(out + last, data.cFileName, i - last); + FindClose(handle); } - if( next != NULL ) { - *next = '\\'; - cur = next + 1; - } else - cur = NULL; + + // if we're not at the end, restore the path + if (i < len) + out[i] = sep; + + // advance + i++; + last = i; } - return path2; + + return caml_copy_string(out); #else return path; #endif diff --git a/libs/extc/process.ml b/libs/extc/process.ml new file mode 100644 index 0000000000000000000000000000000000000000..8e94f7d535cb0f967ecbdc7df0b02f7dd2faab97 --- /dev/null +++ b/libs/extc/process.ml @@ -0,0 +1,31 @@ +(* + * Extc : C common OCaml bindings + * Copyright (c)2004-2015 Nicolas Cannasse + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +type process + +external run : string -> string array -> process = "process_run" +external read_stdout : process -> string -> int -> int -> int = "process_stdout_read" +external read_stderr : process -> string -> int -> int -> int = "process_stderr_read" +external write_stdin : process -> string -> int -> int -> int = "process_stdin_write" +external close_stdin : process -> unit = "process_stdin_close" +external exit : process -> int = "process_exit" +external pid : process -> int = "process_pid" +external close : process -> unit = "process_close" +external kill : process -> unit = "process_kill" + diff --git a/libs/extc/process_stubs.c b/libs/extc/process_stubs.c new file mode 100644 index 0000000000000000000000000000000000000000..b083fb1a969863a575fb6574e10f52a077800e1c --- /dev/null +++ b/libs/extc/process_stubs.c @@ -0,0 +1,564 @@ +/* + * Copyright (C)2005-2015 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. + */ + + // ported from NekoVM + +#include +#include +#include +#include + +#ifdef _WIN32 +# include +#else +# include +# include +# include +# include +# ifndef __APPLE__ +# include +# endif +#endif + +#ifdef _WIN32 +# define POSIX_LABEL(name) +# define HANDLE_EINTR(label) +# define HANDLE_FINTR(f,label) +#else +# include +# define POSIX_LABEL(name) name: +# define HANDLE_EINTR(label) if( errno == EINTR ) goto label +# define HANDLE_FINTR(f,label) if( ferror(f) && errno == EINTR ) goto label +#endif + +// --- neko-to-caml api -- +#define val_check(v,t) +#define val_check_kind(v,k) +#define val_data(v) v +#define val_array_size(v) Wosize_val(v) +#define val_array_ptr(v) (&Field(v,0)) +#define val_string(v) String_val(v) +#define val_strlen(v) caml_string_length(v) +#define alloc_abstract(_,data) ((value)data) +#define alloc_int(i) Val_int(i) +#define val_gc(v,callb) +#define val_null Val_int(0) +#define val_int(v) Int_val(v) +#define DEFINE_KIND(_) +#define neko_error() failwith(__FUNCTION__) + +static value alloc_private( int size ) { + return alloc((size + sizeof(value) - 1) / sizeof(value), Abstract_tag); +} + +// --- buffer api +#define EXTERN + +typedef struct _stringitem { + char *str; + int size; + int len; + struct _stringitem *next; +} * stringitem; + +struct _buffer { + int totlen; + int blen; + stringitem data; +}; + +typedef struct _buffer *buffer; + +static void buffer_append_new( buffer b, const char *s, int len ) { + int size; + stringitem it; + while( b->totlen >= (b->blen << 2) ) + b->blen <<= 1; + size = (len < b->blen)?b->blen:len; + it = (stringitem)malloc(sizeof(struct _stringitem)); + it->str = (char*)malloc(size); + memcpy(it->str,s,len); + it->size = size; + it->len = len; + it->next = b->data; + b->data = it; +} + +EXTERN void buffer_append_sub( buffer b, const char *s, int len ) { + stringitem it; + if( s == NULL || len <= 0 ) + return; + b->totlen += len; + it = b->data; + if( it ) { + int free = it->size - it->len; + if( free >= len ) { + memcpy(it->str + it->len,s,len); + it->len += len; + return; + } else { + memcpy(it->str + it->len,s,free); + it->len += free; + s += free; + len -= free; + } + } + buffer_append_new(b,s,len); +} + +EXTERN void buffer_append_str( buffer b, const char *s ) { + if( s == NULL ) + return; + buffer_append_sub(b,s,strlen(s)); +} + +EXTERN buffer alloc_buffer( const char *init ) { + buffer b = (buffer)malloc(sizeof(struct _buffer)); + b->totlen = 0; + b->blen = 16; + b->data = NULL; + if( init ) + buffer_append_str(b,init); + return b; +} + +EXTERN void buffer_append_char( buffer b, char c ) { + stringitem it; + b->totlen++; + it = b->data; + if( it && it->len != it->size ) { + it->str[it->len++] = c; + return; + } + buffer_append_new(b,&c,1); +} + +EXTERN char *buffer_to_string( buffer b ) { + char *v = (char*)malloc(b->totlen + 1); + stringitem it = b->data; + char *s = v + b->totlen; + *s = 0; + while( it != NULL ) { + stringitem tmp; + s -= it->len; + memcpy(s,it->str,it->len); + tmp = it->next; + free(it->str); + free(it); + it = tmp; + } + free(b); + return v; +} + +EXTERN int buffer_length( buffer b ) { + return b->totlen; +} + +// --------------- + +#include +#include + +typedef struct { +#ifdef _WIN32 + HANDLE oread; + HANDLE eread; + HANDLE iwrite; + PROCESS_INFORMATION pinf; +#else + int oread; + int eread; + int iwrite; + int pid; +#endif +} vprocess; + +DEFINE_KIND(k_process); + +#define val_process(v) ((vprocess*)val_data(v)) + +/** + +

Process

+

+ An API for starting and communication with sub processes. +

+
+**/ +#ifndef _WIN32 +static int do_close( int fd ) { + POSIX_LABEL(close_again); + if( close(fd) != 0 ) { + HANDLE_EINTR(close_again); + return 1; + } + return 0; +} +#endif + +static void free_process( value vp ) { + vprocess *p = val_process(vp); +# ifdef _WIN32 + CloseHandle(p->eread); + CloseHandle(p->oread); + CloseHandle(p->iwrite); + CloseHandle(p->pinf.hProcess); + CloseHandle(p->pinf.hThread); +# else + do_close(p->eread); + do_close(p->oread); + do_close(p->iwrite); +# endif +} + +/** + process_run : cmd:string -> args:string array -> 'process + + Start a process using a command and the specified arguments. + +**/ +CAMLprim value process_run( value cmd, value vargs ) { + int i; + vprocess *p; + val_check(cmd,string); + val_check(vargs,array); +# ifdef _WIN32 + { + SECURITY_ATTRIBUTES sattr; + STARTUPINFO sinf; + HANDLE proc = GetCurrentProcess(); + HANDLE oread,eread,iwrite; + // creates commandline + buffer b = alloc_buffer(NULL); + char *sargs; + buffer_append_char(b,'"'); + buffer_append_str(b,val_string(cmd)); + buffer_append_char(b,'"'); + for(i=0;ioread,0,FALSE,DUPLICATE_SAME_ACCESS); + DuplicateHandle(proc,eread,proc,&p->eread,0,FALSE,DUPLICATE_SAME_ACCESS); + DuplicateHandle(proc,iwrite,proc,&p->iwrite,0,FALSE,DUPLICATE_SAME_ACCESS); + CloseHandle(oread); + CloseHandle(eread); + CloseHandle(iwrite); + + if( !CreateProcess(NULL,val_string(sargs),NULL,NULL,TRUE,0,NULL,NULL,&sinf,&p->pinf) ) { + CloseHandle(p->eread); + CloseHandle(p->oread); + CloseHandle(p->iwrite); + free(sargs); + neko_error(); + } + free(sargs); + // close unused pipes + CloseHandle(sinf.hStdOutput); + CloseHandle(sinf.hStdError); + CloseHandle(sinf.hStdInput); + } +# else + char **argv = (char**)alloc_private(sizeof(char*)*(val_array_size(vargs)+2)); + argv[0] = val_string(cmd); + for(i=0;ipid = fork(); + if( p->pid == -1 ) { + do_close(input[0]); + do_close(input[1]); + do_close(output[0]); + do_close(output[1]); + do_close(error[0]); + do_close(error[1]); + neko_error(); + } + // child + if( p->pid == 0 ) { + close(input[1]); + close(output[0]); + close(error[0]); + dup2(input[0],0); + dup2(output[1],1); + dup2(error[1],2); + execvp(val_string(cmd),argv); + fprintf(stderr,"Command not found : %s\n",val_string(cmd)); + exit(1); + } + // parent + do_close(input[0]); + do_close(output[1]); + do_close(error[1]); + p->iwrite = input[1]; + p->oread = output[0]; + p->eread = error[0]; +# endif + { + value vp = alloc_abstract(k_process,p); + val_gc(vp,free_process); + return vp; + } +} + +#define CHECK_ARGS() \ + vprocess *p; \ + val_check_kind(vp,k_process); \ + val_check(str,string); \ + val_check(pos,int); \ + val_check(len,int); \ + if( val_int(pos) < 0 || val_int(len) < 0 || val_int(pos) + val_int(len) > val_strlen(str) ) \ + neko_error(); \ + p = val_process(vp); \ + + +/** + process_stdout_read : 'process -> buf:string -> pos:int -> len:int -> int + + Read up to [len] bytes in [buf] starting at [pos] from the process stdout. + Returns the number of bytes readed this way. Raise an exception if this + process stdout is closed and no more data is available for reading. + +**/ +CAMLprim value process_stdout_read( value vp, value str, value pos, value len ) { + CHECK_ARGS(); +# ifdef _WIN32 + { + DWORD nbytes; + if( !ReadFile(p->oread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) + neko_error(); + return alloc_int(nbytes); + } +# else + int nbytes; + POSIX_LABEL(stdout_read_again); + nbytes = read(p->oread,val_string(str)+val_int(pos),val_int(len)); + if( nbytes < 0 ) { + HANDLE_EINTR(stdout_read_again); + neko_error(); + } + if( nbytes == 0 ) + neko_error(); + return alloc_int(nbytes); +# endif +} + +/** + process_stderr_read : 'process -> buf:string -> pos:int -> len:int -> int + + Read up to [len] bytes in [buf] starting at [pos] from the process stderr. + Returns the number of bytes readed this way. Raise an exception if this + process stderr is closed and no more data is available for reading. + +**/ +CAMLprim value process_stderr_read( value vp, value str, value pos, value len ) { + CHECK_ARGS(); +# ifdef _WIN32 + { + DWORD nbytes; + if( !ReadFile(p->eread,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) + neko_error(); + return alloc_int(nbytes); + } +# else + int nbytes; + POSIX_LABEL(stderr_read_again); + nbytes = read(p->eread,val_string(str)+val_int(pos),val_int(len)); + if( nbytes < 0 ) { + HANDLE_EINTR(stderr_read_again); + neko_error(); + } + if( nbytes == 0 ) + neko_error(); + return alloc_int(nbytes); +# endif +} + +/** + process_stdin_write : 'process -> buf:string -> pos:int -> len:int -> int + + Write up to [len] bytes from [buf] starting at [pos] to the process stdin. + Returns the number of bytes writen this way. Raise an exception if this + process stdin is closed. + +**/ +CAMLprim value process_stdin_write( value vp, value str, value pos, value len ) { + CHECK_ARGS(); +# ifdef _WIN32 + { + DWORD nbytes; + if( !WriteFile(p->iwrite,val_string(str)+val_int(pos),val_int(len),&nbytes,NULL) ) + neko_error(); + return alloc_int(nbytes); + } +# else + int nbytes; + POSIX_LABEL(stdin_write_again); + nbytes = write(p->iwrite,val_string(str)+val_int(pos),val_int(len)); + if( nbytes == -1 ) { + HANDLE_EINTR(stdin_write_again); + neko_error(); + } + return alloc_int(nbytes); +# endif +} + +/** + process_stdin_close : 'process -> void + + Close the process standard input. + +**/ +CAMLprim value process_stdin_close( value vp ) { + vprocess *p; + val_check_kind(vp,k_process); + p = val_process(vp); +# ifdef _WIN32 + if( !CloseHandle(p->iwrite) ) + neko_error(); +# else + if( do_close(p->iwrite) ) + neko_error(); + p->iwrite = -1; +# endif + return val_null; +} + +/** + process_exit : 'process -> int + + Wait until the process terminate, then returns its exit code. + +**/ +CAMLprim value process_exit( value vp ) { + vprocess *p; + val_check_kind(vp,k_process); + p = val_process(vp); +# ifdef _WIN32 + { + DWORD rval; + WaitForSingleObject(p->pinf.hProcess,INFINITE); + if( !GetExitCodeProcess(p->pinf.hProcess,&rval) ) + neko_error(); + return alloc_int(rval); + } +# else + int rval; + while( waitpid(p->pid,&rval,0) != p->pid ) { + if( errno == EINTR ) + continue; + neko_error(); + } + if( !WIFEXITED(rval) ) + neko_error(); + return alloc_int(WEXITSTATUS(rval)); +# endif +} + +/** + process_pid : 'process -> int + + Returns the process id. + +**/ +CAMLprim value process_pid( value vp ) { + vprocess *p; + val_check_kind(vp,k_process); + p = val_process(vp); +# ifdef _WIN32 + return alloc_int(p->pinf.dwProcessId); +# else + return alloc_int(p->pid); +# endif +} + +/** + process_close : 'process -> void + + Close the process I/O. + +**/ +CAMLprim value process_close( value vp ) { + val_check_kind(vp,k_process); + free_process(vp); + //val_kind(vp) = NULL; + //val_gc(vp,NULL); + return val_null; +} + +/** + process_kill : 'process -> void + + Terminates a running process. + +**/ +CAMLprim value process_kill( value vp ) { + val_check_kind(vp,k_process); +# ifdef _WIN32 + TerminateProcess(val_process(vp)->pinf.hProcess,-1); +# else + kill(val_process(vp)->pid,9); +# endif + return val_null; +} + + +/* ************************************************************************ */ diff --git a/libs/extc/test.ml b/libs/extc/test.ml index 17c222e6b8b121258e70837e30a4cd289828c7e9..0dfccdf32430dc7deda124838ca8b4ad9ec75461 100644 --- a/libs/extc/test.ml +++ b/libs/extc/test.ml @@ -17,7 +17,35 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) +if Array.length Sys.argv > 1 then begin + print_string Sys.argv.(1); + flush stdout; + prerr_string "ERROR"; + flush stderr; + let input = Std.input_all stdin in + print_string input; + exit 66; +end; + +prerr_endline "Start"; + prerr_endline (Extc.executable_path()); let contents = Std.input_file "test.ml" in let s = Extc.unzip (Extc.zip contents) in if s <> contents then failwith "zip + unzip failed"; + +let p = Process.run "test" [|"Hello"|] in +let tmp = String.create 100 in +let out = String.sub tmp 0 (Process.read_stdout p tmp 0 100) in +if out <> "Hello" then failwith ("OUT=" ^ out ^ "#"); +let err = String.sub tmp 0 (Process.read_stderr p tmp 0 100) in +if err <> "ERROR" then failwith ("ERR= " ^ err ^ "#"); +ignore(Process.write_stdin p "INPUT" 0 5); +Process.close_stdin p; +let out = String.sub tmp 0 (Process.read_stdout p tmp 0 100) in +if out <> "INPUT" then failwith ("IN-OUT=" ^ out ^ "#"); +let code = Process.exit p in +if code <> 66 then failwith ("EXIT=" ^ string_of_int code); +Process.close p; + +prerr_endline "End"; \ No newline at end of file diff --git a/libs/extlib/IO.ml b/libs/extlib/IO.ml index 107384f38a8980481fcd80a7c2abf1c953fa750d..010969708a8491d477051e5282e6f93e23f9235e 100644 --- a/libs/extlib/IO.ml +++ b/libs/extlib/IO.ml @@ -664,7 +664,7 @@ let rec read_bits b n = end else begin let k = read_byte b.ch in if b.nbits >= 24 then begin - if n >= 31 then raise Bits_error; + if n > 31 then raise Bits_error; let c = 8 + b.nbits - n in let d = b.bits land ((1 lsl b.nbits) - 1) in let d = (d lsl (8 - c)) lor (k lsr c) in diff --git a/libs/extlib/Makefile b/libs/extlib/Makefile index e0842560fcb797e2e31d8a757323145d431a7013..488d5072ab51dbcda5222afbdd70dc77eeedcb7f 100644 --- a/libs/extlib/Makefile +++ b/libs/extlib/Makefile @@ -1,7 +1,9 @@ # Makefile contributed by Alain Frisch +OCAMLOPT=ocamlopt +OCAMLC=ocamlc MODULES = \ - enum bitSet dynArray extArray extHashtbl extList extString global IO option \ + enum bitSet dynArray extArray extHashtbl extList extString global rbuffer IO option \ pMap std uChar uTF8 base64 unzip refList optParse dllist multiArray # the list is topologically sorted @@ -9,12 +11,22 @@ MODULES = \ MLI = $(MODULES:=.mli) SRC = $(MLI) $(MODULES:=.ml) extLib.ml -all: - ocamlc -a -o extLib.cma $(SRC) -opt: - ocamlopt -g -a -o extLib.cmxa $(SRC) +all: bytecode native + +opt: native + +bytecode: extLib.cma + +native: extLib.cmxa + +extLib.cma: $(SRC) + $(OCAMLC) -a -o extLib.cma $(SRC) + +extLib.cmxa: $(SRC) + $(OCAMLOPT) -g -a -o extLib.cmxa $(SRC) + doc: - ocamlc -c $(MODULES:=.mli) + $(OCAMLC) -c $(MODULES:=.mli) mkdir -p doc/ ocamldoc -sort -html -d doc/ $(MODULES:=.mli) cp odoc_style.css doc/style.css @@ -32,3 +44,9 @@ uninstall: clean: rm -f $(wildcard *.cmo) $(wildcard *.cmx) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cma) $(wildcard *.cmxa) $(wildcard *.a) $(wildcard *.lib) $(wildcard *.obj) rm -Rf doc + +.PHONY: all opt bytecode native doc copy install uninstall clean + +Makefile: ; + +$(SRC): ; diff --git a/libs/extlib/rbuffer.ml b/libs/extlib/rbuffer.ml new file mode 100644 index 0000000000000000000000000000000000000000..fe9f0bd752188e0f0b3e4b51233d9bf15b250b03 --- /dev/null +++ b/libs/extlib/rbuffer.ml @@ -0,0 +1,209 @@ +(**************************************************************************) +(* *) +(* Copyright (C) Jean-Christophe Filliatre *) +(* *) +(* This software is free software; you can redistribute it and/or *) +(* modify it under the terms of the GNU Library General Public *) +(* License version 2.1, with the special exception on linking *) +(* described in file LICENSE. *) +(* *) +(* This software 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. *) +(* *) +(**************************************************************************) + +(* Ropes-based implementation of Buffer *) + +type rope = + | Str of string + | App of rope * rope * int (* total length *) + +let rope_empty = Str "" + +let rope_length = function + | Str s -> String.length s + | App (_, _, n) -> n + +let rec rope_nth i = function + | Str s -> + String.unsafe_get s i + | App (l, r, _) -> + let ll = rope_length l in + if i < ll then rope_nth i l else rope_nth (i - ll) r + +type t = { + mutable rope : rope; (* the left part is a rope *) + mutable buffer : string; (* the right part is a buffer... *) + mutable position : int; (* ...with [position] bytes used *) +} + +let create n = + let n = if n < 1 then 1 else n in + let n = if n > Sys.max_string_length then Sys.max_string_length else n in + let s = String.create n in + { rope = rope_empty; buffer = s; position = 0; } + +let reset b = + b.rope <- rope_empty; + b.position <- 0 + +let clear = reset + +let length b = + rope_length b.rope + b.position + +(* [blit s i r] blits the contents of rope [r] in string [s] at index [i] *) +let rec blit_rope s i = function + | Str str -> + String.blit str 0 s i (String.length str) + | App (l, r, _) -> + let ll = rope_length l in + blit_rope s i l; + blit_rope s (i + ll) r + +(* rename contents to unsafe_contents to avoid accidental usage *) +let unsafe_contents b = + let r = rope_length b.rope in + let n = b.position in + let len = r + n in + if len > Sys.max_string_length then invalid_arg "Rbuffer.contents"; + let s = String.create len in + blit_rope s 0 b.rope; + String.blit b.buffer 0 s r n; + s + +(* [blit_subrope s i ofs len] blits the subrope [r[ofs..ofs+len-1]] in string + [s] at index [i] *) +let rec blit_subrope s i ofs len = function + | Str str -> + assert (ofs >= 0 && ofs + len <= String.length str); + String.blit str ofs s i len + | App (l, r, _) -> + let ll = rope_length l in + if ofs + len <= ll then + blit_subrope s i ofs len l + else if ofs >= ll then + blit_subrope s i (ofs - ll) len r + else begin + let lenl = ll - ofs in + blit_subrope s i ofs lenl l; + blit_subrope s (i + lenl) 0 (len - lenl) r + end + +let sub b ofs len = + let r = rope_length b.rope in + if len > Sys.max_string_length || + ofs < 0 || len < 0 || ofs > r + b.position - len + then invalid_arg "Buffer.sub"; + let s = String.create len in + if ofs + len <= r then + blit_subrope s 0 ofs len b.rope + else if ofs >= r then + String.blit b.buffer (ofs - r) s 0 len + else begin + blit_subrope s 0 ofs (r - ofs) b.rope; + String.blit b.buffer 0 s (r - ofs) (ofs + len - r) + end; + s + +let nth b i = + let r = rope_length b.rope in + if i < 0 || i >= r + b.position then invalid_arg "Buffer.nth"; + if i < r then rope_nth i b.rope else String.unsafe_get b.buffer (i - r) + +(* moves the data in [b.buffer], if any, to the rope; ensures [b.position=0] *) +let move_buffer_to_rope b = + let pos = b.position in + if pos > 0 then begin + let n = String.length b.buffer in + if pos = n then begin + (* whole buffer goes to the rope; faster to allocate a new buffer *) + b.rope <- App (b.rope, Str b.buffer, rope_length b.rope + pos); + b.buffer <- String.create n + end else begin + (* part of the buffer goes to the rope; easier to copy it *) + b.rope <- App (b.rope, Str (String.sub b.buffer 0 pos), + rope_length b.rope + pos) + end; + b.position <- 0 + end + +let add_char b c = + if b.position = String.length b.buffer then move_buffer_to_rope b; + let pos = b.position in + b.buffer.[pos] <- c; + b.position <- pos + 1 + +(* allocates space for [len] bytes and returns the corresponding place + (as a string and an offset within that string) *) +let alloc b len = + let n = String.length b.buffer in + let pos = b.position in + let len' = pos + len in + if len' <= n then begin + (* fits in the buffer *) + b.position <- len'; + b.buffer, pos + end else if len' <= Sys.max_string_length then begin + (* buffer and len fit in a new string, allocated in the rope *) + let str = String.create len' in + String.blit b.buffer 0 str 0 pos; + b.rope <- App (b.rope, Str str, rope_length b.rope + len'); + b.position <- 0; + str, pos + end else begin + (* buffer and len require two strings, allocated in the rope *) + let str = String.create len in + b.rope <- App (b.rope, + App (Str (String.sub b.buffer 0 pos), Str str, len'), + rope_length b.rope + len'); + b.position <- 0; + str, 0 + end + +let safe_add_substring b s offset len = + let str, pos = alloc b len in + String.blit s offset str pos len + +let add_substring b s offset len = + if offset < 0 || len < 0 || offset > String.length s - len + then invalid_arg "Buffer.add_substring"; + safe_add_substring b s offset len + +let add_string b s = + safe_add_substring b s 0 (String.length s) + +let add_buffer b b2 = + if b.position > 0 then move_buffer_to_rope b; + (* now we have b.position = 0 *) + b.rope <- App (b.rope, b2.rope, rope_length b.rope + rope_length b2.rope); + add_substring b b2.buffer 0 b2.position + +let rec add_channel b ic len = + if len <= Sys.max_string_length then begin + let str, pos = alloc b len in + really_input ic str pos len + end else begin + let str, pos = alloc b Sys.max_string_length in + really_input ic str pos Sys.max_string_length; + add_channel b ic (len - Sys.max_string_length) + end + +let output_buffer oc b = + let rec output_rope = function + | Str s -> output oc s 0 (String.length s) + | App (l, r, _) -> output_rope l; output_rope r + in + output_rope b.rope; + output oc b.buffer 0 b.position + +open Format + +let print fmt b = + let rec print_rope = function + | Str s -> pp_print_string fmt s + | App (l, r, _) -> print_rope l; print_rope r + in + print_rope b.rope; + pp_print_string fmt (String.sub b.buffer 0 b.position) diff --git a/libs/extlib/rbuffer.mli b/libs/extlib/rbuffer.mli new file mode 100644 index 0000000000000000000000000000000000000000..90725fe800f3514b8195919d29f1504e7e685eff --- /dev/null +++ b/libs/extlib/rbuffer.mli @@ -0,0 +1,39 @@ +(**************************************************************************) +(* *) +(* Copyright (C) Jean-Christophe Filliatre *) +(* *) +(* This software is free software; you can redistribute it and/or *) +(* modify it under the terms of the GNU Library General Public *) +(* License version 2.1, with the special exception on linking *) +(* described in file LICENSE. *) +(* *) +(* This software 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. *) +(* *) +(**************************************************************************) + +(* Ropes-based implementation of Buffer *) + +type t + +val create : int -> t +val reset : t -> unit +val clear : t -> unit +val length : t -> int + +val unsafe_contents : t -> string + +val sub : t -> int -> int -> string +val nth : t -> int -> char + + +val add_char : t -> char -> unit + +val add_substring : t -> string -> int -> int -> unit +val add_string : t -> string -> unit +val add_buffer : t -> t -> unit + +val add_channel : t -> in_channel -> int -> unit + +val output_buffer : out_channel -> t -> unit diff --git a/libs/ilib/Makefile b/libs/ilib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6317f3f7c198948ae54ace55c6aac2d6f6c3685d --- /dev/null +++ b/libs/ilib/Makefile @@ -0,0 +1,26 @@ +OCAMLOPT=ocamlopt +OCAMLC=ocamlc + +SRCS=peData.ml peReader.ml peWriter.ml ilMeta.mli ilData.mli ilMetaTools.ml ilMetaDebug.ml ilMetaReader.ml + +all: native bytecode + +native: il.cmxa +bytecode: il.cma + +il.cmxa: $(SRCS) + $(OCAMLOPT) -g -I ../extlib -a -o il.cmxa $(SRCS) + +il.cma: $(SRCS) + $(OCAMLC) -g -I ../extlib -a -o il.cma $(SRCS) + +dump: il.cmxa dump.ml peDataDebug.ml ilMetaDebug.ml + $(OCAMLOPT) -g -I ../extlib -o dump ../extlib/extLib.cmxa il.cmxa peDataDebug.ml dump.ml + +clean: + rm -f il.cma il.cmxa il.lib il.a $(wildcard *.cmx) $(wildcard *.cmo) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) dump + +.PHONY: all bytecode native clean + +Makefile: ; +$(SRCS): ; diff --git a/libs/ilib/dump.ml b/libs/ilib/dump.ml new file mode 100644 index 0000000000000000000000000000000000000000..6a2d1f764b8494cc233ec91d059182b4971fac2d --- /dev/null +++ b/libs/ilib/dump.ml @@ -0,0 +1,38 @@ +open PeDataDebug;; +open PeData;; +open PeReader;; +open Printf;; +open IlData;; +open IlMetaTools;; +open IlMetaDebug;; + +let main () = + if Array.length Sys.argv <> 2 then + print_endline "Usage: dump " + else begin + let r = create_r (open_in Sys.argv.(1)) PMap.empty in + let ctx = read r in + let pe = ctx.pe_header in + print_endline (coff_header_s pe.pe_coff_header); + print_endline (pe_header_s pe); + let idata = read_idata ctx in + List.iter (fun t -> print_endline (idata_table_s t)) idata; + let clr_header = read_clr_header ctx in + print_endline (clr_header_s (clr_header)); + let cache = IlMetaReader.create_cache () in + let meta = IlMetaReader.read_meta_tables ctx clr_header cache in + Hashtbl.iter (fun path _ -> + print_endline ("\n\nclass " ^ path_s path ^ ": "); + let cls = convert_class meta path in + List.iter (fun t -> printf "%d: <%s> " t.tnumber (if t.tname = None then "_" else Option.get t.tname)) cls.ctypes; + printf "\n\tis nested: %s - %s\n" (string_of_bool (cls.cenclosing <> None)) (if cls.cenclosing = None then "None" else path_s (Option.get cls.cenclosing)); + print_endline "\tfields:"; + List.iter (fun f -> printf "\t\t%s : %s\n" f.fname (ilsig_s f.fsig.ssig)) cls.cfields; + print_endline "\tmethods:"; + List.iter (fun m -> printf "\t\t%s : %s\n" m.mname (ilsig_s m.msig.ssig)) cls.cmethods; + print_endline "\tprops:"; + List.iter (fun p -> printf "\t\t%s : %s\n" p.pname (ilsig_s p.psig.ssig)) cls.cprops; + ) meta.il_typedefs + end;; + +main() diff --git a/libs/ilib/ilData.mli b/libs/ilib/ilData.mli new file mode 100644 index 0000000000000000000000000000000000000000..d8776bdf9bb9cda3dbb2e06f12f510eb19a2a2d8 --- /dev/null +++ b/libs/ilib/ilData.mli @@ -0,0 +1,115 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) +open IlMeta;; + +type ilpath = string list * string list * string + +type ilsig = IlMeta.ilsig + +and ilsig_norm = + | LVoid | LBool | LChar + | LInt8 | LUInt8 | LInt16 + | LUInt16 | LInt32 | LUInt32 + | LInt64 | LUInt64 | LFloat32 + | LFloat64 | LString | LObject + | LPointer of ilsig_norm + | LTypedReference | LIntPtr | LUIntPtr + | LManagedPointer of ilsig_norm + | LValueType of ilpath * ilsig_norm list + | LClass of ilpath * ilsig_norm list + | LTypeParam of int + | LMethodTypeParam of int + | LVector of ilsig_norm + | LArray of ilsig_norm * (int option * int option) array + | LMethod of callconv list * ilsig_norm * (ilsig_norm list) + | LSentinel + +and ilsig_t = { + snorm : ilsig_norm; + ssig : ilsig; +} + +type ilversion = int * int (* minor + major *) + +type ilclass = { + cpath : ilpath; + cflags : type_def_flags; + csuper : ilsig_t option; + cfields : ilfield list; + cmethods : ilmethod list; + cimplements : ilsig_t list; + ctypes : type_param list; + cprops : ilprop list; + cevents : ilevent list; + (* cevents : *) + cenclosing : ilpath option; + cnested : ilpath list; + cattrs : meta_custom_attribute list; +} + +and type_param = { + tnumber : int; + tflags : generic_flags; + tname : string option; + tconstraints : ilsig_t list; +} + +and ilevent = { + ename : string; + eflags : event_flags; + eadd : (string * method_flags) option; + eremove : (string * method_flags) option; + eraise : (string * method_flags) option; + esig : ilsig_t; +} + +and ilfield = { + fname : string; + fflags : field_flags; + fsig : ilsig_t; + fconstant : constant option; +} + +and ilmethod = { + mname : string; + mflags : method_flags; + msig : ilsig_t; + margs : ilmethod_arg list; + mret : ilsig_t; + moverride : (ilpath * string) option; (* method_impl *) + (* refers to the signature of the declaring class *) + mtypes : type_param list; + msemantics : semantic_flags; +} + +and ilmethod_arg = string * param_flags * ilsig_t + +and ilprop = { + pname : string; + psig : ilsig_t; + pflags : property_flags; + pget : (string * method_flags) option; + pset : (string * method_flags) option; +} + +type ilctx = { + il_tables : (clr_meta DynArray.t) array; + il_relations : (meta_pointer, clr_meta) Hashtbl.t; + il_typedefs : (ilpath, meta_type_def) Hashtbl.t; +} diff --git a/libs/ilib/ilMeta.mli b/libs/ilib/ilMeta.mli new file mode 100644 index 0000000000000000000000000000000000000000..abe9bedae0deed0f9356c081ab318974f963c078 --- /dev/null +++ b/libs/ilib/ilMeta.mli @@ -0,0 +1,1204 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +open PeData;; + +(* useful types for describing CLI metadata *) +type guid = string + (* reference from the #GUID stream *) +type stringref = string + (* reference from the #Strings stream *) +type blobref = string + (* reference from the #Blob stream *) +type id = stringref + (* a stringref that references an identifier. *) + (* must begin with an alphabetic character, or the following characters: *) + (* #, $, @, _ *) + (* and continue with alphanumeric characters or one of the following: *) + (* ?, $, @, _, ` *) + +type ns = id list + +type rid = int + (* record id on a specified meta table *) + +type clr_meta_idx = + (* strongly-type each table index *) + | IModule | ITypeRef | ITypeDef | IFieldPtr + | IField | IMethodPtr | IMethod | IParamPtr + | IParam | IInterfaceImpl | IMemberRef | IConstant + | ICustomAttribute | IFieldMarshal | IDeclSecurity + | IClassLayout | IFieldLayout | IStandAloneSig + | IEventMap | IEventPtr | IEvent | IPropertyMap + | IPropertyPtr | IProperty | IMethodSemantics + | IMethodImpl | IModuleRef | ITypeSpec | IImplMap + | IFieldRVA | IENCLog | IENCMap | IAssembly + | IAssemblyProcessor | IAssemblyOS | IAssemblyRef + | IAssemblyRefProcessor | IAssemblyRefOS + | IFile | IExportedType | IManifestResource | INestedClass + | IGenericParam | IMethodSpec | IGenericParamConstraint + (* reserved metas *) + | IR0x2D | IR0x2E | IR0x2F + | IR0x30 | IR0x31 | IR0x32 | IR0x33 | IR0x34 | IR0x35 | IR0x36 | IR0x37 + | IR0x38 | IR0x39 | IR0x3A | IR0x3B | IR0x3C | IR0x3D | IR0x3E | IR0x3F + (* coded tokens *) + | ITypeDefOrRef | IHasConstant | IHasCustomAttribute + | IHasFieldMarshal | IHasDeclSecurity | IMemberRefParent + | IHasSemantics | IMethodDefOrRef | IMemberForwarded | IImplementation + | ICustomAttributeType | IResolutionScope | ITypeOrMethodDef + +type meta_pointer = clr_meta_idx * rid + (* generic reference to the meta table *) + +(* starting with all annotations of special coded types *) +type type_def_or_ref = clr_meta +and has_const = clr_meta +and has_custom_attribute = clr_meta +and has_field_marshal = clr_meta +and has_decl_security = clr_meta +and member_ref_parent = clr_meta +and has_semantics = clr_meta +and method_def_or_ref = clr_meta +and member_forwarded = clr_meta +and implementation = clr_meta +and custom_attribute_type = clr_meta +and resolution_scope = clr_meta +and type_or_method_def = clr_meta + +and clr_meta = + | Module of meta_module + (* the current module descriptor *) + | TypeRef of meta_type_ref + (* class reference descriptors *) + | TypeDef of meta_type_def + (* class or interface definition descriptors *) + | FieldPtr of meta_field_ptr + (* a class-to-fields lookup table - does not exist in optimized metadatas *) + | Field of meta_field + (* field definition descriptors *) + | MethodPtr of meta_method_ptr + (* a class-to-methods lookup table - does not exist in optimized metadatas *) + | Method of meta_method + (* method definition descriptors *) + | ParamPtr of meta_param_ptr + (* a method-to-parameters lookup table - does not exist in optimized metadatas *) + | Param of meta_param + (* parameter definition descriptors *) + | InterfaceImpl of meta_interface_impl + (* interface implementation descriptors *) + | MemberRef of meta_member_ref + (* member (field or method) reference descriptors *) + | Constant of meta_constant + (* constant value that map the default values stored in the #Blob stream to *) + (* respective fields, parameters and properties *) + | CustomAttribute of meta_custom_attribute + (* custom attribute descriptors *) + | FieldMarshal of meta_field_marshal + (* field or parameter marshaling descriptors for managed/unmanaged interop *) + | DeclSecurity of meta_decl_security + (* security descriptors *) + | ClassLayout of meta_class_layout + (* class layout descriptors that hold information about how the loader should lay out respective classes *) + | FieldLayout of meta_field_layout + (* field layout descriptors that specify the offset or oridnal of individual fields *) + | StandAloneSig of meta_stand_alone_sig + (* stand-alone signature descriptors. used in two capacities: *) + (* as composite signatures of local variables of methods *) + (* and as parameters of the call indirect (calli) IL instruction *) + | EventMap of meta_event_map + (* a class-to-events mapping table. exists also in optimized metadatas *) + | EventPtr of meta_event_ptr + (* an event map-to-events lookup table - does not exist in optimized metadata *) + | Event of meta_event + (* event descriptors *) + | PropertyMap of meta_property_map + (* a class-to-properties mapping table. exists also in optimized metadatas *) + | PropertyPtr of meta_property_ptr + (* a property map-to-properties lookup table - does not exist in optimized metadata *) + | Property of meta_property + (* property descriptors *) + | MethodSemantics of meta_method_semantics + (* method semantics descriptors that hold information about which method is associated *) + (* with a specific property or event and in what capacity *) + | MethodImpl of meta_method_impl + (* method implementation descriptors *) + | ModuleRef of meta_module_ref + (* module reference descriptors *) + | TypeSpec of meta_type_spec + (* Type specification descriptors *) + | ImplMap of meta_impl_map + (* implementation map descriptors used for platform invocation (P/Invoke) *) + | FieldRVA of meta_field_rva + (* field-to-data mapping descriptors *) + | ENCLog of meta_enc_log + (* edit-and-continue log descriptors that hold information about what changes *) + (* have been made to specific metadata items during in-memory editing *) + (* this table does not exist on optimized metadata *) + | ENCMap of meta_enc_map + (* edit-and-continue mapping descriptors. does not exist on optimized metadata *) + | Assembly of meta_assembly + (* the current assembly descriptor, which should appear only in the prime module metadata *) + | AssemblyProcessor of meta_assembly_processor | AssemblyOS of meta_assembly_os + (* unused *) + | AssemblyRef of meta_assembly_ref + (* assembly reference descriptors *) + | AssemblyRefProcessor of meta_assembly_ref_processor | AssemblyRefOS of meta_assembly_ref_os + (* unused *) + | File of meta_file + (* file descriptors that contain information about other files in the current assembly *) + | ExportedType of meta_exported_type + (* exported type descriptors that contain information about public classes *) + (* exported by the current assembly, which are declared in other modules of the assembly *) + (* only the prime module of the assembly should carry this table *) + | ManifestResource of meta_manifest_resource + (* managed resource descriptors *) + | NestedClass of meta_nested_class + (* nested class descriptors that provide mapping of nested classes to their respective enclosing classes *) + | GenericParam of meta_generic_param + (* type parameter descriptors for generic classes and methods *) + | MethodSpec of meta_method_spec + (* generic method instantiation descriptors *) + | GenericParamConstraint of meta_generic_param_constraint + (* descriptors of constraints specified for type parameters of generic classes and methods *) + | UnknownMeta of int + +(* all fields here need to be mutable, as they will first be initialized empty *) + +and meta_root = { + root_id : int; +} + +and meta_root_ptr = { + ptr_id : int; + ptr_to : meta_root; +} + +and meta_module = { + mutable md_id : int; + mutable md_generation : int; + mutable md_name : id; + mutable md_vid : guid; + mutable md_encid : guid; + mutable md_encbase_id : guid; +} + +and meta_type_ref = { + mutable tr_id : int; + mutable tr_resolution_scope : resolution_scope; + mutable tr_name : id; + mutable tr_namespace : ns; +} + +and meta_type_def = { + mutable td_id : int; + mutable td_flags : type_def_flags; + mutable td_name : id; + mutable td_namespace : ns; + mutable td_extends : type_def_or_ref option; + mutable td_field_list : meta_field list; + mutable td_method_list : meta_method list; + + (* extra field *) + mutable td_extra_enclosing : meta_type_def option; +} + +and meta_field_ptr = { + mutable fp_id : int; + mutable fp_field : meta_field; +} + +and meta_field = { + mutable f_id : int; + mutable f_flags : field_flags; + mutable f_name : id; + mutable f_signature : ilsig; +} + +and meta_method_ptr = { + mutable mp_id : int; + mutable mp_method : meta_method; +} + +and meta_method = { + mutable m_id : int; + mutable m_rva : rva; + mutable m_flags : method_flags; + mutable m_name : id; + mutable m_signature : ilsig; + mutable m_param_list : meta_param list; (* rid: Param *) + + (* extra field *) + mutable m_declaring : meta_type_def option; +} + +and meta_param_ptr = { + mutable pp_id : int; + mutable pp_param : meta_param; +} + +and meta_param = { + mutable p_id : int; + mutable p_flags : param_flags; + mutable p_sequence : int; + (* 0 means return value *) + mutable p_name : id; +} + +and meta_interface_impl = { + mutable ii_id : int; + mutable ii_class : meta_type_def; (* TypeDef rid *) + mutable ii_interface : type_def_or_ref; +} + +and meta_member_ref = { + mutable memr_id : int; + mutable memr_class : member_ref_parent; + mutable memr_name : id; + mutable memr_signature : ilsig; +} + +and meta_constant = { + mutable c_id : int; + mutable c_type : constant_type; + mutable c_parent : has_const; + mutable c_value : constant; +} + +and named_attribute = bool * string * instance (* is_property * name * instance *) + +and meta_custom_attribute = { + mutable ca_id : int; + mutable ca_parent : has_custom_attribute; + mutable ca_type : custom_attribute_type; + mutable ca_value : (instance list * named_attribute list) option; + (* can be 0 *) +} + +and meta_field_marshal = { + mutable fm_id : int; + mutable fm_parent : has_field_marshal; + mutable fm_native_type : nativesig; +} + +and meta_decl_security = { + mutable ds_id : int; + mutable ds_action : action_security; + mutable ds_parent : has_decl_security; + mutable ds_permission_set : blobref; + (* an xml with the permission set *) +} + +and meta_class_layout = { + mutable cl_id : int; + mutable cl_packing_size : int; + (* power of two; from 1 through 128 *) + mutable cl_class_size : int; + mutable cl_parent : meta_type_def; (* TypeDef rid *) +} + +and meta_field_layout = { + mutable fl_id : int; + mutable fl_offset : int; + (* offset in bytes or ordinal *) + mutable fl_field : meta_field; (* Field rid *) +} + +and meta_stand_alone_sig = { + mutable sa_id : int; + mutable sa_signature : ilsig; +} + +and meta_event_map = { + mutable em_id : int; + mutable em_parent : meta_type_def; (* TypeDef rid *) + mutable em_event_list : meta_event list; (* Event rid *) +} + +and meta_event_ptr = { + mutable ep_id : int; + mutable ep_event : meta_event; (* Event rid *) +} + +and meta_event = { + mutable e_id : int; + mutable e_flags : event_flags; + mutable e_name : stringref; + mutable e_event_type : type_def_or_ref; +} + +and meta_property_map = { + mutable pm_id : int; + mutable pm_parent : meta_type_def; (* TypeDef rid *) + mutable pm_property_list : meta_property list; (* Property rid *) +} + +and meta_property_ptr = { + mutable prp_id : int; + mutable prp_property : meta_property; (* Property rid *) +} + +and meta_property = { + mutable prop_id : int; + mutable prop_flags : property_flags; + mutable prop_name : stringref; + mutable prop_type : ilsig; +} + +and meta_method_semantics = { + mutable ms_id : int; + mutable ms_semantic : semantic_flags; + mutable ms_method : meta_method; (* Method rid *) + mutable ms_association : has_semantics; +} + +and meta_method_impl = { + mutable mi_id : int; + mutable mi_class : meta_type_def; (* TypeDef rid *) + mutable mi_method_body : method_def_or_ref; + (* overriding method *) + mutable mi_method_declaration : method_def_or_ref; + (* overriden method *) +} + +and meta_module_ref = { + mutable modr_id : int; + mutable modr_name : stringref; +} + +and meta_type_spec = { + mutable ts_id : int; + mutable ts_signature : ilsig; +} + +(* reserved ? *) +and meta_enc_log = { + mutable el_id : int; + mutable el_token : to_det; + mutable el_func_code : to_det; +} + +and meta_impl_map = { + mutable im_id : int; + mutable im_flags : impl_flags; (* mapping_flags *) + mutable im_forwarded : member_forwarded; (* method only *) + mutable im_import_name : stringref; + mutable im_import_scope : meta_module_ref; (* ModuleRef rid *) +} + +(* reserved ? *) +and meta_enc_map = { + mutable encm_id : int; + mutable encm_token : to_det; +} + +and meta_field_rva = { + mutable fr_id : int; + mutable fr_rva : rva; + mutable fr_field : meta_field; (* Field rid *) +} + +and meta_assembly = { + mutable a_id : int; + mutable a_hash_algo : hash_algo; + mutable a_major : int; + mutable a_minor : int; + mutable a_build : int; + mutable a_rev : int; + mutable a_flags : assembly_flags; (* assembly_flags *) + mutable a_public_key : blobref; + mutable a_name : stringref; + mutable a_locale : stringref; +} + +(* unused *) +and meta_assembly_processor = { + mutable ap_id : int; + mutable ap_processor : to_det; +} + +(* unused *) +and meta_assembly_os = { + mutable aos_id : int; + mutable aos_platform_id : to_det; + mutable aos_major_version : to_det; + mutable aos_minor_version : to_det; +} + +and meta_assembly_ref = { + mutable ar_id : int; + mutable ar_major : int; + mutable ar_minor : int; + mutable ar_build : int; + mutable ar_rev : int; + mutable ar_flags : assembly_flags; + mutable ar_public_key : blobref; + mutable ar_name : stringref; (* no path, no extension *) + mutable ar_locale : stringref; + mutable ar_hash_value : blobref; +} + +(* unused *) +and meta_assembly_ref_processor = { + mutable arp_id : int; + mutable arp_processor : to_det; + mutable arp_assembly_ref : meta_assembly_ref; (* AssemblyRef rid *) +} + +(* unused *) +and meta_assembly_ref_os = { + mutable aros_id : int; + mutable aros_platform_id : to_det; + mutable aros_major : int; + mutable aros_minor : int; + mutable aros_assembly_ref : meta_assembly_ref; (* AssemblyRef rid *) +} + +and meta_file = { + mutable file_id : int; + mutable file_flags : file_flag; (* file_flags *) + mutable file_name : stringref; (* no path; only file name *) + mutable file_hash_value : blobref; +} + +and meta_exported_type = { + mutable et_id : int; + mutable et_flags : type_def_flags; + mutable et_type_def_id : int; + (* TypeDef token in another module *) + mutable et_type_name : stringref; + mutable et_type_namespace : ns; + mutable et_implementation : implementation; +} + +and meta_manifest_resource = { + mutable mr_id : int; + mutable mr_offset : int; + mutable mr_flags : manifest_resource_flag; (* manifest_resource_flags *) + mutable mr_name : stringref; + mutable mr_implementation : implementation option; +} + +and meta_nested_class = { + mutable nc_id : int; + mutable nc_nested : meta_type_def; (* TypeDef rid *) + mutable nc_enclosing : meta_type_def; (* TypeDef rid *) +} + +and meta_generic_param = { + mutable gp_id : int; + mutable gp_number : int; (* ordinal *) + mutable gp_flags : generic_flags; + mutable gp_owner : type_or_method_def; + (* generic type or method *) + mutable gp_name : stringref option; +} + +and meta_method_spec = { + mutable mspec_id : int; + mutable mspec_method : method_def_or_ref; + (* instantiated method *) + mutable mspec_instantiation : ilsig; + (* instantiated signature *) +} + +and meta_generic_param_constraint = { + mutable gc_id : int; + mutable gc_owner : meta_generic_param; (* GenericParam rid *) + (* constrained parameter *) + mutable gc_constraint : type_def_or_ref; + (* type the parameter must extend or implement *) +} + +and to_det = int + +and not_implemented = int + +and constant = + | IBool of bool + | IChar of int + | IByte of int + | IShort of int + | IInt of int32 + | IInt64 of int64 + | IFloat32 of float + | IFloat64 of float + | IString of string + | INull + +and instance = + | InstConstant of constant + | InstBoxed of instance + | InstType of string + | InstArray of instance list + | InstEnum of int + +and constant_type = + | CBool (* 0x2 *) + | CChar (* 0x3 *) + | CInt8 (* 0x4 *) + | CUInt8 (* 0x5 *) + | CInt16 (* 0x6 *) + | CUInt16 (* 0x7 *) + | CInt32 (* 0x8 *) + | CUInt32 (* 0x9 *) + | CInt64 (* 0xA *) + | CUInt64 (* 0xB *) + | CFloat32 (* 0xC *) + | CFloat64 (* 0xD *) + | CString (* 0xE *) + | CNullRef (* 0x12 *) + (* null object reference - the value of the constant *) + (* of this type must be a 4-byte integer containing 0 *) + +and type_def_vis = + (* visibility flags - mask 0x7 *) + | VPrivate (* 0x0 *) + (* type is not visible outside the assembly. default *) + | VPublic (* 0x1 *) + (* type visible outside the assembly *) + | VNestedPublic (* 0x2 *) + (* the nested type has public visibility *) + | VNestedPrivate (* 0x3 *) + (* nested type has private visibility - it's not visible outside the enclosing class *) + | VNestedFamily (* 0x4 *) + (* nested type has family visibility - it's visible to descendants of the enclosing class only *) + | VNestedAssembly (* 0x5 *) + (* nested type visible within the assembly only *) + | VNestedFamAndAssem (* 0x6 *) + (* nested type is visible to the descendants of the enclosing class residing in the same assembly *) + | VNestedFamOrAssem (* 0x7 *) + (* nested type is visible to the descendants of the enclosing class either within *) + (* or outside the assembly and to every type within the assembly *) + +and type_def_layout = + (* layout flags - mask 0x18 *) + | LAuto (* 0x0 *) + (* type fields are laid out automatically *) + | LSequential (* 0x8 *) + (* loader must preserve the order of the instance fields *) + | LExplicit (* 0x10 *) + (* type layout is specified explicitly *) + +and type_def_semantics = + (* semantics flags - mask 0x5A0 *) + | SInterface (* 0x20 *) + (* type is an interface. If specified, the default parent is set to nil *) + | SAbstract (* 0x80 *) + | SSealed (* 0x100 *) + | SSpecialName (* 0x400 *) + (* type has a special name. how special depends on the name itself *) + (* e.g. .ctor or .cctor *) + +and type_def_impl = + (* type implementation flags - mask 0x103000 *) + | IImport (* 0x1000 *) + (* the type is imported from a COM type library *) + | ISerializable (* 0x2000 *) + (* the type can be serialized into sequential data *) + | IBeforeFieldInit (* 0x00100000 *) + (* the type can be initialized any time before the first access *) + (* to a static field. *) + +and type_def_string = + (* string formatting flags - mask 0x00030000 *) + | SAnsi (* 0x0 *) + (* managed strings are marshaled to and from ANSI strings *) + | SUnicode (* 0x00010000 *) + (* managed strings are marshaled to and from UTF-16 *) + | SAutoChar (* 0x00020000 *) + (* marshaling is defined by the underlying platform *) + +and type_def_flags = { + tdf_vis : type_def_vis; + tdf_layout : type_def_layout; + tdf_semantics : type_def_semantics list; + tdf_impl : type_def_impl list; + tdf_string : type_def_string; +} + +and field_access = + (* access flags - mask 0x07 *) + | FAPrivateScope (* 0x0 *) + (* default - exempt from the requirement of having a unique triad of owner, name and signature *) + (* so it must always be referenced by a FieldDef token and never by a MemberRef *) + (* privatescope fields are accessible from anywhere within the current module *) + | FAPrivate (* 0x1 *) + (* field is accessible from its owner and from classes nested in the field's owner. *) + (* global private fields are accessible from anywhere within current module *) + | FAFamAndAssem (* 0x2 *) + (* accessible from types belonging to the owner's family defined in the current assembly *) + (* family means the type itself and all its descendants *) + | FAAssembly (* 0x3 *) + (* accessible from types defined in the current assembly *) + | FAFamily (* 0x4 *) + (* accessible from the owner's family - defined in this or any other assembly *) + | FAFamOrAssem (* 0x5 *) + (* accessible from the owner's family and from all types defined in the current assembly *) + | FAPublic (* 0x6 *) + (* field is accessible from any type *) + +and field_contract = + (* contract flags - mask 0x02F0 *) + | CStatic (* 0x10 *) + (* static field. global fields must be static *) + | CInitOnly (* 0x20 *) + (* field can be initialized only and cannot be written to later. *) + (* Initialization takes place in an instance constructor (.ctor) for instance fields *) + (* and in a class constructor (.cctor) for static fields. *) + (* this flag is not enforced by the CLR *) + | CLiteral (* 0x40 *) + (* field is a compile-time constant. the loader does not lay out this field *) + (* and does not create an internal handle for it *) + (* it cannot be directly addressed from IL and can only be used as a Reflection reference *) + | CNotSerialized (* 0x80 *) + (* field is not serialized when the owner is remoted *) + | CSpecialName (* 0x200 *) + (* the field is special in some way, as defined by its name *) + (* example is the field value__ of an enumeration type *) + +and field_reserved = + (* reserved flags - cannot be set explicitly. mask 0x9500 *) + | RSpecialName (* 0x400 *) + (* has a special name that is reserved for internal use of the CLR *) + (* two field names are reserved: value_, for instance fields in enumerations *) + (* and _Deleted* for fields marked for deletion but not actually removed from metadata *) + | RMarshal (* 0x1000 *) + (* The field has an associated FieldMarshal record specifying how the field must be *) + (* marshaled when consumed by unmanaged code. *) + | RConstant (* 0x8000 *) + (* field has an associated Constant record *) + | RFieldRVA (* 0x0100 *) + (* field is mapped to data and has an associated FieldRVA record *) + +and field_flags = { + ff_access : field_access; + ff_contract : field_contract list; + ff_reserved : field_reserved list; +} + +and method_contract = + (* contract flags - mask 0xF0 *) + | CMStatic (* 0x10 *) + | CMFinal (* 0x20 *) + (* must be paired with the virtual flag - otherwise it is meaningless *) + | CMVirtual (* 0x40 *) + | CMHideBySig (* 0x80 *) + (* the method hides all methods of the parent classes that have a matching *) + (* signature and name (as opposed to having a matching name only). ignored by the CLR *) + +and method_vtable = + (* vtable flags - mask 0x300 *) + | VNewSlot (* 0x100 *) + (* a new vtable slot is created, so it doesn't override the old implementation *) + | VStrict (* 0x200 *) + (* virtual method can be overriden only if it is accessible from the overriding class *) + +and method_impl = + (* implementation flags - mask 0x2C08 *) + | IAbstract (* 0x0400 *) + | ISpecialName (* 0x0800 *) + | IPInvokeImpl (* 0x2000 *) + (* the method has an unmanaged implementation and is called through the platform *) + (* invocation mechanism. the rva field must be 0, since the method is implemented externally *) + | IUnmanagedExp (* 0x0008 *) + (* the managed method is exposed as an unmanaged export. not used by the CLR currently *) + +and method_reserved = + (* reserved flags - cannot be set explicitly. mask 0xD000 *) + | RTSpecialName (* 0x1000 *) + (* has a special name: .ctor, .cctor, _VtblGap* and _Deleted* *) + | RHasSecurity (* 0x4000 *) + (* either has an associated DeclSecurity metadata or the custom attribte *) + (* System.Security.SuppressUnmanagedCodeSecurityAttribute *) + | RReqSecObj (* 0x8000 *) + (* this method calls another method containing security code, so it requires *) + (* an additional stack slot for a security object. *) + +and method_code_type = + (* code type - mask 0x3 *) + | CCil (* 0x0 *) + | CNative (* 0x1 *) + (* implemented in native platform-specific code *) + | COptIl (* 0x2 *) + (* optimized il - not supported; must not be set *) + | CRuntime (* 0x3 *) + (* automatically generated by the runtime itself (intrinsic) *) + +and method_code_mngmt = + (* code management - mask 0x4 *) + | MManaged (* 0x0 *) + | MUnmanaged (* 0x4 *) + (* must be paired with the native flag *) + +and method_interop = + (* method implementation and interop - mask 0x10D8 *) + | OForwardRef (* 0x10 *) + (* managed object fiels and edit-and-continue scenarios only *) + | OPreserveSig (* 0x80 *) + (* method signature must not be mangled during interop with classic COM code *) + | OInternalCall (* 0x1000 *) + (* reserved for internal use. if set, RVA must be 0 *) + | OSynchronized (* 0x20 *) + (* automatically insert code to take a lock on entry to the method and release it *) + (* on exit from the method. Value types cannot have this flag set *) + | ONoInlining (* 0x08 *) + (* the runtime is not allowed to inline the method *) + +and method_flags = { + mf_access : field_access; + mf_contract : method_contract list; + mf_vtable : method_vtable list; + mf_impl : method_impl list; + mf_reserved : method_reserved list; + mf_code_type : method_code_type; + mf_code_mngmt : method_code_mngmt; + mf_interop : method_interop list; +} + +and param_io = + (* input/output flags - mask 0x13 *) + | PIn (* 0x1 *) + | POut (* 0x2 *) + | POpt (* 0x10 *) + +and param_reserved = + (* reserved flags - mask 0xF000 *) + | PHasConstant (* 0x1000 *) + (* the parameter has an associated Constant record *) + | PMarshal (* 0x2000 *) + (* the parameter has an associated FieldMarshal record specifying how the parameter *) + (* must be marshaled when consumed by unmanaged code *) + +and param_flags = { + pf_io : param_io list; + pf_reserved : param_reserved list; +} + +and event_flag = + | ESpecialName (* 0x0200 *) + (* event is special *) + | ERTSpecialName (* 0x0400 *) + (* CLI provides special behavior, depending on the name of the event *) + +and event_flags = event_flag list + +and property_flag = + | PSpecialName (* 0x0200 *) + (* property is special *) + | PRTSpecialName (* 0x0400 *) + (* runtime (intrinsic) should check name encoding *) + | PHasDefault (* 0x1000 *) + (* property has default *) + | PUnused (* 0xE9FF *) + (* reserved *) + +and property_flags = property_flag list + +and semantic_flag = + | SSetter (* 0x0001 *) + (* setter for property *) + | SGetter (* 0x0002 *) + (* getter for property *) + | SOther (* 0x0004 *) + (* other method for property or event *) + | SAddOn (* 0x0008 *) + (* addon method for event - refers to the required add_ method for events *) + | SRemoveOn (* 0x0010 *) + (* removeon method for event - refers to the required remove_ method for events *) + | SFire (* 0x0020 *) + (* fire method for event. this refers to the optional raise_ method for events *) + +and semantic_flags = semantic_flag list + +and action_security = + | SecNull + | SecRequest (* 0x1 *) + | SecDemand (* 0x2 *) + | SecAssert (* 0x3 *) + | SecDeny (* 0x4 *) + | SecPermitOnly (* 0x5 *) + | SecLinkCheck (* 0x6 *) + | SecInheritCheck (* 0x7 *) + | SecReqMin (* 0x8 *) + | SecReqOpt (* 0x9 *) + | SecReqRefuse (* 0xA *) + | SecPreJitGrant (* 0xB *) + | SecPreJitDeny (* 0xC *) + | SecNonCasDemand (* 0xD *) + | SecNonCasLinkDemand (* 0xE *) + | SecNonCasInheritance (* 0xF *) + +and impl_charset = + | IDefault (* 0x0 *) + | IAnsi (* 0x2 *) + (* method parameters of type string must be marshaled as ANSI zero-terminated *) + (* strings unless explicitly specified otherwise *) + | IUnicode (* 0x4 *) + (* method parameters of type string must be marshaled as Unicode strings *) + | IAutoChar (* 0x6 *) + (* method parameters of type string must be marshaled as ANSI or Unicode strings *) + (* depending on the platform *) + +and impl_callconv = + | IDefaultCall (* 0x0 *) + | IWinApi (* 0x100 *) + (* the native method uses the calling convention standard for the underlying platform *) + | ICDecl (* 0x200 *) + (* the native method uses the C/C++ style calling convention *) + | IStdCall (* 0x300 *) + (* native method uses the standard Win32 API calling convention *) + | IThisCall (* 0x400 *) + (* native method uses the C++ member method (non-vararg) calling convention *) + | IFastCall (* 0x500 *) + +and impl_flag = + | INoMangle (* 0x1 *) + (* exported method's name must be matched literally *) + | IBestFit (* 0x10 *) + (* allow "best fit" guessing when converting the strings *) + | IBestFitOff (* 0x20 *) + (* disallow "best fit" guessing *) + | ILastErr (* 0x40 *) + (* the native method supports the last error querying by the Win32 API GetLastError *) + | ICharMapError (* 0x1000 *) + (* throw an exception when an unmappable character is encountered in a string *) + | ICharMapErrorOff (* 0x2000 *) + (* don't throw an exception when an unmappable character is encountered *) + +and impl_flags = { + if_charset : impl_charset; + if_callconv : impl_callconv; + if_flags : impl_flag list; +} + +and hash_algo = + | HNone (* 0x0 *) + | HReserved (* 0x8003 *) + (* MD5 ? *) + | HSha1 (* 0x8004 *) + (* SHA1 *) + +and assembly_flag = + | APublicKey (* 0x1 *) + (* assembly reference holds the full (unhashed) public key *) + | ARetargetable (* 0x100 *) + (* implementation of this assembly used at runtime is not expected to match *) + (* the version seen at compile-time *) + | ADisableJitCompileOptimizer (* 0x4000 *) + (* Reserved *) + | AEnableJitCompileTracking (* 0x8000 *) + (* Reserved *) + +and assembly_flags = assembly_flag list + +and file_flag = + | ContainsMetadata (* 0x0 *) + | ContainsNoMetadata (* 0x1 *) + +and manifest_resource_flag = + (* mask 0x7 *) + | RNone (* 0x0 *) + | RPublic (* 0x1 *) + | RPrivate (* 0x2 *) + +and generic_variance = + (* mask 0x3 *) + | VNone (* 0x0 *) + | VCovariant (* 0x1 *) + | VContravariant (* 0x2 *) + +and generic_constraint = + (* mask 0x1C *) + | CInstanceType (* 0x4 *) + (* generic parameter has the special class constraint *) + | CValueType (* 0x8 *) + (* generic parameter has the special valuetype constraint *) + | CDefaultCtor (* 0x10 *) + (* has the special .ctor constraint *) + +and generic_flags = { + gf_variance : generic_variance; + gf_constraint : generic_constraint list; +} + +and ilsig = + (* primitive types *) + | SVoid (* 0x1 *) + | SBool (* 0x2 *) + | SChar (* 0x3 *) + | SInt8 (* 0x4 *) + | SUInt8 (* 0x5 *) + | SInt16 (* 0x6 *) + | SUInt16 (* 0x7 *) + | SInt32 (* 0x8 *) + | SUInt32 (* 0x9 *) + | SInt64 (* 0xA *) + | SUInt64 (* 0xB *) + | SFloat32 (* 0xC *) + | SFloat64 (* 0xD *) + | SString (* 0xE *) + | SPointer of ilsig (* 0xF *) + (* unmanaged pointer to type ( * ) *) + | SManagedPointer of ilsig (* 0x10 *) + (* managed pointer to type ( & ) *) + | SValueType of type_def_or_ref (* 0x11 *) + (* a value type modifier, followed by TypeDef or TypeRef token *) + | SClass of type_def_or_ref (* 0x12 *) + (* a class type modifier, followed by TypeDef or TypeRef token *) + | STypeParam of int (* 0x13 *) + (* generic parameter in a generic type definition. represented by a number *) + | SArray of ilsig * (int option * int option) array (* 0x14 *) + (* ilsig * ( bound * size ) *) + (* a multi-dimensional array type modifier *) + (* encoded like: *) + (* SArray ... + ... *) + (* is the number of dimensions (K>0) *) + (* num of specified sizes for dimensions (N <= K) *) + (* num of lower bounds (M <= K) *) + (* all int values are compressed *) + | SGenericInst of ilsig * (ilsig list) (* 0x15 *) + (* A generic type instantiation. encoded like: *) + (* SGenericInst ... *) + | STypedReference (* 0x16 *) + (* typed reference, carrying both a reference to a type *) + (* and information identifying the referenced type *) + | SIntPtr (* 0x18 *) + (* pointer-sized managed integer *) + | SUIntPtr (* 0x19 *) + (* pointer-size managed unsigned integer *) + (* | SNativeFloat (* 0x1A *) *) + (* refer to http://stackoverflow.com/questions/13961205/native-float-type-usage-in-clr *) + | SFunPtr of callconv list * ilsig * (ilsig list) (* 0x1B *) + (* a pointer to a function, followed by full method signature *) + | SObject (* 0x1C *) + (* System.Object *) + | SVector of ilsig (* 0x1D *) + (* followed by the encoding of the underlying type *) + | SMethodTypeParam of int (* 0x1E *) + (* generic parameter in a generic method definition *) + | SReqModifier of type_def_or_ref * ilsig (* 0x1F *) + (* modreq: required custom modifier : indicate that the item to which they are attached *) + (* must be treated in a special way *) + | SOptModifier of type_def_or_ref * ilsig (* 0x20 *) + (* modopt: optional custom modifier *) + | SSentinel (* 0x41 *) + (* ... - signifies the beginning of optional arguments supplied for a vararg method call *) + (* This can only appear at call site, since varargs optional parameters are not specified *) + (* when a method is declared *) + | SPinned of ilsig (* 0x45 *) + (* pinned reference: it's only applicable to local variables only *) + (* special undocumented (yay) *) + | SType (* 0x50 *) + | SBoxed (* 0x51 *) + | SEnum of string (* 0x55 *) + +and callconv = + | CallDefault (* 0x0 *) + | CallCDecl (* 0x1 *) + | CallStdCall (* 0x2 *) + | CallThisCall (* 0x3 *) + | CallFastCall (* 0x4 *) + | CallVararg (* 0x5 *) + | CallField (* 0x6 *) + (* field call *) + | CallLocal (* 0x7 *) + (* local variable call *) + | CallProp (* 0x8 *) + (* property call *) + | CallUnmanaged (* 0x9 *) + (* unmanaged calling convention. not used *) + | CallGenericInst (* 0xA *) + (* generic instantiation - MethodSpec *) + | CallGeneric of int (* 0x10 *) + (* also contains the number of generic arguments *) + | CallHasThis (* 0x20 *) + (* instance method that has an instance pointer (this) *) + (* as an implicit first argument - ilasm 'instance' *) + | CallExplicitThis (* 0x40 *) + (* the first explicitly specified parameter is the instance pointer *) + (* ilasm 'explicit' *) + +and nativesig = + | NVoid (* 0x01 *) + (* obsolete *) + | NBool (* 0x02 *) + | NInt8 (* 0x03 *) + | NUInt8 (* 0x4 *) + | NInt16 (* 0x5 *) + | NUInt16 (* 0x6 *) + | NInt32 (* 0x7 *) + | NUInt32 (* 0x8 *) + | NInt64 (* 0x9 *) + | NUInt64 (* 0xA *) + | NFloat32 (* 0xB *) + | NFloat64 (* 0xC *) + | NSysChar (* 0xD *) + (* obsolete *) + | NVariant (* 0xE *) + (* obsolete *) + | NCurrency (* 0xF *) + | NPointer (* 0x10 *) + (* obsolete - use NativeInt *) + | NDecimal (* 0x11 *) + (* obsolete *) + | NDate (* 0x12 *) + (* obsolete *) + | NBStr (* 0x13 *) + (* unicode VB-style: used in COM operations *) + | NLPStr (* 0x14 *) + (* pointer to a zero-terminated ANSI string *) + | NLPWStr (* 0x15 *) + (* pointer to a zero-terminated Unicode string *) + | NLPTStr (* 0x16 *) + (* pointer to a zero-terminated ANSI or Unicode string - depends on platform *) + | NFixedString of int (* 0x17 *) + (* fixed-size system string of size bytes; applicable to field marshalling only *) + | NObjectRef (* 0x18 *) + (* obsolete *) + | NUnknown (* 0x19 *) + (* IUnknown interface pointer *) + | NDispatch (* 0x1A *) + (* IDispatch interface pointer *) + | NStruct (* 0x1B *) + (* C-style structure, for marshaling the formatted managed types *) + | NInterface (* 0x1C *) + (* interface pointer *) + | NSafeArray of variantsig (* 0x1D *) + (* safe array of type *) + | NFixedArray of int * variantsig (* 0x1E *) + (* fixed-size array, of size bytes *) + | NIntPointer (* 0x1F *) + (* signed pointer-size integer *) + | NUIntPointer (* 0x20 *) + (* unsigned pointer-sized integer *) + | NNestedStruct (* 0x21 *) + (* obsolete *) + | NByValStr (* 0x22 *) + (* VB-style string in a fixed-length buffer *) + | NAnsiBStr (* 0x23 *) + (* ansi bstr - ANSI VB-style string *) + | NTBStr (* 0x24 *) + (* tbstr - bstr or ansi bstr, depending on the platform *) + | NVariantBool (* 0x25 *) + (* variant bool - 2-byte Boolean: true = -1; false = 0 *) + | NFunctionPtr (* 0x26 *) + | NAsAny (* 0x28 *) + (* as any - object: type defined at run time (?) *) + | NArray of nativesig * int * int * int (* 0x2A *) + (* fixed-size array of a native type *) + (* if size is empty, the size of the native array is derived from the size *) + (* of the managed type being marshaled *) + | NLPStruct (* 0x2B *) + (* pointer to a c-style structure *) + | NCustomMarshaler of string * string (* 0x2C *) + (* custom (, ) *) + | NError (* 0x2D *) + (* maps in32 to VT_HRESULT *) + | NCustom of int + +and variantsig = + | VT_EMPTY (* 0x00 *) + (* No *) + | VT_NULL (* 0x01 *) + (* No null *) + | VT_I2 (* 0x02 *) + (* Yes int16 *) + | VT_I4 (* 0x03 *) + (* Yes int32 *) + | VT_R4 (* 0x04 *) + (* Yes float32 *) + | VT_R8 (* 0x05 *) + (* Yes float64 *) + | VT_CY (* 0x06 *) + (* Yes currency *) + | VT_DATE (* 0x07 *) + (* Yes date *) + | VT_BSTR (* 0x08 *) + (* Yes bstr *) + | VT_DISPATCH (* 0x09 *) + (* Yes idispatch *) + | VT_ERROR (* 0x0A *) + (* Yes error *) + | VT_BOOL (* 0x0B *) + (* Yes bool *) + | VT_VARIANT (* 0x0C *) + (* Yes variant *) + | VT_UNKNOWN (* 0x0D *) + (* Yes iunknown *) + | VT_DECIMAL (* 0x0E *) + (* Yes decimal *) + | VT_I1 (* 0x10 *) + (* Yes int8 *) + | VT_UI1 (* 0x11 *) + (* Yes unsigned int8, uint8 *) + | VT_UI2 (* 0x12 *) + (* Yes unsigned int16, uint16 *) + | VT_UI4 (* 0x13 *) + (* Yes unsigned int32, uint32 *) + | VT_I8 (* 0x14 *) + (* No int64 *) + | VT_UI8 (* 0x15 *) + (* No unsigned int64, uint64 *) + | VT_INT (* 0x16 *) + (* Yes int *) + | VT_UINT (* 0x17 *) + (* Yes unsigned int, uint *) + | VT_VOID (* 0x18 *) + (* No void *) + | VT_HRESULT (* 0x19 *) + (* No hresult *) + | VT_PTR (* 0x1A *) + (* No * *) + | VT_SAFEARRAY (* 0x1B *) + (* No safearray *) + | VT_CARRAY (* 0x1C *) + (* No carray *) + | VT_USERDEFINED (* 0x1D *) + (* No userdefined *) + | VT_LPSTR (* 0x1E *) + (* No lpstr *) + | VT_LPWSTR (* 0x1F *) + (* No lpwstr *) + | VT_RECORD (* 0x24 *) + (* Yes record *) + | VT_FILETIME (* 0x40 *) + (* No filetime *) + | VT_BLOB (* 0x41 *) + (* No blob *) + | VT_STREAM (* 0x42 *) + (* No stream *) + | VT_STORAGE (* 0x43 *) + (* No storage *) + | VT_STREAMED_OBJECT (* 0x44 *) + (* No streamed_object *) + | VT_STORED_OBJECT (* 0x45 *) + (* No stored_object *) + | VT_BLOB_OBJECT (* 0x46 *) + (* No blob_object *) + | VT_CF (* 0x47 *) + (* No cf *) + | VT_CLSID (* 0x48 *) + (* No clsid *) + (* | VT_VECTOR of variantsig (* 0x1000 *) *) + (* (* Yes vector *) *) + (* | VT_ARRAY of variantsig (* 0x2000 *) *) + (* (* Yes [ ] *) *) + (* | VT_BYREF of variantsig (* 0x4000 *) *) + (* (* Yes & *) *) diff --git a/libs/ilib/ilMetaDebug.ml b/libs/ilib/ilMetaDebug.ml new file mode 100644 index 0000000000000000000000000000000000000000..50972581a410ae2b02b76da3c4d357c39b51ea66 --- /dev/null +++ b/libs/ilib/ilMetaDebug.ml @@ -0,0 +1,24 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) +open IlMeta;; +open IlMetaTools;; + +let path_s = IlMetaTools.path_s +let ilsig_s = IlMetaTools.ilsig_s +let instance_s = IlMetaTools.instance_s diff --git a/libs/ilib/ilMetaReader.ml b/libs/ilib/ilMetaReader.ml new file mode 100644 index 0000000000000000000000000000000000000000..3d4a62b1e76ef95c6b640ebeff8384188f3f57d6 --- /dev/null +++ b/libs/ilib/ilMetaReader.ml @@ -0,0 +1,2420 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +open PeData;; +open PeReader;; +open IlMeta;; +open IO;; +open Printf;; +open IlMetaTools;; +open ExtString;; +open IlData;; + +(* *) +let get_field = function + | Field f -> f + | _ -> assert false + +let get_method = function + | Method m -> m + | _ -> assert false + +let get_param = function + | Param p -> p + | _ -> assert false + +let get_type_def = function + | TypeDef p -> p + | _ -> assert false + +let get_event = function + | Event e -> e + | _ -> assert false + +let get_property = function + | Property p -> p + | _ -> assert false + +let get_module_ref = function + | ModuleRef r -> r + | _ -> assert false + +let get_assembly_ref = function + | AssemblyRef r -> r + | _ -> assert false + +let get_generic_param = function + | GenericParam p -> p + | _ -> assert false + +(* decoding helpers *) +let type_def_vis_of_int i = match i land 0x7 with + (* visibility flags - mask 0x7 *) + | 0x0 -> VPrivate (* 0x0 *) + | 0x1 -> VPublic (* 0x1 *) + | 0x2 -> VNestedPublic (* 0x2 *) + | 0x3 -> VNestedPrivate (* 0x3 *) + | 0x4 -> VNestedFamily (* 0x4 *) + | 0x5 -> VNestedAssembly (* 0x5 *) + | 0x6 -> VNestedFamAndAssem (* 0x6 *) + | 0x7 -> VNestedFamOrAssem (* 0x7 *) + | _ -> assert false + +let type_def_layout_of_int i = match i land 0x18 with + (* layout flags - mask 0x18 *) + | 0x0 -> LAuto (* 0x0 *) + | 0x8 -> LSequential (* 0x8 *) + | 0x10 -> LExplicit (* 0x10 *) + | _ -> assert false + +let type_def_semantics_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* semantics flags - mask 0x5A0 *) + | 0x20 -> SInterface (* 0x20 *) + | 0x80 -> SAbstract (* 0x80 *) + | 0x100 -> SSealed (* 0x100 *) + | 0x400 -> SSpecialName (* 0x400 *) + | _ -> assert false) :: acc + else + acc) [] [0x20;0x80;0x100;0x400] + +let type_def_impl_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* type implementation flags - mask 0x103000 *) + | 0x1000 -> IImport (* 0x1000 *) + | 0x2000 -> ISerializable (* 0x2000 *) + | 0x00100000 -> IBeforeFieldInit (* 0x00100000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1000;0x2000;0x00100000] + +let type_def_string_of_int i = match i land 0x00030000 with + (* string formatting flags - mask 0x00030000 *) + | 0x0 -> SAnsi (* 0x0 *) + | 0x00010000 -> SUnicode (* 0x00010000 *) + | 0x00020000 -> SAutoChar (* 0x00020000 *) + | _ -> assert false + +let type_def_flags_of_int i = + { + tdf_vis = type_def_vis_of_int i; + tdf_layout = type_def_layout_of_int i; + tdf_semantics = type_def_semantics_of_int i; + tdf_impl = type_def_impl_of_int i; + tdf_string = type_def_string_of_int i; + } + +let null_type_def_flags = type_def_flags_of_int 0 + +let field_access_of_int i = match i land 0x07 with + (* access flags - mask 0x07 *) + | 0x0 -> FAPrivateScope (* 0x0 *) + | 0x1 -> FAPrivate (* 0x1 *) + | 0x2 -> FAFamAndAssem (* 0x2 *) + | 0x3 -> FAAssembly (* 0x3 *) + | 0x4 -> FAFamily (* 0x4 *) + | 0x5 -> FAFamOrAssem (* 0x5 *) + | 0x6 -> FAPublic (* 0x6 *) + | _ -> assert false + +let field_contract_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* contract flags - mask 0x02F0 *) + | 0x10 -> CStatic (* 0x10 *) + | 0x20 -> CInitOnly (* 0x20 *) + | 0x40 -> CLiteral (* 0x40 *) + | 0x80 -> CNotSerialized (* 0x80 *) + | 0x200 -> CSpecialName (* 0x200 *) + | _ -> assert false) :: acc + else + acc) [] [0x10;0x20;0x40;0x80;0x200] + +let field_reserved_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* reserved flags - cannot be set explicitly. mask 0x9500 *) + | 0x400 -> RSpecialName (* 0x400 *) + | 0x1000 -> RMarshal (* 0x1000 *) + | 0x8000 -> RConstant (* 0x8000 *) + | 0x0100 -> RFieldRVA (* 0x0100 *) + | _ -> assert false) :: acc + else + acc) [] [0x400;0x1000;0x8000;0x100] + +let field_flags_of_int i = + { + ff_access = field_access_of_int i; + ff_contract = field_contract_of_int i; + ff_reserved = field_reserved_of_int i; + } + +let null_field_flags = field_flags_of_int 0 + +let method_contract_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* contract flags - mask 0xF0 *) + | 0x10 -> CMStatic (* 0x10 *) + | 0x20 -> CMFinal (* 0x20 *) + | 0x40 -> CMVirtual (* 0x40 *) + | 0x80 -> CMHideBySig (* 0x80 *) + | _ -> assert false) :: acc + else + acc) [] [0x10;0x20;0x40;0x80] + +let method_vtable_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* vtable flags - mask 0x300 *) + | 0x100 -> VNewSlot (* 0x100 *) + | 0x200 -> VStrict (* 0x200 *) + | _ -> assert false) :: acc + else + acc) [] [0x100;0x200] + +let method_impl_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* implementation flags - mask 0x2C08 *) + | 0x0400 -> IAbstract (* 0x0400 *) + | 0x0800 -> ISpecialName (* 0x0800 *) + | 0x2000 -> IPInvokeImpl (* 0x2000 *) + | 0x0008 -> IUnmanagedExp (* 0x0008 *) + | _ -> assert false) :: acc + else + acc) [] [0x0400;0x0800;0x2000;0x0008] + +let method_reserved_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* reserved flags - cannot be set explicitly. mask 0xD000 *) + | 0x1000 -> RTSpecialName (* 0x1000 *) + | 0x4000 -> RHasSecurity (* 0x4000 *) + | 0x8000 -> RReqSecObj (* 0x8000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1000;0x4000;0x8000] + +let method_code_type_of_int i = match i land 0x3 with + | 0x0 -> CCil (* 0x0 *) + | 0x1 -> CNative (* 0x1 *) + | 0x2 -> COptIl (* 0x2 *) + | 0x3 -> CRuntime (* 0x3 *) + | _ -> assert false + +let method_code_mngmt_of_int i = match i land 0x4 with + | 0x0 -> MManaged (* 0x0 *) + | 0x4 -> MUnmanaged (* 0x4 *) + | _ -> assert false + +let method_interop_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x10 -> OForwardRef (* 0x10 *) + | 0x80 -> OPreserveSig (* 0x80 *) + | 0x1000 -> OInternalCall (* 0x1000 *) + | 0x20 -> OSynchronized (* 0x20 *) + | 0x08 -> ONoInlining (* 0x08 *) + | _ -> assert false) :: acc + else + acc) [] [0x10;0x80;0x1000;0x20;0x08] + +let method_flags_of_int iflags flags = + { + mf_access = field_access_of_int flags; + mf_contract = method_contract_of_int flags; + mf_vtable = method_vtable_of_int flags; + mf_impl = method_impl_of_int flags; + mf_reserved = method_reserved_of_int flags; + mf_code_type = method_code_type_of_int iflags; + mf_code_mngmt = method_code_mngmt_of_int iflags; + mf_interop = method_interop_of_int iflags; + } + +let null_method_flags = method_flags_of_int 0 0 + +let param_io_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* input/output flags - mask 0x13 *) + | 0x1 -> PIn (* 0x1 *) + | 0x2 -> POut (* 0x2 *) + | 0x10 -> POpt (* 0x10 *) + | _ -> assert false) :: acc + else + acc) [] [0x1;0x2;0x10] + +let param_reserved_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* reserved flags - mask 0xF000 *) + | 0x1000 -> PHasConstant (* 0x1000 *) + | 0x2000 -> PMarshal (* 0x2000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1000;0x2000] + +let param_flags_of_int i = + { + pf_io = param_io_of_int i; + pf_reserved = param_reserved_of_int i; + } + +let null_param_flags = param_flags_of_int 0 + +let callconv_of_int i = + let basic = match i land 0xF with + | 0x0 -> CallDefault (* 0x0 *) + | 0x1 -> CallCDecl + | 0x2 -> CallStdCall + | 0x3 -> CallThisCall + | 0x4 -> CallFastCall + | 0x5 -> CallVararg (* 0x5 *) + | 0x6 -> CallField (* 0x6 *) + | 0x7 -> CallLocal (* 0x7 *) + | 0x8 -> CallProp (* 0x8 *) + | 0x9 -> CallUnmanaged (* 0x9 *) + | i -> printf "error 0x%x\n\n" i; assert false + in + match i land 0x20 with + | 0x20 -> + [CallHasThis;basic] + | _ when i land 0x40 = 0x40 -> + [CallExplicitThis;basic] + | _ -> [basic] + +let event_flags_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x0200 -> ESpecialName (* 0x0200 *) + | 0x0400 -> ERTSpecialName (* 0x0400 *) + | _ -> assert false) :: acc + else + acc) [] [0x0200;0x0400] + +let property_flags_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x0200 -> PSpecialName (* 0x0200 *) + | 0x0400 -> PRTSpecialName (* 0x0400 *) + | 0x1000 -> PHasDefault (* 0x1000 *) + | 0xE9FF -> PUnused (* 0xE9FF *) + | _ -> assert false) :: acc + else + acc) [] [0x0200;0x0400;0x1000;0xE9FF] + +let semantic_flags_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x0001 -> SSetter (* 0x0001 *) + | 0x0002 -> SGetter (* 0x0002 *) + | 0x0004 -> SOther (* 0x0004 *) + | 0x0008 -> SAddOn (* 0x0008 *) + | 0x0010 -> SRemoveOn (* 0x0010 *) + | 0x0020 -> SFire (* 0x0020 *) + | _ -> assert false) :: acc + else + acc) [] [0x0001;0x0002;0x0004;0x0008;0x0010;0x0020] + +let impl_charset_of_int = function + | 0x0 -> IDefault (* 0x0 *) + | 0x2 -> IAnsi (* 0x2 *) + | 0x4 -> IUnicode (* 0x4 *) + | 0x6 -> IAutoChar (* 0x6 *) + | _ -> assert false + +let impl_callconv_of_int = function + | 0x0 -> IDefaultCall (* 0x0 *) + | 0x100 -> IWinApi (* 0x100 *) + | 0x200 -> ICDecl (* 0x200 *) + | 0x300 -> IStdCall (* 0x300 *) + | 0x400 -> IThisCall (* 0x400 *) + | 0x500 -> IFastCall (* 0x500 *) + | _ -> assert false + +let impl_flag_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x1 -> INoMangle (* 0x1 *) + | 0x10 -> IBestFit (* 0x10 *) + | 0x20 -> IBestFitOff (* 0x20 *) + | 0x40 -> ILastErr (* 0x40 *) + | 0x1000 -> ICharMapError (* 0x1000 *) + | 0x2000 -> ICharMapErrorOff (* 0x2000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1;0x10;0x20;0x40;0x1000;0x2000] + +let impl_flags_of_int i = + { + if_charset = impl_charset_of_int (i land 0x6); + if_callconv = impl_callconv_of_int (i land 0x700); + if_flags = impl_flag_of_int i; + } + +let null_impl_flags = impl_flags_of_int 0 + +let assembly_flags_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x1 -> APublicKey (* 0x1 *) + | 0x100 -> ARetargetable (* 0x100 *) + | 0x4000 -> ADisableJitCompileOptimizer (* 0x4000 *) + | 0x8000 -> AEnableJitCompileTracking (* 0x8000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1;0x100;0x4000;0x8000] + +let hash_algo_of_int = function + | 0x0 -> HNone (* 0x0 *) + | 0x8003 -> HReserved (* 0x8003 *) + | 0x8004 -> HSha1 (* 0x8004 *) + | _ -> assert false + +let file_flag_of_int = function + | 0x0 -> ContainsMetadata (* 0x0 *) + | 0x1 -> ContainsNoMetadata (* 0x1 *) + | _ -> assert false + +let manifest_resource_flag_of_int i = match i land 0x7 with + | 0x0 -> RNone (* 0x0 *) + | 0x1 -> RPublic (* 0x1 *) + | 0x2 -> RPrivate (* 0x2 *) + | _ -> assert false + +let generic_variance_of_int = function + (* mask 0x3 *) + | 0x0 -> VNone (* 0x0 *) + | 0x1 -> VCovariant (* 0x1 *) + | 0x2 -> VContravariant (* 0x2 *) + | _ -> assert false + +let generic_constraint_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + (* mask 0x1C *) + | 0x4 -> CInstanceType (* 0x4 *) + | 0x8 -> CValueType (* 0x8 *) + | 0x10 -> CDefaultCtor (* 0x10 *) + | _ -> assert false) :: acc + else + acc) [] [0x4;0x8;0x10] + +let generic_flags_of_int i = + { + gf_variance = generic_variance_of_int (i land 0x3); + gf_constraint = generic_constraint_of_int (i land 0x1C); + } + +let null_generic_flags = generic_flags_of_int 0 + +(* TODO: convert from string to Bigstring if OCaml 4 is available *) +type meta_ctx = { + compressed : bool; + (* is a compressed stream *) + strings_stream : string; + mutable strings_offset : int; + (* #Strings: a string heap containing the names of metadata items *) + blob_stream : string; + mutable blob_offset : int; + (* #Blob: blob heap containing internal metadata binary object, such as default values, signatures, etc *) + guid_stream : string; + mutable guid_offset : int; + (* #GUID: a GUID heap *) + us_stream : string; + (* #US: user-defined strings *) + meta_stream : string; + (* may be either: *) + (* #~: compressed (optimized) metadata stream *) + (* #-: uncompressed (unoptimized) metadata stream *) + mutable meta_edit_continue : bool; + mutable meta_has_deleted : bool; + + module_cache : meta_cache; + tables : (clr_meta DynArray.t) array; + table_sizes : ( string -> int -> int * int ) array; + extra_streams : clr_stream_header list; + relations : (meta_pointer, clr_meta) Hashtbl.t; + typedefs : (ilpath, meta_type_def) Hashtbl.t; + + mutable delays : (unit -> unit) list; +} + +and meta_cache = { + mutable lookups : (string -> meta_ctx option) list; + mutable mcache : (meta_module * meta_ctx) list; +} + +let empty = "" + +let create_cache () = + { + lookups = []; + mcache = []; + } + +let add_lookup cache fn = + cache.lookups <- fn :: cache.lookups + +(* ******* Reading from Strings ********* *) + +let sget s pos = Char.code (String.get s pos) + +let read_compressed_i32 s pos = + let v = sget s pos in + (* Printf.printf "compressed: %x (18 0x%x 19 0x%x)\n" v (sget s (pos+20)) (sget s (pos+21)); *) + if v land 0x80 = 0x00 then + pos+1, v + else if v land 0xC0 = 0x80 then + pos+2, ((v land 0x3F) lsl 8) lor (sget s (pos+1)) + else if v land 0xE0 = 0xC0 then + pos+4, ((v land 0x1F) lsl 24) lor ((sget s (pos+1)) lsl 16) lor ((sget s (pos+2)) lsl 8) lor (sget s (pos+3)) + else + error (Printf.sprintf "Error reading compressed data. Invalid first byte: %x" v) + +let int_of_table (idx : clr_meta_idx) : int = Obj.magic idx +let table_of_int (idx : int) : clr_meta_idx = Obj.magic idx + +let sread_ui8 s pos = + let n1 = sget s pos in + pos+1,n1 + +let sread_i32 s pos = + let n1 = sget s pos in + let n2 = sget s (pos+1) in + let n3 = sget s (pos+2) in + let n4 = sget s (pos+3) in + pos+4, (n4 lsl 24) lor (n3 lsl 16) lor (n2 lsl 8) lor n1 + +let sread_real_i32 s pos = + let n1 = sget s pos in + let n2 = sget s (pos+1) in + let n3 = sget s (pos+2) in + let n4 = Int32.of_int (sget s (pos+3)) in + let n = Int32.of_int ((n3 lsl 16) lor (n2 lsl 8) lor n1) in + let n4 = Int32.shift_left n4 24 in + pos+4, (Int32.logor n4 n) + +let sread_i64 s pos = + let pos, v1 = sread_real_i32 s (pos+1) in + let v1 = Int64.of_int32 v1 in + let pos, v2 = sread_real_i32 s pos in + let v2 = Int64.of_int32 v2 in + let v2 = Int64.shift_left v2 32 in + pos, (Int64.logor v1 v2) + +let sread_ui16 s pos = + let n1 = sget s pos in + let n2 = sget s (pos+1) in + pos+2, (n2 lsl 8) lor n1 + +let read_cstring ctx pos = + let s = ctx.strings_stream in + let rec loop en = + match String.get s en with + | '\x00' -> en - pos + | _ -> loop (en+1) + in + (* printf "len 0x%x - pos 0x%x\n" (String.length s) pos; *) + let len = loop pos in + String.sub s pos len + +let read_sstring_idx ctx pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.strings_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + match i with + | 0 -> + metapos, "" + | _ -> + metapos, read_cstring ctx i + +let read_sblob_idx ctx pos = + let s = ctx.meta_stream in + let metapos, i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + match i with + | 0 -> + metapos,"" + | _ -> + let bpos, len = read_compressed_i32 ctx.blob_stream i in + metapos, String.sub ctx.blob_stream bpos len + +let read_sguid_idx ctx pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.guid_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + match i with + | 0 -> + metapos, "" + | _ -> + let s = ctx.guid_stream in + let i = i - 1 in + let pos = i * 16 in + metapos, String.sub s pos 16 + +let read_callconv ctx s pos = + let pos, conv = read_compressed_i32 s pos in + let basic = match conv land 0xF with + | 0x0 -> CallDefault (* 0x0 *) + | 0x5 -> CallVararg (* 0x5 *) + | 0x6 -> CallField (* 0x6 *) + | 0x7 -> CallLocal (* 0x7 *) + | 0x8 -> CallProp (* 0x8 *) + | 0x9 -> CallUnmanaged (* 0x9 *) + | 0xa -> CallGenericInst (* 0xA *) + | i -> printf "error 0x%x\n" i; assert false + in + let basic = [basic] in + let pos, c = match conv land 0x10 with + | 0x10 -> + let pos, nparams = read_compressed_i32 s pos in + pos, CallGeneric nparams :: basic + | _ -> + pos, basic + in + match conv land 0x20 with + | 0x20 -> + pos, CallHasThis :: basic + | _ when conv land 0x40 = 0x40 -> + pos, CallExplicitThis :: basic + | _ -> pos, basic + +let read_constant ctx with_type s pos = + match with_type with + | CBool -> + pos+1, IBool (sget s (pos) <> 0) + | CChar -> + let pos, v = sread_ui16 s (pos) in + pos, IChar v + | CInt8 | CUInt8 -> + pos+1,IByte (sget s (pos)) + | CInt16 | CUInt16 -> + let pos, v = sread_ui16 s (pos) in + pos, IShort v + | CInt32 | CUInt32 -> + let pos, v = sread_real_i32 s (pos) in + pos, IInt v + | CInt64 | CUInt64 -> + let pos, v = sread_i64 s (pos) in + pos, IInt64 v + | CFloat32 -> + let pos, v1 = sread_real_i32 s (pos) in + pos, IFloat32 (Int32.float_of_bits v1) + | CFloat64 -> + let pos, v1 = sread_i64 s (pos) in + pos, IFloat64 (Int64.float_of_bits v1) + | CString -> + if sget s pos = 0xff then + pos+1,IString "" + else + let pos, len = read_compressed_i32 s pos in + pos+len, IString (String.sub s pos len) + | CNullRef -> + pos+1, INull + +let sig_to_const = function + | SBool -> CBool + | SChar -> CChar + | SInt8 -> CInt8 + | SUInt8 -> CUInt8 + | SInt16 -> CInt16 + | SUInt16 -> CUInt16 + | SInt32 -> CInt32 + | SUInt32 -> CUInt32 + | SInt64 -> CInt64 + | SUInt64 -> CUInt64 + | SFloat32 -> CFloat32 + | SFloat64 -> CFloat64 + | SString -> CString + | _ -> CNullRef + +let read_constant_type ctx s pos = match sget s pos with + | 0x2 -> pos+1, CBool (* 0x2 *) + | 0x3 -> pos+1, CChar (* 0x3 *) + | 0x4 -> pos+1, CInt8 (* 0x4 *) + | 0x5 -> pos+1, CUInt8 (* 0x5 *) + | 0x6 -> pos+1, CInt16 (* 0x6 *) + | 0x7 -> pos+1, CUInt16 (* 0x7 *) + | 0x8 -> pos+1, CInt32 (* 0x8 *) + | 0x9 -> pos+1, CUInt32 (* 0x9 *) + | 0xA -> pos+1, CInt64 (* 0xA *) + | 0xB -> pos+1, CUInt64 (* 0xB *) + | 0xC -> pos+1, CFloat32 (* 0xC *) + | 0xD -> pos+1, CFloat64 (* 0xD *) + | 0xE -> pos+1, CString (* 0xE *) + | 0x12 -> pos+1, CNullRef (* 0x12 *) + | i -> Printf.printf "0x%x\n" i; assert false + +let action_security_of_int = function + | 0x1 -> SecRequest (* 0x1 *) + | 0x2 -> SecDemand (* 0x2 *) + | 0x3 -> SecAssert (* 0x3 *) + | 0x4 -> SecDeny (* 0x4 *) + | 0x5 -> SecPermitOnly (* 0x5 *) + | 0x6 -> SecLinkCheck (* 0x6 *) + | 0x7 -> SecInheritCheck (* 0x7 *) + | 0x8 -> SecReqMin (* 0x8 *) + | 0x9 -> SecReqOpt (* 0x9 *) + | 0xA -> SecReqRefuse (* 0xA *) + | 0xB -> SecPreJitGrant (* 0xB *) + | 0xC -> SecPreJitDeny (* 0xC *) + | 0xD -> SecNonCasDemand (* 0xD *) + | 0xE -> SecNonCasLinkDemand (* 0xE *) + | 0xF -> SecNonCasInheritance (* 0xF *) + | _ -> assert false + +(* ******* Metadata Tables ********* *) +let null_meta = UnknownMeta (-1) + +let mk_module id = + { + md_id = id; + md_generation = 0; + md_name = empty; + md_vid = empty; + md_encid = empty; + md_encbase_id = empty; + } + +let null_module = mk_module (-1) + +let mk_type_ref id = + { + tr_id = id; + tr_resolution_scope = null_meta; + tr_name = empty; + tr_namespace = []; + } + +let null_type_ref = mk_type_ref (-1) + +let mk_type_def id = + { + td_id = id; + td_flags = null_type_def_flags; + td_name = empty; + td_namespace = []; + td_extends = None; + td_field_list = []; + td_method_list = []; + td_extra_enclosing = None; + } + +let null_type_def = mk_type_def (-1) + +let mk_field id = + { + f_id = id; + f_flags = null_field_flags; + f_name = empty; + f_signature = SVoid; + } + +let null_field = mk_field (-1) + +let mk_field_ptr id = + { + fp_id = id; + fp_field = null_field; + } + +let null_field_ptr = mk_field_ptr (-1) + +let mk_method id = + { + m_id = id; + m_rva = Int32.of_int (-1); + m_flags = null_method_flags; + m_name = empty; + m_signature = SVoid; + m_param_list = []; + m_declaring = None; + } + +let null_method = mk_method (-1) + +let mk_method_ptr id = + { + mp_id = id; + mp_method = null_method; + } + +let null_method_ptr = mk_method_ptr (-1) + +let mk_param id = + { + p_id = id; + p_flags = null_param_flags; + p_sequence = -1; + p_name = empty; + } + +let null_param = mk_param (-1) + +let mk_param_ptr id = + { + pp_id = id; + pp_param = null_param; + } + +let null_param_ptr = mk_param_ptr (-1) + +let mk_interface_impl id = + { + ii_id = id; + ii_class = null_type_def; (* TypeDef rid *) + ii_interface = null_meta; + } + +let null_interface_impl = mk_interface_impl (-1) + +let mk_member_ref id = + { + memr_id = id; + memr_class = null_meta; + memr_name = empty; + memr_signature = SVoid; + } + +let null_member_ref = mk_member_ref (-1) + +let mk_constant id = + { + c_id = id; + c_type = CNullRef; + c_parent = null_meta; + c_value = INull; + } + +let null_constant = mk_constant (-1) + +let mk_custom_attribute id = + { + ca_id = id; + ca_parent = null_meta; + ca_type = null_meta; + ca_value = None; + } + +let null_custom_attribute = mk_custom_attribute (-1) + +let mk_field_marshal id = + { + fm_id = id; + fm_parent = null_meta; + fm_native_type = NVoid; + } + +let null_field_marshal = mk_field_marshal (-1) + +let mk_decl_security id = + { + ds_id = id; + ds_action = SecNull; + ds_parent = null_meta; + ds_permission_set = empty; + } + +let mk_class_layout id = + { + cl_id = id; + cl_packing_size = -1; + cl_class_size = -1; + cl_parent = null_type_def; + } + +let mk_field_layout id = + { + fl_id = id; + fl_offset = -1; + fl_field = null_field; + } + +let mk_stand_alone_sig id = + { + sa_id = id; + sa_signature = SVoid; + } + +let mk_event id = + { + e_id = id; + e_flags = []; + e_name = empty; + e_event_type = null_meta; + } + +let null_event = mk_event (-1) + +let mk_event_map id = + { + em_id = id; + em_parent = null_type_def; + em_event_list = []; + } + +let mk_event_ptr id = + { + ep_id = id; + ep_event = null_event; + } + +let mk_property id = + { + prop_id = id; + prop_flags = []; + prop_name = empty; + prop_type = SVoid; + } + +let null_property = mk_property (-1) + +let mk_property_map id = + { + pm_id = id; + pm_parent = null_type_def; + pm_property_list = []; + } + +let mk_property_ptr id = + { + prp_id = id; + prp_property = null_property; + } + +let mk_method_semantics id = + { + ms_id = id; + ms_semantic = []; + ms_method = null_method; + ms_association = null_meta; + } + +let mk_method_impl id = + { + mi_id = id; + mi_class = null_type_def; + mi_method_body = null_meta; + mi_method_declaration = null_meta; + } + +let mk_module_ref id = + { + modr_id = id; + modr_name = empty; + } + +let null_module_ref = mk_module_ref (-1) + +let mk_type_spec id = + { + ts_id = id; + ts_signature = SVoid; + } + +let mk_enc_log id = + { + el_id = id; + el_token = -1; + el_func_code = -1; + } + +let mk_impl_map id = + { + im_id = id; + im_flags = null_impl_flags; + im_forwarded = null_meta; + im_import_name = empty; + im_import_scope = null_module_ref; + } + +let mk_enc_map id = + { + encm_id = id; + encm_token = -1; + } + +let mk_field_rva id = + { + fr_id = id; + fr_rva = Int32.zero; + fr_field = null_field; + } + +let mk_assembly id = + { + a_id = id; + a_hash_algo = HNone; + a_major = -1; + a_minor = -1; + a_build = -1; + a_rev = -1; + a_flags = []; + a_public_key = empty; + a_name = empty; + a_locale = empty; + } + +let mk_assembly_processor id = + { + ap_id = id; + ap_processor = -1; + } + +let mk_assembly_os id = + { + aos_id = id; + aos_platform_id = -1; + aos_major_version = -1; + aos_minor_version = -1; + } + +let mk_assembly_ref id = + { + ar_id = id; + ar_major = -1; + ar_minor = -1; + ar_build = -1; + ar_rev = -1; + ar_flags = []; + ar_public_key = empty; + ar_name = empty; + ar_locale = empty; + ar_hash_value = empty; + } + +let null_assembly_ref = mk_assembly_ref (-1) + +let mk_assembly_ref_processor id = + { + arp_id = id; + arp_processor = -1; + arp_assembly_ref = null_assembly_ref; + } + +let mk_assembly_ref_os id = + { + aros_id = id; + aros_platform_id = -1; + aros_major = -1; + aros_minor = -1; + aros_assembly_ref = null_assembly_ref; + } + +let mk_file id = + { + file_id = id; + file_flags = ContainsMetadata; + file_name = empty; + file_hash_value = empty; + } + +let mk_exported_type id = + { + et_id = id; + et_flags = null_type_def_flags; + et_type_def_id = -1; + et_type_name = empty; + et_type_namespace = []; + et_implementation = null_meta; + } + +let mk_manifest_resource id = + { + mr_id = id; + mr_offset = -1; + mr_flags = RNone; + mr_name = empty; + mr_implementation = None; + } + +let mk_nested_class id = + { + nc_id = id; + nc_nested = null_type_def; + nc_enclosing = null_type_def; + } + +let mk_generic_param id = + { + gp_id = id; + gp_number = -1; + gp_flags = null_generic_flags; + gp_owner = null_meta; + gp_name = None; + } + +let null_generic_param = mk_generic_param (-1) + +let mk_method_spec id = + { + mspec_id = id; + mspec_method = null_meta; + mspec_instantiation = SVoid; + } + +let mk_generic_param_constraint id = + { + gc_id = id; + gc_owner = null_generic_param; + gc_constraint = null_meta; + } + +let mk_meta tbl id = match tbl with + | IModule -> Module (mk_module id) + | ITypeRef -> TypeRef (mk_type_ref id) + | ITypeDef -> TypeDef (mk_type_def id) + | IFieldPtr -> FieldPtr (mk_field_ptr id) + | IField -> Field (mk_field id) + | IMethodPtr -> MethodPtr (mk_method_ptr id) + | IMethod -> Method (mk_method id) + | IParamPtr -> ParamPtr (mk_param_ptr id) + | IParam -> Param (mk_param id) + | IInterfaceImpl -> InterfaceImpl (mk_interface_impl id) + | IMemberRef -> MemberRef (mk_member_ref id) + | IConstant -> Constant (mk_constant id) + | ICustomAttribute -> CustomAttribute (mk_custom_attribute id) + | IFieldMarshal -> FieldMarshal(mk_field_marshal id) + | IDeclSecurity -> DeclSecurity(mk_decl_security id) + | IClassLayout -> ClassLayout(mk_class_layout id) + | IFieldLayout -> FieldLayout(mk_field_layout id) + | IStandAloneSig -> StandAloneSig(mk_stand_alone_sig id) + | IEventMap -> EventMap(mk_event_map id) + | IEventPtr -> EventPtr(mk_event_ptr id) + | IEvent -> Event(mk_event id) + | IPropertyMap -> PropertyMap(mk_property_map id) + | IPropertyPtr -> PropertyPtr(mk_property_ptr id) + | IProperty -> Property(mk_property id) + | IMethodSemantics -> MethodSemantics(mk_method_semantics id) + | IMethodImpl -> MethodImpl(mk_method_impl id) + | IModuleRef -> ModuleRef(mk_module_ref id) + | ITypeSpec -> TypeSpec(mk_type_spec id) + | IImplMap -> ImplMap(mk_impl_map id) + | IFieldRVA -> FieldRVA(mk_field_rva id) + | IENCLog -> ENCLog(mk_enc_log id) + | IENCMap -> ENCMap(mk_enc_map id) + | IAssembly -> Assembly(mk_assembly id) + | IAssemblyProcessor -> AssemblyProcessor(mk_assembly_processor id) + | IAssemblyOS -> AssemblyOS(mk_assembly_os id) + | IAssemblyRef -> AssemblyRef(mk_assembly_ref id) + | IAssemblyRefProcessor -> AssemblyRefProcessor(mk_assembly_ref_processor id) + | IAssemblyRefOS -> AssemblyRefOS(mk_assembly_ref_os id) + | IFile -> File(mk_file id) + | IExportedType -> ExportedType(mk_exported_type id) + | IManifestResource -> ManifestResource(mk_manifest_resource id) + | INestedClass -> NestedClass(mk_nested_class id) + | IGenericParam -> GenericParam(mk_generic_param id) + | IMethodSpec -> MethodSpec(mk_method_spec id) + | IGenericParamConstraint -> GenericParamConstraint(mk_generic_param_constraint id) + | i -> UnknownMeta (int_of_table i) + +let get_table ctx idx rid = + let cur = ctx.tables.(int_of_table idx) in + DynArray.get cur (rid-1) + +(* special coded types *) +let max_clr_meta_idx = 76 + +let coded_description = Array.init (max_clr_meta_idx - 63) (fun i -> + let i = 64 + i in + match table_of_int i with + | ITypeDefOrRef -> + Array.of_list [ITypeDef;ITypeRef;ITypeSpec], 2 + | IHasConstant -> + Array.of_list [IField;IParam;IProperty], 2 + | IHasCustomAttribute -> + Array.of_list + [IMethod;IField;ITypeRef;ITypeDef;IParam;IInterfaceImpl;IMemberRef; + IModule;IDeclSecurity;IProperty;IEvent;IStandAloneSig;IModuleRef; + ITypeSpec;IAssembly;IAssemblyRef;IFile;IExportedType;IManifestResource; + IGenericParam;IGenericParamConstraint;IMethodSpec], 5 + | IHasFieldMarshal -> + Array.of_list [IField;IParam], 1 + | IHasDeclSecurity -> + Array.of_list [ITypeDef;IMethod;IAssembly], 2 + | IMemberRefParent -> + Array.of_list [ITypeDef;ITypeRef;IModuleRef;IMethod;ITypeSpec], 3 + | IHasSemantics -> + Array.of_list [IEvent;IProperty], 1 + | IMethodDefOrRef -> + Array.of_list [IMethod;IMemberRef], 1 + | IMemberForwarded -> + Array.of_list [IField;IMethod], 1 + | IImplementation -> + Array.of_list [IFile;IAssemblyRef;IExportedType], 2 + | ICustomAttributeType -> + Array.of_list [ITypeRef(* unused ? *);ITypeDef (* unused ? *);IMethod;IMemberRef(*;IString FIXME *)], 3 + | IResolutionScope -> + Array.of_list [IModule;IModuleRef;IAssemblyRef;ITypeRef], 2 + | ITypeOrMethodDef -> + Array.of_list [ITypeDef;IMethod], 1 + | _ -> + print_endline ("Unknown coded index: " ^ string_of_int i); + assert false) + +let set_coded_sizes ctx rows = + let check i tbls max = + if List.exists (fun t -> + let _, nrows = rows.(int_of_table t) in + nrows >= max + ) tbls then + ctx.table_sizes.(i) <- sread_i32 + in + for i = 64 to (max_clr_meta_idx) do + let tbls, size = coded_description.(i - 64) in + let max = 1 lsl (16 - size) in + check i (Array.to_list tbls) max + done + +let sread_from_table_opt ctx in_blob tbl s pos = + let i = int_of_table tbl in + let sread = if in_blob then + read_compressed_i32 + else + ctx.table_sizes.(i) + in + let pos, rid = sread s pos in + if i >= 64 then begin + let tbls,size = coded_description.(i-64) in + let mask = (1 lsl size) - 1 in + let mask = if mask = 0 then 1 else mask in + let tidx = rid land mask in + let real_rid = rid lsr size in + let real_tbl = tbls.(tidx) in + (* printf "rid 0x%x - table idx 0x%x - real_rid 0x%x\n\n" rid tidx real_rid; *) + if real_rid = 0 then + pos, None + else + pos, Some (get_table ctx real_tbl real_rid) + end else if rid = 0 then + pos, None + else + pos, Some (get_table ctx tbl rid) + +let sread_from_table ctx in_blob tbl s pos = + let pos, opt = sread_from_table_opt ctx in_blob tbl s pos in + pos, Option.get opt + +(* ******* SIGNATURE READING ********* *) +let read_inline_str s pos = + let pos, len = read_compressed_i32 s pos in + let ret = String.sub s pos len in + pos+len,ret + +let rec read_ilsig ctx s pos = + let i = sget s pos in + (* printf "0x%x\n" i; *) + let pos = pos + 1 in + match i with + | 0x1 -> pos, SVoid (* 0x1 *) + | 0x2 -> pos, SBool (* 0x2 *) + | 0x3 -> pos, SChar (* 0x3 *) + | 0x4 -> pos, SInt8 (* 0x4 *) + | 0x5 -> pos, SUInt8 (* 0x5 *) + | 0x6 -> pos, SInt16 (* 0x6 *) + | 0x7 -> pos, SUInt16 (* 0x7 *) + | 0x8 -> pos, SInt32 (* 0x8 *) + | 0x9 -> pos, SUInt32 (* 0x9 *) + | 0xA -> pos, SInt64 (* 0xA *) + | 0xB -> pos, SUInt64 (* 0xB *) + | 0xC -> pos, SFloat32 (* 0xC *) + | 0xD -> pos, SFloat64 (* 0xD *) + | 0xE -> pos, SString (* 0xE *) + | 0xF -> + let pos, s = read_ilsig ctx s pos in + pos, SPointer s + | 0x10 -> + let pos, s = read_ilsig ctx s pos in + pos, SManagedPointer s + | 0x11 -> + let pos, vt = sread_from_table ctx true ITypeDefOrRef s pos in + pos, SValueType vt + | 0x12 -> + let pos, c = sread_from_table ctx true ITypeDefOrRef s pos in + pos, SClass c + | 0x13 -> + let n = sget s pos in + pos + 1, STypeParam n + | 0x14 -> + let pos, ssig = read_ilsig ctx s pos in + let pos, rank = read_compressed_i32 s pos in + let pos, numsizes = read_compressed_i32 s pos in + let pos = ref pos in + let sizearray = Array.init numsizes (fun _ -> + let p, size = read_compressed_i32 s !pos in + pos := p; + size + ) in + let pos, bounds = read_compressed_i32 s !pos in + let pos = ref pos in + let boundsarray = Array.init bounds (fun _ -> + let p, b = read_compressed_i32 s !pos in + pos := p; + let signed = b land 0x1 = 0x1 in + let b = b lsr 1 in + if signed then -b else b + ) in + let ret = Array.init rank (fun i -> + (if i >= bounds then None else Some boundsarray.(i)) + , (if i >= numsizes then None else Some sizearray.(i)) + ) in + !pos, SArray(ssig, ret) + | 0x15 -> + (* let pos, c = sread_from_table ctx ITypeDefOrRef s pos in *) + let pos, ssig = read_ilsig ctx s pos in + let pos, ntypes = read_compressed_i32 s pos in + let rec loop acc pos n = + if n > ntypes then + pos, List.rev acc + else + let pos, ssig = read_ilsig ctx s pos in + loop (ssig :: acc) pos (n+1) + in + let pos, args = loop [] pos 1 in + pos, SGenericInst (ssig, args) + | 0x16 -> pos, STypedReference (* 0x16 *) + | 0x18 -> pos, SIntPtr (* 0x18 *) + | 0x19 -> pos, SUIntPtr (* 0x19 *) + | 0x1B -> + let pos, conv = read_compressed_i32 s pos in + let callconv = callconv_of_int conv in + let pos, ntypes = read_compressed_i32 s pos in + let pos, ret = read_ilsig ctx s pos in + let rec loop acc pos n = + if n >= ntypes then + pos, List.rev acc + else + let pos, ssig = read_ilsig ctx s pos in + loop (ssig :: acc) pos (n+1) + in + let pos, args = loop [] pos 1 in + pos, SFunPtr (callconv, ret, args) + | 0x1C -> pos, SObject (* 0x1C *) + | 0x1D -> + let pos, ssig = read_ilsig ctx s pos in + pos, SVector ssig + | 0x1E -> + let pos, conv = read_compressed_i32 s pos in + pos, SMethodTypeParam conv + | 0x1F -> + let pos, tdef = sread_from_table ctx true ITypeDefOrRef s pos in + let pos, ilsig = read_ilsig ctx s pos in + pos, SReqModifier (tdef, ilsig) + | 0x20 -> + let pos, tdef = sread_from_table ctx true ITypeDefOrRef s pos in + let pos, ilsig = read_ilsig ctx s pos in + pos, SOptModifier (tdef, ilsig) + | 0x41 -> pos, SSentinel (* 0x41 *) + | 0x45 -> + let pos, ssig = read_ilsig ctx s pos in + pos,SPinned ssig (* 0x45 *) + (* special undocumented constants *) + | 0x50 -> pos, SType + | 0x51 -> pos, SBoxed + | 0x55 -> + let pos, vt = read_inline_str s pos in + pos, SEnum vt + | _ -> + Printf.printf "unknown ilsig 0x%x\n\n" i; + assert false + +let rec read_variantsig ctx s pos = + let pos, b = sread_ui8 s pos in + match b with + | 0x00 -> pos, VT_EMPTY (* 0x00 *) + | 0x01 -> pos, VT_NULL (* 0x01 *) + | 0x02 -> pos, VT_I2 (* 0x02 *) + | 0x03 -> pos, VT_I4 (* 0x03 *) + | 0x04 -> pos, VT_R4 (* 0x04 *) + | 0x05 -> pos, VT_R8 (* 0x05 *) + | 0x06 -> pos, VT_CY (* 0x06 *) + | 0x07 -> pos, VT_DATE (* 0x07 *) + | 0x08 -> pos, VT_BSTR (* 0x08 *) + | 0x09 -> pos, VT_DISPATCH (* 0x09 *) + | 0x0A -> pos, VT_ERROR (* 0x0A *) + | 0x0B -> pos, VT_BOOL (* 0x0B *) + | 0x0C -> pos, VT_VARIANT (* 0x0C *) + | 0x0D -> pos, VT_UNKNOWN (* 0x0D *) + | 0x0E -> pos, VT_DECIMAL (* 0x0E *) + | 0x10 -> pos, VT_I1 (* 0x10 *) + | 0x11 -> pos, VT_UI1 (* 0x11 *) + | 0x12 -> pos, VT_UI2 (* 0x12 *) + | 0x13 -> pos, VT_UI4 (* 0x13 *) + | 0x14 -> pos, VT_I8 (* 0x14 *) + | 0x15 -> pos, VT_UI8 (* 0x15 *) + | 0x16 -> pos, VT_INT (* 0x16 *) + | 0x17 -> pos, VT_UINT (* 0x17 *) + | 0x18 -> pos, VT_VOID (* 0x18 *) + | 0x19 -> pos, VT_HRESULT (* 0x19 *) + | 0x1A -> pos, VT_PTR (* 0x1A *) + | 0x1B -> pos, VT_SAFEARRAY (* 0x1B *) + | 0x1C -> pos, VT_CARRAY (* 0x1C *) + | 0x1D -> pos, VT_USERDEFINED (* 0x1D *) + | 0x1E -> pos, VT_LPSTR (* 0x1E *) + | 0x1F -> pos, VT_LPWSTR (* 0x1F *) + | 0x24 -> pos, VT_RECORD (* 0x24 *) + | 0x40 -> pos, VT_FILETIME (* 0x40 *) + | 0x41 -> pos, VT_BLOB (* 0x41 *) + | 0x42 -> pos, VT_STREAM (* 0x42 *) + | 0x43 -> pos, VT_STORAGE (* 0x43 *) + | 0x44 -> pos, VT_STREAMED_OBJECT (* 0x44 *) + | 0x45 -> pos, VT_STORED_OBJECT (* 0x45 *) + | 0x46 -> pos, VT_BLOB_OBJECT (* 0x46 *) + | 0x47 -> pos, VT_CF (* 0x47 *) + | 0x48 -> pos, VT_CLSID (* 0x48 *) + | _ -> assert false + +let rec read_nativesig ctx s pos : int * nativesig = + let pos, b = sread_ui8 s pos in + match b with + | 0x01 -> pos, NVoid (* 0x01 *) + | 0x02 -> pos, NBool (* 0x02 *) + | 0x03 -> pos, NInt8 (* 0x03 *) + | 0x4 -> pos, NUInt8 (* 0x4 *) + | 0x5 -> pos, NInt16 (* 0x5 *) + | 0x6 -> pos, NUInt16 (* 0x6 *) + | 0x7 -> pos, NInt32 (* 0x7 *) + | 0x8 -> pos, NUInt32 (* 0x8 *) + | 0x9 -> pos, NInt64 (* 0x9 *) + | 0xA -> pos, NUInt64 (* 0xA *) + | 0xB -> pos, NFloat32 (* 0xB *) + | 0xC -> pos, NFloat64 (* 0xC *) + | 0xD -> pos, NSysChar (* 0xD *) + | 0xE -> pos, NVariant (* 0xE *) + | 0xF -> pos, NCurrency (* 0xF *) + | 0x10 -> pos, NPointer (* 0x10 *) + | 0x11 -> pos, NDecimal (* 0x11 *) + | 0x12 -> pos, NDate (* 0x12 *) + | 0x13 -> pos, NBStr (* 0x13 *) + | 0x14 -> pos, NLPStr (* 0x14 *) + | 0x15 -> pos, NLPWStr (* 0x15 *) + | 0x16 -> pos, NLPTStr (* 0x16 *) + | 0x17 -> + let pos, size = read_compressed_i32 s pos in + pos, NFixedString size + | 0x18 -> pos, NObjectRef (* 0x18 *) + | 0x19 -> pos, NUnknown (* 0x19 *) + | 0x1A -> pos, NDispatch (* 0x1A *) + | 0x1B -> pos, NStruct (* 0x1B *) + | 0x1C -> pos, NInterface (* 0x1C *) + | 0x1D -> + let pos, v = read_variantsig ctx s pos in + pos, NSafeArray v + | 0x1E -> + let pos, size = read_compressed_i32 s pos in + let pos, t = read_variantsig ctx s pos in + pos, NFixedArray (size,t) + | 0x1F -> pos, NIntPointer (* 0x1F *) + | 0x20 -> pos, NUIntPointer (* 0x20 *) + | 0x21 -> pos, NNestedStruct (* 0x21 *) + | 0x22 -> pos, NByValStr (* 0x22 *) + | 0x23 -> pos, NAnsiBStr (* 0x23 *) + | 0x24 -> pos, NTBStr (* 0x24 *) + | 0x25 -> pos, NVariantBool (* 0x25 *) + | 0x26 -> pos, NFunctionPtr (* 0x26 *) + | 0x28 -> pos, NAsAny (* 0x28 *) + | 0x2A -> + let pos, elt = read_nativesig ctx s pos in + let pos, paramidx = read_compressed_i32 s pos in + let pos, size = read_compressed_i32 s pos in + let pos, param_mult = read_compressed_i32 s pos in + pos, NArray(elt,paramidx,size,param_mult) + | 0x2B -> pos, NLPStruct (* 0x2B *) + | 0x2C -> + let pos, guid_val = read_inline_str s pos in + let pos, unmanaged = read_inline_str s pos in + (* FIXME: read TypeRef *) + pos, NCustomMarshaler (guid_val,unmanaged) + | 0x2D -> pos, NError (* 0x2D *) + | i -> pos, NCustom i + +let read_blob_idx ctx s pos = + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + metapos, i + + +let read_nativesig_idx ctx s pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let s = ctx.blob_stream in + let _, ret = read_nativesig ctx s i in + metapos, ret + +let read_method_ilsig_idx ctx pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let s = ctx.blob_stream in + let pos, len = read_compressed_i32 s i in + (* for x = 0 to len do *) + (* printf "%x " (sget s (i+x)) *) + (* done; *) + let endpos = pos + len in + (* printf "\n"; *) + let pos, callconv = read_callconv ctx s pos in + let pos, ntypes = read_compressed_i32 s pos in + let pos, ret = read_ilsig ctx s pos in + let rec loop acc pos n = + if n > ntypes || pos >= endpos then + pos, List.rev acc + else + let pos, ssig = read_ilsig ctx s pos in + loop (ssig :: acc) pos (n+1) + in + let pos, args = loop [] pos 1 in + metapos, SFunPtr (callconv, ret, args) + +let read_ilsig_idx ctx pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let s = ctx.blob_stream in + let i, _ = read_compressed_i32 s i in + let _, ilsig = read_ilsig ctx s i in + metapos, ilsig + +let read_field_ilsig_idx ?(force_field=true) ctx pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let s = ctx.blob_stream in + let i, _ = read_compressed_i32 s i in + if sget s i <> 0x6 then + if force_field then + error ("Invalid field signature: " ^ string_of_int (sget s i)) + else + read_method_ilsig_idx ctx pos + else + let _, ilsig = read_ilsig ctx s (i+1) in + metapos, ilsig + +let get_underlying_enum_type ctx name = + (* first try to get a typedef *) + let ns, name = match List.rev (String.nsplit name ".") with + | name :: ns -> List.rev ns, name + | _ -> assert false + in + try + let tdefs = ctx.tables.(int_of_table ITypeDef) in + let len = DynArray.length tdefs in + let rec loop_find idx = + if idx >= len then + raise Not_found + else + let tdef = match DynArray.get tdefs idx with | TypeDef td -> td | _ -> assert false in + if tdef.td_name = name && tdef.td_namespace = ns then + tdef + else + loop_find (idx+1) + in + let tdef = loop_find 1 in + (* now find the first static field associated with it *) + try + let nonstatic = List.find (fun f -> + not (List.mem CStatic f.f_flags.ff_contract) + ) tdef.td_field_list in + nonstatic.f_signature + with | Not_found -> assert false (* should never happen! *) + with | Not_found -> + (* FIXME: in order to correctly handle SEnum, we need to look it up *) + (* from either this assembly or from any other assembly that we reference *) + (* this is tricky - specially since this reader does not intend to handle file system *) + (* operations by itself. For now, if an enum is referenced from another module, *) + (* we won't handle it. The `cache` structure is laid out to deal with these problems *) + (* but isn't implemented yet *) + raise Exit + +let read_custom_attr ctx attr_type s pos = + let pos, prolog = sread_ui16 s pos in + if prolog <> 0x0001 then error (sprintf "Error reading custom attribute: Expected prolog 0x0001 ; got 0x%x" prolog); + let isig = match attr_type with + | Method m -> m.m_signature + | MemberRef mr -> mr.memr_signature + | _ -> assert false + in + let args = match follow isig with + | SFunPtr (_,ret,args) -> args + | _ -> assert false + in + let rec read_instance ilsig pos = + (* print_endline (IlMetaDebug.ilsig_s ilsig); *) + match follow ilsig with + | SBool | SChar | SInt8 | SUInt8 | SInt16 | SUInt16 + | SInt32 | SUInt32 | SInt64 | SUInt64 | SFloat32 | SFloat64 | SString -> + let pos, cons = read_constant ctx (sig_to_const ilsig) s pos in + pos, InstConstant (cons) + | SClass c when is_type (["System"],"Type") c -> + let pos, len = read_compressed_i32 s pos in + pos+len, InstType (String.sub s pos len) + | SType -> + let pos, len = read_compressed_i32 s pos in + pos+len, InstType (String.sub s pos len) + | SObject | SBoxed -> (* boxed *) + let pos = if sget s pos = 0x51 then pos+1 else pos in + let pos, ilsig = read_ilsig ctx s pos in + let pos, ret = read_instance ilsig pos in + pos, InstBoxed( ret ) + (* (match follow ilsig with *) + (* | SEnum e -> *) + (* let ilsig = get_underlying_enum_type ctx e; *) + (* let pos,e = if is_boxed then sread_i32 s pos else read_compressed_i32 s pos in *) + (* pos, InstBoxed(InstEnum e) *) + (* | _ -> *) + (* let pos, boxed = read_constant ctx (sig_to_const ilsig) s pos in *) + (* pos, InstBoxed (InstConstant boxed)) *) + | SEnum e -> + let ilsig = get_underlying_enum_type ctx e in + read_instance ilsig pos + | SValueType _ -> (* enum *) + let pos, e = sread_i32 s pos in + pos, InstEnum e + | _ -> assert false + in + let rec read_fixed acc args pos = match args with + | [] -> + pos, List.rev acc + | SVector isig :: args -> + (* print_endline "vec"; *) + let pos, nelem = sread_real_i32 s pos in + let pos, ret = if nelem = -1l then + pos, InstConstant INull + else + let nelem = Int32.to_int nelem in + let rec loop acc pos n = + if n = nelem then + pos, InstArray (List.rev acc) + else + let pos, inst = read_instance isig pos in + loop (inst :: acc) pos (n+1) + in + loop [] pos 0 + in + read_fixed (ret :: acc) args pos + | isig :: args -> + let pos, i = read_instance isig pos in + read_fixed (i :: acc) args pos + in + (* let tpos = pos in *) + let pos, fixed = read_fixed [] args pos in + (* printf "fixed %d : " (List.length args); *) + (* for x = tpos to pos do *) + (* printf "%x " (sget s x) *) + (* done; *) + (* printf "\n"; *) + (* let len = String.length s - pos - 1 in *) + (* let len = if len > 10 then 10 else len in *) + (* for x = 0 to len do *) + (* printf "%x " (sget s (pos + x)) *) + (* done; *) + (* printf "\n"; *) + let pos, nnamed = read_compressed_i32 s pos in + let pos = if nnamed > 0 then pos+1 else pos in + (* FIXME: this is a hack / quick fix around #3485 . We need to actually read named arguments *) + (* let rec read_named acc pos n = *) + (* if n = nnamed then *) + (* pos, List.rev acc *) + (* else *) + (* let pos, forp = sread_ui8 s pos in *) + (* let is_prop = if forp = 0x53 then *) + (* false *) + (* else if forp = 0x54 then *) + (* true *) + (* else *) + (* error (sprintf "named custom attribute error: expected 0x53 or 0x54 - got 0x%x" forp) *) + (* in *) + (* let pos, t = read_ilsig ctx s pos in *) + (* let pos, len = read_compressed_i32 s pos in *) + (* let name = String.sub s pos len in *) + (* let pos = pos+len in *) + (* let pos, inst = read_instance t pos in *) + (* read_named ( (is_prop, name, inst) :: acc ) pos (n+1) *) + (* in *) + (* let pos, named = read_named [] pos 0 in *) + pos, (fixed, []) + (* pos, (fixed, named) *) + +let read_custom_attr_idx ctx ca attr_type pos = + let s = ctx.meta_stream in + let metapos,i = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + if i = 0 then + metapos + else + let s = ctx.blob_stream in + let i, _ = read_compressed_i32 s i in + ctx.delays <- (fun () -> + try + let _, attr = read_custom_attr ctx attr_type s i in + ca.ca_value <- Some attr + with | Exit -> + () + ) :: ctx.delays; + metapos + +let read_next_index ctx offset table last pos = + if last then + DynArray.length ctx.tables.(int_of_table table) + 1 + else + let s = ctx.meta_stream in + let _, idx = ctx.table_sizes.(int_of_table table) s (pos+offset) in + idx + +let get_rev_list ctx table ptr_table begin_idx end_idx = + (* first check if index exists on pointer table *) + let ptr_table_t = ctx.tables.(int_of_table ptr_table) in + (* printf "table %d begin %d end %d\n" (int_of_table table) begin_idx end_idx; *) + match ctx.compressed, DynArray.length ptr_table_t with + | true, _ | _, 0 -> + (* use direct index *) + let rec loop idx acc = + if idx >= end_idx then + acc + else + loop (idx+1) (get_table ctx table idx :: acc) + in + loop begin_idx [] + | _ -> + (* use indirect index *) + let rec loop idx acc = + if idx > end_idx then + acc + else + loop (idx+1) (get_table ctx ptr_table idx :: acc) + in + let ret = loop begin_idx [] in + List.map (fun meta -> + let p = meta_root_ptr meta in + get_table ctx table p.ptr_to.root_id + ) ret + +let read_list ctx table ptr_table begin_idx offset last pos = + let end_idx = read_next_index ctx offset table last pos in + get_rev_list ctx table ptr_table begin_idx end_idx + +let parse_ns id = match String.nsplit id "." with + | [""] -> [] + | ns -> ns + +let get_meta_pointer = function + | Module r -> IModule, r.md_id + | TypeRef r -> ITypeRef, r.tr_id + | TypeDef r -> ITypeDef, r.td_id + | FieldPtr r -> IFieldPtr, r.fp_id + | Field r -> IField, r.f_id + | MethodPtr r -> IMethodPtr, r.mp_id + | Method r -> IMethod, r.m_id + | ParamPtr r -> IParamPtr, r.pp_id + | Param r -> IParam, r.p_id + | InterfaceImpl r -> IInterfaceImpl, r.ii_id + | MemberRef r -> IMemberRef, r.memr_id + | Constant r -> IConstant, r.c_id + | CustomAttribute r -> ICustomAttribute, r.ca_id + | FieldMarshal r -> IFieldMarshal, r.fm_id + | DeclSecurity r -> IDeclSecurity, r.ds_id + | ClassLayout r -> IClassLayout, r.cl_id + | FieldLayout r -> IFieldLayout, r.fl_id + | StandAloneSig r -> IStandAloneSig, r.sa_id + | EventMap r -> IEventMap, r.em_id + | EventPtr r -> IEventPtr, r.ep_id + | Event r -> IEvent, r.e_id + | PropertyMap r -> IPropertyMap, r.pm_id + | PropertyPtr r -> IPropertyPtr, r.prp_id + | Property r -> IProperty, r.prop_id + | MethodSemantics r -> IMethodSemantics, r.ms_id + | MethodImpl r -> IMethodImpl, r.mi_id + | ModuleRef r -> IModuleRef, r.modr_id + | TypeSpec r -> ITypeSpec, r.ts_id + | ImplMap r -> IImplMap, r.im_id + | FieldRVA r -> IFieldRVA, r.fr_id + | ENCLog r -> IENCLog, r.el_id + | ENCMap r -> IENCMap, r.encm_id + | Assembly r -> IAssembly, r.a_id + | AssemblyProcessor r -> IAssemblyProcessor, r.ap_id + | AssemblyOS r -> IAssemblyOS, r.aos_id + | AssemblyRef r -> IAssemblyRef, r.ar_id + | AssemblyRefProcessor r -> IAssemblyRefProcessor, r.arp_id + | AssemblyRefOS r -> IAssemblyRefOS, r.aros_id + | File r -> IFile, r.file_id + | ExportedType r -> IExportedType, r.et_id + | ManifestResource r -> IManifestResource, r.mr_id + | NestedClass r -> INestedClass, r.nc_id + | GenericParam r -> IGenericParam, r.gp_id + | MethodSpec r -> IMethodSpec, r.mspec_id + | GenericParamConstraint r -> IGenericParamConstraint, r.gc_id + | _ -> assert false + +let add_relation ctx key v = + let ptr = get_meta_pointer key in + Hashtbl.add ctx.relations ptr v + +let read_table_at ctx tbl n last pos = + (* print_endline ("rr " ^ string_of_int (n+1)); *) + let s = ctx.meta_stream in + match get_table ctx tbl (n+1 (* indices start at 1 *)) with + | Module m -> + let pos, gen = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, vid = read_sguid_idx ctx pos in + let pos, encid = read_sguid_idx ctx pos in + let pos, encbase_id = read_sguid_idx ctx pos in + m.md_generation <- gen; + m.md_name <- name; + m.md_vid <- vid; + m.md_encid <- encid; + m.md_encbase_id <- encbase_id; + pos, Module m + | TypeRef tr -> + let pos, scope = sread_from_table ctx false IResolutionScope s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, ns = read_sstring_idx ctx pos in + tr.tr_resolution_scope <- scope; + tr.tr_name <- name; + tr.tr_namespace <- parse_ns ns; + (* print_endline name; *) + (* print_endline ns; *) + pos, TypeRef tr + | TypeDef td -> + let startpos = pos in + let pos, flags = sread_i32 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, ns = read_sstring_idx ctx pos in + let ns = parse_ns ns in + let pos, extends = sread_from_table_opt ctx false ITypeDefOrRef s pos in + let field_offset = pos - startpos in + let pos, flist_begin = ctx.table_sizes.(int_of_table IField) s pos in + let method_offset = pos - startpos in + let pos, mlist_begin = ctx.table_sizes.(int_of_table IMethod) s pos in + td.td_flags <- type_def_flags_of_int flags; + td.td_name <- name; + td.td_namespace <- ns; + td.td_extends <- extends; + td.td_field_list <- List.rev_map get_field (read_list ctx IField IFieldPtr flist_begin field_offset last pos); + td.td_method_list <- List.rev_map get_method (read_list ctx IMethod IMethodPtr mlist_begin method_offset last pos); + List.iter (fun m -> m.m_declaring <- Some td) td.td_method_list; + let path = get_path (TypeDef td) in + Hashtbl.add ctx.typedefs path td; + (* print_endline "Type Def!"; *) + (* print_endline name; *) + (* print_endline ns; *) + pos, TypeDef td + | FieldPtr fp -> + let pos, field = sread_from_table ctx false IField s pos in + let field = get_field field in + fp.fp_field <- field; + pos, FieldPtr fp + | Field f -> + let pos, flags = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + (* print_endline ("FIELD NAME " ^ name); *) + let pos, ilsig = read_field_ilsig_idx ctx pos in + (* print_endline (ilsig_s ilsig); *) + f.f_flags <- field_flags_of_int flags; + f.f_name <- name; + f.f_signature <- ilsig; + pos, Field f + | MethodPtr mp -> + let pos, m = sread_from_table ctx false IMethod s pos in + let m = get_method m in + mp.mp_method <- m; + pos, MethodPtr mp + | Method m -> + let startpos = pos in + let pos, rva = sread_i32 s pos in + let pos, iflags = sread_ui16 s pos in + let pos, flags = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, ilsig = read_method_ilsig_idx ctx pos in + let offset = pos - startpos in + let pos, paramlist = ctx.table_sizes.(int_of_table IParam) s pos in + m.m_rva <- Int32.of_int rva; + m.m_flags <- method_flags_of_int iflags flags; + m.m_name <- name; + m.m_signature <- ilsig; + m.m_param_list <- List.rev_map get_param (read_list ctx IParam IParamPtr paramlist offset last pos); + pos, Method m + | ParamPtr pp -> + let pos, p = sread_from_table ctx false IParam s pos in + let p = get_param p in + pp.pp_param <- p; + pos, ParamPtr pp + | Param p -> + let pos, flags = sread_ui16 s pos in + let pos, sequence = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + p.p_flags <- param_flags_of_int flags; + p.p_sequence <- sequence; + p.p_name <- name; + pos, Param p + | InterfaceImpl ii -> + let pos, cls = sread_from_table ctx false ITypeDef s pos in + add_relation ctx cls (InterfaceImpl ii); + let cls = get_type_def cls in + let pos, interface = sread_from_table ctx false ITypeDefOrRef s pos in + ii.ii_class <- cls; + ii.ii_interface <- interface; + pos, InterfaceImpl ii + | MemberRef mr -> + let pos, cls = sread_from_table ctx false IMemberRefParent s pos in + let pos, name = read_sstring_idx ctx pos in + (* print_endline name; *) + (* let pos, signature = read_ilsig_idx ctx pos in *) + let pos, signature = read_field_ilsig_idx ~force_field:false ctx pos in + (* print_endline (ilsig_s signature); *) + mr.memr_class <- cls; + mr.memr_name <- name; + mr.memr_signature <- signature; + add_relation ctx cls (MemberRef mr); + pos, MemberRef mr + | Constant c -> + let pos, ctype = read_constant_type ctx s pos in + let pos = pos+1 in + let pos, parent = sread_from_table ctx false IHasConstant s pos in + let pos, blobpos = if ctx.blob_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let blob = ctx.blob_stream in + let blobpos, _ = read_compressed_i32 blob blobpos in + let _, value = read_constant ctx ctype blob blobpos in + c.c_type <- ctype; + c.c_parent <- parent; + c.c_value <- value; + add_relation ctx parent (Constant c); + pos, Constant c + | CustomAttribute ca -> + let pos, parent = sread_from_table ctx false IHasCustomAttribute s pos in + let pos, t = sread_from_table ctx false ICustomAttributeType s pos in + let pos = read_custom_attr_idx ctx ca t pos in + ca.ca_parent <- parent; + ca.ca_type <- t; + ca.ca_value <- None; (* this will be delayed by read_custom_attr_idx *) + add_relation ctx parent (CustomAttribute ca); + pos, CustomAttribute ca + | FieldMarshal fm -> + let pos, parent = sread_from_table ctx false IHasFieldMarshal s pos in + let pos, nativesig = read_nativesig_idx ctx s pos in + fm.fm_parent <- parent; + fm.fm_native_type <- nativesig; + add_relation ctx parent (FieldMarshal fm); + pos, FieldMarshal fm + | DeclSecurity ds -> + let pos, action = sread_ui16 s pos in + let action = action_security_of_int action in + let pos, parent = sread_from_table ctx false IHasDeclSecurity s pos in + let pos, permission_set = read_sblob_idx ctx pos in + ds.ds_action <- action; + ds.ds_parent <- parent; + ds.ds_permission_set <- permission_set; + add_relation ctx parent (DeclSecurity ds); + pos, DeclSecurity ds + | ClassLayout cl -> + let pos, psize = sread_ui16 s pos in + let pos, csize = sread_i32 s pos in + let pos, parent = sread_from_table ctx false ITypeDef s pos in + add_relation ctx parent (ClassLayout cl); + let parent = get_type_def parent in + cl.cl_packing_size <- psize; + cl.cl_class_size <- csize; + cl.cl_parent <- parent; + pos, ClassLayout cl + | FieldLayout fl -> + let pos, offset = sread_i32 s pos in + let pos, field = sread_from_table ctx false IField s pos in + fl.fl_offset <- offset; + fl.fl_field <- get_field field; + add_relation ctx field (FieldLayout fl); + pos, FieldLayout fl + | StandAloneSig sa -> + let pos, ilsig = read_field_ilsig_idx ~force_field:false ctx pos in + (* print_endline (ilsig_s ilsig); *) + sa.sa_signature <- ilsig; + pos, StandAloneSig sa + | EventMap em -> + let startpos = pos in + let pos, parent = sread_from_table ctx false ITypeDef s pos in + let offset = pos - startpos in + let pos, event_list = ctx.table_sizes.(int_of_table IEvent) s pos in + em.em_parent <- get_type_def parent; + em.em_event_list <- List.rev_map get_event (read_list ctx IEvent IEventPtr event_list offset last pos); + add_relation ctx parent (EventMap em); + pos, EventMap em + | EventPtr ep -> + let pos, event = sread_from_table ctx false IEvent s pos in + ep.ep_event <- get_event event; + pos, EventPtr ep + | Event e -> + let pos, flags = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, event_type = sread_from_table ctx false ITypeDefOrRef s pos in + e.e_flags <- event_flags_of_int flags; + e.e_name <- name; + (* print_endline name; *) + e.e_event_type <- event_type; + add_relation ctx event_type (Event e); + pos, Event e + | PropertyMap pm -> + let startpos = pos in + let pos, parent = sread_from_table ctx false ITypeDef s pos in + let offset = pos - startpos in + let pos, property_list = ctx.table_sizes.(int_of_table IProperty) s pos in + pm.pm_parent <- get_type_def parent; + pm.pm_property_list <- List.rev_map get_property (read_list ctx IProperty IPropertyPtr property_list offset last pos); + add_relation ctx parent (PropertyMap pm); + pos, PropertyMap pm + | PropertyPtr pp -> + let pos, property = sread_from_table ctx false IProperty s pos in + pp.prp_property <- get_property property; + pos, PropertyPtr pp + | Property prop -> + let pos, flags = sread_ui16 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, t = read_field_ilsig_idx ~force_field:false ctx pos in + prop.prop_flags <- property_flags_of_int flags; + prop.prop_name <- name; + (* print_endline name; *) + prop.prop_type <- t; + (* print_endline (ilsig_s t); *) + pos, Property prop + | MethodSemantics ms -> + let pos, semantic = sread_ui16 s pos in + let pos, m = sread_from_table ctx false IMethod s pos in + let pos, association = sread_from_table ctx false IHasSemantics s pos in + ms.ms_semantic <- semantic_flags_of_int semantic; + ms.ms_method <- get_method m; + ms.ms_association <- association; + add_relation ctx m (MethodSemantics ms); + add_relation ctx association (MethodSemantics ms); + pos, MethodSemantics ms + | MethodImpl mi -> + let pos, cls = sread_from_table ctx false ITypeDef s pos in + let pos, method_body = sread_from_table ctx false IMethodDefOrRef s pos in + let pos, method_declaration = sread_from_table ctx false IMethodDefOrRef s pos in + mi.mi_class <- get_type_def cls; + mi.mi_method_body <- method_body; + mi.mi_method_declaration <- method_declaration; + add_relation ctx method_body (MethodImpl mi); + pos, MethodImpl mi + | ModuleRef modr -> + let pos, name = read_sstring_idx ctx pos in + modr.modr_name <- name; + (* print_endline name; *) + pos, ModuleRef modr + | TypeSpec ts -> + let pos, signature = read_ilsig_idx ctx pos in + (* print_endline (ilsig_s signature); *) + ts.ts_signature <- signature; + pos, TypeSpec ts + | ENCLog el -> + let pos, token = sread_i32 s pos in + let pos, func_code = sread_i32 s pos in + el.el_token <- token; + el.el_func_code <- func_code; + pos, ENCLog el + | ImplMap im -> + let pos, flags = sread_ui16 s pos in + let pos, forwarded = sread_from_table ctx false IMemberForwarded s pos in + let pos, import_name = read_sstring_idx ctx pos in + let pos, import_scope = sread_from_table ctx false IModuleRef s pos in + im.im_flags <- impl_flags_of_int flags; + im.im_forwarded <- forwarded; + im.im_import_name <- import_name; + im.im_import_scope <- get_module_ref import_scope; + add_relation ctx forwarded (ImplMap im); + pos, ImplMap im + | ENCMap em -> + let pos, token = sread_i32 s pos in + em.encm_token <- token; + pos, ENCMap em + | FieldRVA f -> + let pos, rva = sread_real_i32 s pos in + let pos, field = sread_from_table ctx false IField s pos in + f.fr_rva <- rva; + f.fr_field <- get_field field; + add_relation ctx field (FieldRVA f); + pos, FieldRVA f + | Assembly a -> + let pos, hash_algo = sread_i32 s pos in + let pos, major = sread_ui16 s pos in + let pos, minor = sread_ui16 s pos in + let pos, build = sread_ui16 s pos in + let pos, rev = sread_ui16 s pos in + let pos, flags = sread_i32 s pos in + let pos, public_key = read_sblob_idx ctx pos in + let pos, name = read_sstring_idx ctx pos in + let pos, locale = read_sstring_idx ctx pos in + a.a_hash_algo <- hash_algo_of_int hash_algo; + a.a_major <- major; + a.a_minor <- minor; + a.a_build <- build; + a.a_rev <- rev; + a.a_flags <- assembly_flags_of_int flags; + a.a_public_key <- public_key; + a.a_name <- name; + a.a_locale <- locale; + pos, Assembly a + | AssemblyProcessor ap -> + let pos, processor = sread_i32 s pos in + ap.ap_processor <- processor; + pos, AssemblyProcessor ap + | AssemblyOS aos -> + let pos, platform_id = sread_i32 s pos in + let pos, major = sread_i32 s pos in + let pos, minor = sread_i32 s pos in + aos.aos_platform_id <- platform_id; + aos.aos_major_version <- major; + aos.aos_minor_version <- minor; + pos, AssemblyOS aos + | AssemblyRef ar -> + let pos, major = sread_ui16 s pos in + let pos, minor = sread_ui16 s pos in + let pos, build = sread_ui16 s pos in + let pos, rev = sread_ui16 s pos in + let pos, flags = sread_i32 s pos in + let pos, public_key = read_sblob_idx ctx pos in + let pos, name = read_sstring_idx ctx pos in + let pos, locale = read_sstring_idx ctx pos in + let pos, hash_value = read_sblob_idx ctx pos in + ar.ar_major <- major; + ar.ar_minor <- minor; + ar.ar_build <- build; + ar.ar_rev <- rev; + ar.ar_flags <- assembly_flags_of_int flags; + ar.ar_public_key <- public_key; + ar.ar_name <- name; + (* print_endline name; *) + ar.ar_locale <- locale; + (* print_endline locale; *) + ar.ar_hash_value <- hash_value; + pos, AssemblyRef ar + | AssemblyRefProcessor arp -> + let pos, processor = sread_i32 s pos in + let pos, assembly_ref = sread_from_table ctx false IAssemblyRef s pos in + arp.arp_processor <- processor; + arp.arp_assembly_ref <- get_assembly_ref assembly_ref; + pos, AssemblyRefProcessor arp + | AssemblyRefOS aros -> + let pos, platform_id = sread_i32 s pos in + let pos, major = sread_i32 s pos in + let pos, minor = sread_i32 s pos in + let pos, assembly_ref = sread_from_table ctx false IAssemblyRef s pos in + aros.aros_platform_id <- platform_id; + aros.aros_major <- major; + aros.aros_minor <- minor; + aros.aros_assembly_ref <- get_assembly_ref assembly_ref; + pos, AssemblyRefOS aros + | File file -> + let pos, flags = sread_i32 s pos in + let pos, name = read_sstring_idx ctx pos in + let pos, hash_value = read_sblob_idx ctx pos in + file.file_flags <- file_flag_of_int flags; + file.file_name <- name; + (* print_endline ("file " ^ name); *) + file.file_hash_value <- hash_value; + pos, File file + | ExportedType et -> + let pos, flags = sread_i32 s pos in + let pos, type_def_id = sread_i32 s pos in + let pos, type_name = read_sstring_idx ctx pos in + let pos, type_namespace = read_sstring_idx ctx pos in + let pos, impl = sread_from_table ctx false IImplementation s pos in + et.et_flags <- type_def_flags_of_int flags; + et.et_type_def_id <- type_def_id; + et.et_type_name <- type_name; + et.et_type_namespace <- parse_ns type_namespace; + et.et_implementation <- impl; + add_relation ctx impl (ExportedType et); + pos, ExportedType et + | ManifestResource mr -> + let pos, offset = sread_i32 s pos in + let pos, flags = sread_i32 s pos in + (* printf "offset 0x%x flags 0x%x\n" offset flags; *) + let pos, name = read_sstring_idx ctx pos in + let rpos, i = ctx.table_sizes.(int_of_table IImplementation) s pos in + let pos, impl = + if i = 0 then + rpos, None + else + let pos, ret = sread_from_table ctx false IImplementation s pos in + add_relation ctx ret (ManifestResource mr); + pos, Some ret + in + mr.mr_offset <- offset; + mr.mr_flags <- manifest_resource_flag_of_int flags; + mr.mr_name <- name; + mr.mr_implementation <- impl; + pos, ManifestResource mr + | NestedClass nc -> + let pos, nested = sread_from_table ctx false ITypeDef s pos in + let pos, enclosing = sread_from_table ctx false ITypeDef s pos in + nc.nc_nested <- get_type_def nested; + nc.nc_enclosing <- get_type_def enclosing; + + assert (nc.nc_nested.td_extra_enclosing = None); + nc.nc_nested.td_extra_enclosing <- Some nc.nc_enclosing; + add_relation ctx enclosing (NestedClass nc); + pos, NestedClass nc + | GenericParam gp -> + let pos, number = sread_ui16 s pos in + let pos, flags = sread_ui16 s pos in + let pos, owner = sread_from_table ctx false ITypeOrMethodDef s pos in + let spos, nidx = + if ctx.strings_offset = 2 then + sread_ui16 s pos + else + sread_i32 s pos + in + let pos, name = + if nidx = 0 then + spos, None + else + let pos, ret = read_sstring_idx ctx pos in + (* print_endline ret; *) + pos, Some ret + in + gp.gp_number <- number; + gp.gp_flags <- generic_flags_of_int flags; + gp.gp_owner <- owner; + gp.gp_name <- name; + add_relation ctx owner (GenericParam gp); + pos, GenericParam gp + | MethodSpec mspec -> + let pos, meth = sread_from_table ctx false IMethodDefOrRef s pos in + let pos, instantiation = read_method_ilsig_idx ctx pos in + (* print_endline (ilsig_s instantiation); *) + mspec.mspec_method <- meth; + mspec.mspec_instantiation <- instantiation; + add_relation ctx meth (MethodSpec mspec); + pos, MethodSpec mspec + | GenericParamConstraint gc -> + let pos, owner = sread_from_table ctx false IGenericParam s pos in + let pos, c = sread_from_table ctx false ITypeDefOrRef s pos in + gc.gc_owner <- get_generic_param owner; + gc.gc_constraint <- c; + add_relation ctx owner (GenericParamConstraint gc); + pos, GenericParamConstraint gc + | _ -> assert false + +(* ******* META READING ********* *) + +let preset_sizes ctx rows = + Array.iteri (fun n r -> match r with + | false,_ -> () + | true,nrows -> + (* printf "table %d nrows %d\n" n nrows; *) + let tbl = table_of_int n in + ctx.tables.(n) <- DynArray.init (nrows) (fun id -> mk_meta tbl (id+1)) + ) rows + +(* let read_ *) +let read_meta ctx = + (* read header *) + let s = ctx.meta_stream in + let pos = 4 + 1 + 1 in + let flags = sget s pos in + List.iter (fun i -> if flags land i = i then match i with + | 0x01 -> + ctx.strings_offset <- 4 + | 0x02 -> + ctx.guid_offset <- 4 + | 0x04 -> + ctx.blob_offset <- 4 + | 0x20 -> + assert (not ctx.compressed); + ctx.meta_edit_continue <- true + | 0x80 -> + assert (not ctx.compressed); + ctx.meta_has_deleted <- true + | _ -> assert false + ) [0x01;0x02;0x04;0x20;0x80]; + let rid = sget s (pos+1) in + ignore rid; + let pos = pos + 2 in + let mask = Array.init 8 ( fun n -> sget s (pos + n) ) in + (* loop over masks and check which table is set *) + let set_table = Array.init 64 (fun n -> + let idx = n / 8 in + let bit = n mod 8 in + (mask.(idx) lsr bit) land 0x1 = 0x1 + ) in + let pos = ref (pos + 8 + 8) in (* there is an extra 'sorted' field, which we do not use *) + let rows = Array.mapi (fun i b -> match b with + | false -> false,0 + | true -> + let nidx, nrows = sread_i32 s !pos in + if nrows > 0xFFFF then ctx.table_sizes.(i) <- sread_i32; + pos := nidx; + true,nrows + ) set_table in + set_coded_sizes ctx rows; + (* pre-set all sizes *) + preset_sizes ctx rows; + Array.iteri (fun n r -> match r with + | false,_ -> () + | true,nrows -> + (* print_endline (string_of_int n); *) + let fn = read_table_at ctx (table_of_int n) in + let rec loop_fn n = + if n = nrows then + () + else begin + let p, _ = fn n (n = (nrows-1)) !pos in + pos := p; + loop_fn (n+1) + end + in + loop_fn 0 + ) rows; + () + +let read_padded i npad = + let buf = Buffer.create 10 in + let rec loop n = + let chr = read i in + if chr = '\x00' then begin + let npad = n land 0x3 in + if npad <> 0 then ignore (nread i (4 - npad)); + Buffer.contents buf + end else begin + Buffer.add_char buf chr; + if n = npad then + Buffer.contents buf + else + loop (n+1) + end + in + loop 1 + +let read_meta_tables pctx header module_cache = + let i = pctx.r.i in + seek_rva pctx (fst header.clr_meta); + let magic = nread i 4 in + if magic <> "BSJB" then error ("Error reading metadata table: Expected magic 'BSJB'. Got " ^ magic); + let major = read_ui16 i in + let minor = read_ui16 i in + ignore major; ignore minor; (* no use for them *) + ignore (read_i32 i); (* reserved *) + let vlen = read_i32 i in + let ver = nread i vlen in + ignore ver; + + (* meta storage header *) + ignore (read_ui16 i); (* reserved *) + let nstreams = read_ui16 i in + let rec streams n acc = + let offset = read_i32 i in + let size = read_real_i32 i in + let name = read_padded i 32 in + let acc = { + str_offset = offset; + str_size = size; + str_name = name; + } :: acc in + if (n+1) = nstreams then + acc + else + streams (n+1) acc + in + let streams = streams 0 [] in + + (* streams *) + let compressed = ref None in + let sstrings = ref "" in + let sblob = ref "" in + let sguid = ref "" in + let sus = ref "" in + let smeta = ref "" in + let extra = ref [] in + List.iter (fun s -> + let rva = Int32.add (fst header.clr_meta) (Int32.of_int s.str_offset) in + seek_rva pctx rva; + match String.lowercase s.str_name with + | "#guid" -> + sguid := nread i (Int32.to_int s.str_size) + | "#strings" -> + sstrings := nread i (Int32.to_int s.str_size) + | "#us" -> + sus := nread i (Int32.to_int s.str_size) + | "#blob" -> + sblob := nread i (Int32.to_int s.str_size) + | "#~" -> + assert (Option.is_none !compressed); + compressed := Some true; + smeta := nread i (Int32.to_int s.str_size) + | "#-" -> + assert (Option.is_none !compressed); + compressed := Some false; + smeta := nread i (Int32.to_int s.str_size) + | _ -> + extra := s :: !extra + ) streams; + let compressed = match !compressed with + | None -> error "No compressed or uncompressed metadata streams was found!" + | Some c -> c + in + let tables = Array.init 64 (fun _ -> DynArray.create ()) in + let ctx = { + compressed = compressed; + strings_stream = !sstrings; + strings_offset = 2; + blob_stream = !sblob; + blob_offset = 2; + guid_stream = !sguid; + guid_offset = 2; + us_stream = !sus; + meta_stream = !smeta; + meta_edit_continue = false; + meta_has_deleted = false; + + module_cache = module_cache; + extra_streams = !extra; + relations = Hashtbl.create 64; + typedefs = Hashtbl.create 64; + tables = tables; + table_sizes = Array.make (max_clr_meta_idx+1) sread_ui16; + + delays = []; + } in + read_meta ctx; + let delays = ctx.delays in + ctx.delays <- []; + List.iter (fun fn -> fn()) delays; + assert (ctx.delays = []); + { + il_tables = ctx.tables; + il_relations = ctx.relations; + il_typedefs = ctx.typedefs; + } + diff --git a/libs/ilib/ilMetaTools.ml b/libs/ilib/ilMetaTools.ml new file mode 100644 index 0000000000000000000000000000000000000000..402099bbb97f01f0f3b2ba0b3cd781e22b500bc3 --- /dev/null +++ b/libs/ilib/ilMetaTools.ml @@ -0,0 +1,472 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) +open IlMeta;; +open IlData;; +open PeReader;; +open ExtString;; + +let rec follow s = match s with + | SReqModifier (_,s) + | SOptModifier (_,s) -> + follow s + | SPinned s -> + follow s + | s -> s + +(* tells if a type_def_or_ref is of type `path` *) +let rec is_type path = function + | TypeDef td -> + td.td_namespace = fst path && td.td_name = snd path + | TypeRef tr -> + tr.tr_namespace = fst path && tr.tr_name = snd path + | TypeSpec ts -> (match follow ts.ts_signature with + | SClass c | SValueType c -> + is_type path c + | SGenericInst(s,_) -> (match follow s with + | SClass c | SValueType c -> + is_type path c + | _ -> false) + | _ -> false) + | _ -> assert false + +let rec get_path type_def_or_ref = match type_def_or_ref with + | TypeDef td -> (match td.td_extra_enclosing with + | None -> + td.td_namespace,[], td.td_name + | Some t2 -> + let ns, nested = match get_path (TypeDef t2) with + | ns,nested, name -> + ns, nested @ [name] + in + ns,nested, td.td_name) + | TypeRef tr -> (match tr.tr_resolution_scope with + | TypeRef tr2 -> + let ns, nested = match get_path (TypeRef tr2) with + | ns,nested, name -> + ns, nested @ [name] + in + ns,nested, tr.tr_name + | _ -> + tr.tr_namespace,[],tr.tr_name) + | TypeSpec ts -> (match follow ts.ts_signature with + | SClass c | SValueType c -> + get_path c + | SGenericInst(s,_) -> (match follow s with + | SClass c | SValueType c -> + get_path c + | _ -> [],[],"") + | _ -> [],[],"") + | _ -> assert false + +let constant_s = function + | IBool true -> "true" + | IBool false -> "false" + | IChar chr -> "'" ^ Char.escaped (Char.chr chr) ^ "'" + | IByte i -> + Printf.sprintf "(byte) 0x%x" i + | IShort i -> + Printf.sprintf "(short) 0x%x" i + | IInt i -> + Printf.sprintf "0x%lx" i + | IInt64 i -> + Printf.sprintf "0x%Lx" i + | IFloat32 f -> + Printf.sprintf "%ff" f + | IFloat64 f -> + Printf.sprintf "%fd" f + | IString s -> "\"" ^ s ^ "\"" + | INull -> "null" + +let path_s = function + | [],[], s -> s + | ns,[], s -> String.concat "." ns ^ "." ^ s + | [],enc, s -> String.concat "@" enc ^ "." ^ s + | ns,enc,s -> String.concat "." ns ^ "." ^ String.concat "@" enc ^ "." ^ s + +let rec ilsig_s = function + | SBoxed -> "boxed" + | SEnum e -> "enum " ^ e + | SType -> "System.Type" + | SVoid -> "void" + | SBool -> "bool" + | SChar -> "char" + | SInt8 -> "int8" + | SUInt8 -> "uint8" + | SInt16 -> "int16" + | SUInt16 -> "uint16" + | SInt32 -> "int32" + | SUInt32 -> "uint32" + | SInt64 -> "int64" + | SUInt64 -> "uint64" + | SFloat32 -> "float" + | SFloat64 -> "double" + | SString -> "string" + | SPointer s -> ilsig_s s ^ "*" + | SManagedPointer s -> ilsig_s s ^ "&" + | SValueType td -> "valuetype " ^ path_s (get_path td) + | SClass cl -> "classtype " ^ path_s (get_path cl) + | STypeParam t | SMethodTypeParam t -> "!" ^ string_of_int t + | SArray (s,opts) -> + ilsig_s s ^ "[" ^ String.concat "," (List.map (function + | Some i,None when i <> 0 -> + string_of_int i ^ "..." + | None, Some i when i <> 0 -> + string_of_int i + | Some s, Some b when b = 0 && s <> 0 -> + string_of_int s ^ "..." + | Some s, Some b when s <> 0 || b <> 0 -> + let b = if b > 0 then b - 1 else b in + string_of_int s ^ "..." ^ string_of_int (s + b) + | _ -> + "" + ) (Array.to_list opts)) ^ "]" + | SGenericInst (t,tl) -> + "generic " ^ (ilsig_s t) ^ "<" ^ String.concat ", " (List.map ilsig_s tl) ^ ">" + | STypedReference -> "typedreference" + | SIntPtr -> "native int" + | SUIntPtr -> "native unsigned int" + | SFunPtr (callconv,ret,args) -> + "function " ^ ilsig_s ret ^ "(" ^ String.concat ", " (List.map ilsig_s args) ^ ")" + | SObject -> "object" + | SVector s -> ilsig_s s ^ "[]" + | SReqModifier (_,s) -> "modreq() " ^ ilsig_s s + | SOptModifier (_,s) -> "modopt() " ^ ilsig_s s + | SSentinel -> "..." + | SPinned s -> "pinned " ^ ilsig_s s + +let rec instance_s = function + | InstConstant c -> constant_s c + | InstBoxed b -> "boxed " ^ instance_s b + | InstType t -> "Type " ^ t + | InstArray il -> "[" ^ String.concat ", " (List.map instance_s il) ^ "]" + | InstEnum e -> "Enum " ^ string_of_int e + +let named_attribute_s (is_prop,name,inst) = + (if is_prop then + "/*prop*/ " + else + "") + ^ name ^ " = " ^ instance_s inst + +let attributes_s (il,nal) = + "(" ^ (String.concat ", " (List.map instance_s il)) ^ (if nal <> [] then ", " ^ (String.concat ", " (List.map named_attribute_s nal)) else "") ^")" + +let meta_root m : meta_root = match m with + | Module r -> Obj.magic r + | TypeRef r -> Obj.magic r + | TypeDef r -> Obj.magic r + | FieldPtr r -> Obj.magic r + | Field r -> Obj.magic r + | MethodPtr r -> Obj.magic r + | Method r -> Obj.magic r + | ParamPtr r -> Obj.magic r + | Param r -> Obj.magic r + | InterfaceImpl r -> Obj.magic r + | MemberRef r -> Obj.magic r + | Constant r -> Obj.magic r + | CustomAttribute r -> Obj.magic r + | FieldMarshal r -> Obj.magic r + | DeclSecurity r -> Obj.magic r + | ClassLayout r -> Obj.magic r + | FieldLayout r -> Obj.magic r + | StandAloneSig r -> Obj.magic r + | EventMap r -> Obj.magic r + | EventPtr r -> Obj.magic r + | Event r -> Obj.magic r + | PropertyMap r -> Obj.magic r + | PropertyPtr r -> Obj.magic r + | Property r -> Obj.magic r + | MethodSemantics r -> Obj.magic r + | MethodImpl r -> Obj.magic r + | ModuleRef r -> Obj.magic r + | TypeSpec r -> Obj.magic r + | ImplMap r -> Obj.magic r + | FieldRVA r -> Obj.magic r + | ENCLog r -> Obj.magic r + | ENCMap r -> Obj.magic r + | Assembly r -> Obj.magic r + | AssemblyProcessor r -> Obj.magic r + | AssemblyOS r -> Obj.magic r + | AssemblyRef r -> Obj.magic r + | AssemblyRefProcessor r -> Obj.magic r + | AssemblyRefOS r -> Obj.magic r + | File r -> Obj.magic r + | ExportedType r -> Obj.magic r + | ManifestResource r -> Obj.magic r + | NestedClass r -> Obj.magic r + | GenericParam r -> Obj.magic r + | MethodSpec r -> Obj.magic r + | GenericParamConstraint r -> Obj.magic r + | _ -> assert false + +let meta_root_ptr p : meta_root_ptr = match p with + | FieldPtr r -> Obj.magic r + | MethodPtr r -> Obj.magic r + | ParamPtr r -> Obj.magic r + | EventPtr r -> Obj.magic r + | _ -> assert false + +let rec ilsig_norm = function + | SVoid -> LVoid + | SBool -> LBool + | SChar -> LChar + | SInt8 -> LInt8 + | SUInt8 -> LUInt8 + | SInt16 -> LInt16 + | SUInt16 -> LUInt16 + | SInt32 -> LInt32 + | SUInt32 -> LUInt32 + | SInt64 -> LInt64 + | SUInt64 -> LUInt64 + | SFloat32 -> LFloat32 + | SFloat64 -> LFloat64 + | SString -> LString + | SPointer p -> LPointer (ilsig_norm p) + | SManagedPointer p -> LManagedPointer (ilsig_norm p) + | SValueType v -> LValueType (get_path v, []) + | SClass v -> LClass (get_path v, []) + | STypeParam i -> LTypeParam i + | SArray (t, opts) -> LArray(ilsig_norm t, opts) + | SGenericInst (p,args) -> (match follow p with + | SClass v -> + LClass(get_path v, List.map ilsig_norm args) + | SValueType v -> + LValueType(get_path v, List.map ilsig_norm args) + | _ -> assert false) + | STypedReference -> LTypedReference + | SIntPtr -> LIntPtr + | SUIntPtr -> LUIntPtr + | SFunPtr(conv,ret,args) -> LMethod(conv,ilsig_norm ret,List.map ilsig_norm args) + | SObject -> LObject + | SVector s -> LVector (ilsig_norm s) + | SMethodTypeParam i -> LMethodTypeParam i + | SReqModifier (_,s) -> ilsig_norm s + | SOptModifier (_,s) -> ilsig_norm s + | SSentinel -> LSentinel + | SPinned s -> ilsig_norm s + | SType -> LClass( (["System"],[],"Type"), []) + | SBoxed -> LObject + | SEnum e -> + let lst = String.nsplit e "." in + let rev = List.rev lst in + match rev with + | hd :: tl -> LValueType( (List.rev tl,[],hd), [] ) + | _ -> assert false + +let ilsig_t s = + { + snorm = ilsig_norm s; + ssig = s; + } + +let ilsig_of_tdef_ref = function + | TypeDef td -> + SClass (TypeDef td) + | TypeRef tr -> + SClass (TypeRef tr) + | TypeSpec ts -> + ts.ts_signature + | s -> + (* error ("Invalid tdef_or_ref: " ^ ilsig_s s) *) + error "Invalid tdef_or_ref" + +let convert_field ctx f = + let constant = List.fold_left (fun c -> function + | Constant c -> + Some c.c_value + | _ -> + c + ) None (Hashtbl.find_all ctx.il_relations (IField, f.f_id)) + in + { + fname = f.f_name; + fflags = f.f_flags; + fsig = ilsig_t f.f_signature; + fconstant = constant; + } + +let convert_generic ctx gp = + let constraints = List.fold_left (fun c -> function + | GenericParamConstraint gc -> + ilsig_t (ilsig_of_tdef_ref gc.gc_constraint) :: c + | _ -> + c + ) [] (Hashtbl.find_all ctx.il_relations (IGenericParam, gp.gp_id)) + in + { + tnumber = gp.gp_number; + tflags = gp.gp_flags; + tname = gp.gp_name; + tconstraints = constraints; + } + +let convert_method ctx m = + let msig = ilsig_t m.m_signature in + let ret, margs = match follow msig.ssig with + | SFunPtr (_,ret,args) -> + (* print_endline m.m_name; *) + (* print_endline (Printf.sprintf "%d vs %d" (List.length args) (List.length m.m_param_list)); *) + (* print_endline (String.concat ", " (List.map (fun p ->string_of_int p.p_sequence ^ ":" ^ p.p_name) m.m_param_list)); *) + (* print_endline (String.concat ", " (List.map (ilsig_s) args)); *) + (* print_endline "\n"; *) + (* TODO: find out WHY this happens *) + let param_list = List.filter (fun p -> p.p_sequence > 0) m.m_param_list in + if List.length param_list <> List.length args then + let i = ref 0 in + ilsig_t ret, List.map (fun s -> + incr i; "arg" ^ (string_of_int !i), { pf_io = []; pf_reserved = [] }, ilsig_t s) args + else + ilsig_t ret, List.map2 (fun p s -> + p.p_name, p.p_flags, ilsig_t s + ) param_list args + | _ -> assert false + in + + let override, types, semantics = + List.fold_left (fun (override,types,semantics) -> function + | MethodImpl mi -> + let declaring = match mi.mi_method_declaration with + | MemberRef mr -> + Some (get_path mr.memr_class, mr.memr_name) + | Method m -> (match m.m_declaring with + | Some td -> + Some (get_path (TypeDef td), m.m_name) + | None -> override) + | _ -> override + in + declaring, types, semantics + | GenericParam gp -> + override, (convert_generic ctx gp) :: types, semantics + | MethodSemantics ms -> + override, types, ms.ms_semantic @ semantics + | _ -> + override,types, semantics + ) (None,[],[]) (Hashtbl.find_all ctx.il_relations (IMethod, m.m_id)) + in + { + mname = m.m_name; + mflags = m.m_flags; + msig = msig; + margs = margs; + mret = ret; + moverride = override; + mtypes = types; + msemantics = semantics; + } + +let convert_prop ctx prop = + let name = prop.prop_name in + let flags = prop.prop_flags in + let psig = ilsig_t prop.prop_type in + let pget, pset = + List.fold_left (fun (get,set) -> function + | MethodSemantics ms when List.mem SGetter ms.ms_semantic -> + assert (get = None); + Some (ms.ms_method.m_name, ms.ms_method.m_flags), set + | MethodSemantics ms when List.mem SSetter ms.ms_semantic -> + assert (set = None); + get, Some (ms.ms_method.m_name,ms.ms_method.m_flags) + | _ -> get,set + ) + (None,None) + (Hashtbl.find_all ctx.il_relations (IProperty, prop.prop_id)) + in + { + pname = name; + psig = psig; + pflags = flags; + pget = pget; + pset = pset; + } + +let convert_event ctx event = + let name = event.e_name in + let flags = event.e_flags in + let esig = ilsig_of_tdef_ref event.e_event_type in + let esig = ilsig_t esig in + let add, remove, eraise = + List.fold_left (fun (add, remove, eraise) -> function + | MethodSemantics ms when List.mem SAddOn ms.ms_semantic -> + assert (add = None); + Some (ms.ms_method.m_name, ms.ms_method.m_flags), remove, eraise + | MethodSemantics ms when List.mem SRemoveOn ms.ms_semantic -> + assert (remove = None); + add, Some (ms.ms_method.m_name,ms.ms_method.m_flags), eraise + | MethodSemantics ms when List.mem SFire ms.ms_semantic -> + assert (eraise = None); + add, remove, Some (ms.ms_method.m_name, ms.ms_method.m_flags) + | _ -> add, remove, eraise + ) + (None,None,None) + (Hashtbl.find_all ctx.il_relations (IEvent, event.e_id)) + in + { + ename = name; + eflags = flags; + esig = esig; + eadd = add; + eremove = remove; + eraise = eraise; + } + +let convert_class ctx path = + let td = Hashtbl.find ctx.il_typedefs path in + let cpath = get_path (TypeDef td) in + let cflags = td.td_flags in + let csuper = Option.map (fun e -> ilsig_t (ilsig_of_tdef_ref e)) td.td_extends in + let cfields = List.map (convert_field ctx) td.td_field_list in + let cmethods = List.map (convert_method ctx) td.td_method_list in + let enclosing = Option.map (fun t -> get_path (TypeDef t)) td.td_extra_enclosing in + let impl, types, nested, props, events, attrs = + List.fold_left (fun (impl,types,nested,props,events,attrs) -> function + | InterfaceImpl ii -> + (ilsig_t (ilsig_of_tdef_ref ii.ii_interface)) :: impl,types,nested, props, events, attrs + | GenericParam gp -> + (impl, (convert_generic ctx gp) :: types, nested, props,events, attrs) + | NestedClass nc -> + assert (nc.nc_enclosing.td_id = td.td_id); + (impl,types,(get_path (TypeDef nc.nc_nested)) :: nested, props, events, attrs) + | PropertyMap pm -> + assert (props = []); + impl,types,nested,List.map (convert_prop ctx) pm.pm_property_list, events, attrs + | EventMap em -> + assert (events = []); + (impl,types,nested,props,List.map (convert_event ctx) em.em_event_list, attrs) + | CustomAttribute a -> + impl,types,nested,props,events,(a :: attrs) + | _ -> + (impl,types,nested,props,events,attrs) + ) + ([],[],[],[],[],[]) + (Hashtbl.find_all ctx.il_relations (ITypeDef, td.td_id)) + in + { + cpath = cpath; + cflags = cflags; + csuper = csuper; + cfields = cfields; + cmethods = cmethods; + cevents = events; + cprops = props; + cimplements = impl; + ctypes = types; + cenclosing = enclosing; + cnested = nested; + cattrs = attrs; + } diff --git a/libs/ilib/ilMetaWriter.ml b/libs/ilib/ilMetaWriter.ml new file mode 100644 index 0000000000000000000000000000000000000000..48956d5fae4208c160643238441742681161589a --- /dev/null +++ b/libs/ilib/ilMetaWriter.ml @@ -0,0 +1,78 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +open PeData;; +open PeReader;; +open IlMeta;; +open IO;; + +(* encoding helpers *) + +let int_of_type_def_vis = function + (* visibility flags - mask 0x7 *) + | VPrivate -> 0x0 (* 0x0 *) + | VPublic -> 0x1 (* 0x1 *) + | VNestedPublic -> 0x2 (* 0x2 *) + | VNestedPrivate -> 0x3 (* 0x3 *) + | VNestedFamily -> 0x4 (* 0x4 *) + | VNestedAssembly -> 0x5 (* 0x5 *) + | VNestedFamAndAssem -> 0x6 (* 0x6 *) + | VNestedFamOrAssem -> 0x7 (* 0x7 *) + +let int_of_type_def_layout = function + (* layout flags - mask 0x18 *) + | LAuto -> 0x0 (* 0x0 *) + | LSequential -> 0x8 (* 0x8 *) + | LExplicit -> 0x10 (* 0x10 *) + +let int_of_type_def_semantics props = List.fold_left (fun acc prop -> + (match prop with + (* semantics flags - mask 0x5A0 *) + | SInterface -> 0x20 (* 0x20 *) + | SAbstract -> 0x80 (* 0x80 *) + | SSealed -> 0x100 (* 0x100 *) + | SSpecialName -> 0x400 (* 0x400 *) + ) lor acc + ) 0 props + +let int_of_type_def_impl props = List.fold_left (fun acc prop -> + (match prop with + (* type implementation flags - mask 0x103000 *) + | IImport -> 0x1000 (* 0x1000 *) + | ISerializable -> 0x2000 (* 0x2000 *) + | IBeforeFieldInit -> 0x00100000 (* 0x00100000 *) + ) lor acc + ) 0 props + +let int_of_type_def_string = function + (* string formatting flags - mask 0x00030000 *) + | SAnsi -> 0x0 (* 0x0 *) + | SUnicode -> 0x00010000 (* 0x00010000 *) + | SAutoChar -> 0x00020000 (* 0x00020000 *) + +let int_of_type_def_flags f = + int_of_type_def_vis f.tdf_vis + logor + int_of_type_def_layout f.tdf_layout + logor + int_of_type_def_semantics f.tdf_semantics + logor + int_of_type_def_impl f.tdf_impl + logor + int_of_type_def_string f.tdf_string diff --git a/libs/ilib/peData.ml b/libs/ilib/peData.ml new file mode 100644 index 0000000000000000000000000000000000000000..5cd4d5d5a47108777e1d53753e13351f6c70b63b --- /dev/null +++ b/libs/ilib/peData.ml @@ -0,0 +1,546 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +(* + This data is based on the + Microsoft Portable Executable and Common Object File Format Specification + Revision 8.3 +*) + +type machine_type = + | TUnknown (* 0 - unmanaged PE files only *) + | Ti386 (* 0x014c - i386 *) + | TR3000 (* 0x0162 - R3000 MIPS Little Endian *) + | TR4000 (* 0x0166 - R4000 MIPS Little Endian *) + | TR10000 (* 0x0168 - R10000 MIPS Little Endian *) + | TWCeMipsV2 (* 0x0169 - MIPS Little Endian running MS Windows CE 2 *) + | TAlpha (* 0x0184 - Alpha AXP *) + | TSh3 (* 0x01a2 - SH3 Little Endian *) + | TSh3Dsp (* 0x01a3 SH3DSP Little Endian *) + | TSh3e (* 0x01a4 SH3E Little Endian *) + | TSh4 (* 0x01a6 SH4 Little Endian *) + | TSh5 (* 0x01a8 SH5 *) + | TArm (* 0x1c0 ARM Little Endian *) + | TArmN (* 0x1c4 ARMv7 (or higher) Thumb mode only Little Endian *) + | TArm64 (* 0xaa64 - ARMv8 in 64-bit mode *) + | TEbc (* 0xebc - EFI byte code *) + | TThumb (* 0x1c2 ARM processor with Thumb decompressor *) + | TAm33 (* 0x1d3 AM33 processor *) + | TPowerPC (* 0x01f0 IBM PowerPC Little Endian *) + | TPowerPCFP (* 0x01f1 IBM PowerPC with FPU *) + | TItanium64 (* 0x0200 Intel IA64 (Itanium) *) + | TMips16 (* 0x0266 MIPS *) + | TAlpha64 (* 0x0284 Alpha AXP64 *) + | TMipsFpu (* 0x0366 MIPS with FPU *) + | TMipsFpu16 (* 0x0466 MIPS16 with FPU *) + | TTriCore (* 0x0520 Infineon *) + | TAmd64 (* 0x8664 AMD x64 and Intel E64T *) + | TM32R (* 0x9041 M32R *) + +type coff_prop = + | RelocsStripped (* 0x1 *) + (* image file only. Indicates the file contains no base relocations and *) + (* must be loaded at its preferred base address. Should not be set for MPE files *) + | ExecutableImage (* 0x2 *) + (* Indicates that the file is an image file (EXE or DLL). Should be set for MPE files *) + | LineNumsStripped (* 0x4 *) + (* COFF line numbers have been removed. This flag should not be set for MPE files *) + (* because they do not use the debug info embedded in the PE file itself. They are saved on PDB files *) + | LocalSymsStripped (* 0x8 *) + (* COFF symbol table entries for local symbols have been removed. It should be set for MPE files *) + | AgressiveWsTrim (* 0x10 *) + (* Agressively trim the working set. This flag should not be set for pure-IL MPE files *) + | LargeAddressAware (* 0x20 *) + (* Application can handle addresses beyond the 2GB range. This flag should not be set for *) + (* pure-IL MPE files of versions 1 and 1.1, but can be set for v2.0 files *) + | BytesReversedLO (* 0x80 *) + (* Little endian. This flag should not be set for pure-IL MPE files *) + | Machine32Bit (* 0x100 *) + (* Machine is based on 32-bit architecture. This flag is usually set by the current *) + (* versions of code generators producing PE files. V2.0+ can produce 64-bit specific images *) + (* which don't have this flag set *) + | DebugStripped (* 0x200 *) + (* Debug information has been removed from the image file *) + | RemovableRunFromSwap (* 0x400 *) + (* If the image file is on removable media, copy and run it from swap file. *) + (* This flag should no be set for pure-IL MPE files *) + | NetRunFromSwap (* 0x800 *) + (* If the image file is on a network, copy and run it from the swap file. *) + (* This flag should no be set for pure-IL MPE files *) + | FileSystem (* 0x1000 *) + (* The image file is a system file (for example, a device driver) *) + (* This flag should not be set for pure-IL MPE files *) + | FileDll (* 0x2000 *) + (* This image file is a DLL rather than an EXE. It cannot be directly run. *) + | UpSystemOnly (* 0x4000 *) + (* The image file should be run on an uniprocessor machine only. *) + (* This flag should not be set for pure-IL MPE files *) + | BytesReversedHI (* 0x8000 *) + (* Big endian *) + (* This flag should not be set for pure-IL MPE files *) + +(* represents a virtual address pointer. It's 64-bit on 64-bit executables, and 32-bit otherwise *) +type pointer = int64 + +(* represents a memory index address on the target architecture. It's 64-bit on 64-bit executables, and 32-bit otherwise *) +type size_t = pointer + +(* relative virtual address. *) +(* it's always 32-bit - which means that PE/COFF files are still limited to the 4GB size *) +type rva = int32 + +(* represents a PE file-bound memory index *) +type size_t_file = int32 + +(* represents a file offset *) +(* there's no point in defining it as int32, as file seek operations need an int *) +type pointer_file = int + +type coff_header = { + coff_machine : machine_type; (* offset 0 - size 2 . *) + (* If the managed PE file is intended for various machine types (AnyCPU), it should be Ti386 *) + coff_nsections : int; (* O2S2 *) + coff_timestamp : int32; (* O4S4 *) + coff_symbol_table_pointer : rva; (* O8S4 *) + (* File pointer of the COFF symbol table. In managed PE files, it is 0 *) + coff_nsymbols : int; (* O12S4 *) + (* Number of entries in the COFF symbol table. Should be 0 in managed PE files *) + coff_optheader_size: int; (* O16S2 *) + (* Size of the PE header *) + coff_props : coff_prop list; +} + +let coff_default_exe_props = [ ExecutableImage; LineNumsStripped; LocalSymsStripped; (* Machine32Bit; *) ] + +let coff_default_dll_props = [ ExecutableImage; LineNumsStripped; LocalSymsStripped; (* Machine32Bit; *) FileDll ] + +type pe_magic = + | P32 (* 0x10b *) + | PRom (* 0x107 *) + | P64 (* 0x20b - called PE32+ on the docs *) + (* allows 64-bit address space while limiting the image size to 2 gb *) + +type subsystem = + | SUnknown (* 0 *) + | SNative (* 1 *) + (* Device drivers and native windows processes *) + | SWGui (* 2 *) + (* Windows GUI subsystem *) + | SWCui (* 3 *) + (* Windows character subsystem *) + | SPCui (* 7 *) + (* Posix character subsystem *) + | SWCeGui (* 9 *) + (* Windows CE subsystem *) + | SEfi (* 10 *) + (* EFI application *) + | SEfiBoot (* 11 *) + (* EFI driver with boot services *) + | SEfiRuntime (* 12 *) + (* EFI driver with run-time services *) + | SEfiRom (* 13 *) + (* EFI ROM Image *) + | SXbox (* 14 *) + +type dll_prop = + | DDynamicBase (* 0x0040 *) + (* DLL can be relocated at load time *) + | DForceIntegrity (* 0x0080 *) + (* Code integrity checks are enforced *) + | DNxCompat (* 0x0100 *) + (* Image is NX compatible *) + | DNoIsolation (* 0x0200 *) + (* Isolation-aware, but do not isolate the image *) + | DNoSeh (* 0x0400 *) + (* No structured exception handling *) + | DNoBind (* 0x0800 *) + (* Do not bind the image *) + | DWdmDriver (* 0x2000 *) + (* A WDM driver *) + | DTerminalServer (* 0x8000 *) + (* Terminal server aware *) + +type directory_type = + | ExportTable (* .edata *) + (* contains information about four other tables, which hold data describing *) + (* unmanaged exports of the PE file. ILAsm and VC++ linker are capable of exposing *) + (* the managed PE file as unmanaged exports *) + | ImportTable (* .idata *) + (* data on unmanaged imports consumed by the PE file. Only the VC++ linker makes *) + (* use of this table, by marking the imported unmanaged external functions used by *) + (* the unmanaged native code embedded in the same assembly. Other compilers only *) + (* contain a single entry - that of the CLR entry function *) + | ResourceTable (* .rsrc *) + (* unmanaged resources embedded in the PE file. Managed resources don't use this *) + | ExceptionTable (* .pdata *) + (* unmanaged exceptions only *) + | CertificateTable + (* points to a table of attribute certificates, used for file authentication *) + (* the first field of this entry is a file pointer rather than an RVA *) + | RelocTable (* .reloc *) + (* relocation table. We need to be aware of it if we use native TLS. *) + (* only the VC++ linker uses native TLS' *) + | DebugTable + (* unmanaged debug data starting address and size. A managed PE file doesn't carry *) + (* embedded debug data, so this data is either all zero or points to a 30-byte debug dir entry *) + (* of type 2 (IMAGE_DEBUG_TYPE_CODEVIEW), which in turn points to a CodeView-style header, containing *) + (* the path to the PDB debug file. *) + | ArchitectureTable + (* for i386, Itanium64 or AMD64, this data is set to all zeros *) + | GlobalPointer + (* the RVA of the value to be stored in the global pointer register. Size must be 0. *) + (* if the target architecture (e.g. i386 or AMD64) don't use the concept of a global pointer, *) + (* it is set to all zeros *) + | TlsTable (* .tls *) + (* The thread-local storage data. Only the VC++ linker and IL assembler produce code that use it *) + | LoadConfigTable + (* data specific to Windows NT OS *) + | BoundImportTable + (* array of bound import descriptors, each of which describes a DLL this image was bound *) + (* at link-time, along with time stamps of the bindings. Iff they are up-to-date, the OS loader *) + (* uses these bindings as a "shortcut" for API import *) + | ImportAddressTable + (* referenced from the Import Directory table (data directory 1) *) + | DelayImport + (* delay-load imports are DLLs described as implicit imports but loaded as explicit imports *) + (* (via calls to the LoadLibrary API) *) + | ClrRuntimeHeader (* .cormeta *) + (* pointer to the clr_runtime_header *) + | Reserved + (* must be zero *) + | Custom of int + +let directory_type_info = function + | ExportTable -> 0, "ExportTable" + | ImportTable -> 1, "ImportTable" + | ResourceTable -> 2, "ResourceTable" + | ExceptionTable -> 3, "ExceptionTable" + | CertificateTable -> 4, "CertificateTable" + | RelocTable -> 5, "RelocTable" + | DebugTable -> 6, "DebugTable" + | ArchitectureTable -> 7, "ArchTable" + | GlobalPointer -> 8, "GlobalPointer" + | TlsTable -> 9, "TlsTable" + | LoadConfigTable -> 10, "LoadConfigTable" + | BoundImportTable -> 11, "BuildImportTable" + | ImportAddressTable -> 12, "ImportAddressTable" + | DelayImport -> 13, "DelayImport" + | ClrRuntimeHeader -> 14, "ClrRuntimeHeader" + | Reserved -> 15, "Reserved" + | Custom i -> i, "Custom" ^ (string_of_int i) + +let directory_type_of_int = function + | 0 -> ExportTable + | 1 -> ImportTable + | 2 -> ResourceTable + | 3 -> ExceptionTable + | 4 -> CertificateTable + | 5 -> RelocTable + | 6 -> DebugTable + | 7 -> ArchitectureTable + | 8 -> GlobalPointer + | 9 -> TlsTable + | 10 -> LoadConfigTable + | 11 -> BoundImportTable + | 12 -> ImportAddressTable + | 13 -> DelayImport + | 14 -> ClrRuntimeHeader + | 15 -> Reserved + | i -> Custom i + +type section_prop = + | SNoPad (* 0x8 *) + (* the section should not be padded to the next boundary. *) + (* OBSOLETE - replaced by SAlign1Bytes *) + | SHasCode (* 0x20 *) + (* the section contains executable code *) + | SHasIData (* 0x40 *) + (* contains initialized data *) + | SHasData (* 0x80 *) + (* contains uninitialized data *) + | SHasLinkInfo (* 0x200 *) + (* contains comments or other information. only valid for object files *) + | SLinkRemove (* 0x1000 *) + (* this will not become part of the image. only valid for object files *) + | SGlobalRel (* 0x8000 *) + (* contains data referenced through the global pointer (GP) *) + | SHas16BitMem (* 0x20000 *) + (* for ARM architecture. The section contains Thumb code *) + | SAlign1Bytes (* 0x100000 *) + (* align data on a 1-byte boundary. valid only for object files *) + | SAlign2Bytes (* 0x200000 *) + | SAlign4Bytes (* 0x300000 *) + | SAlign8Bytes (* 0x400000 *) + | SAlign16Bytes (* 0x500000 *) + | SAlign32Bytes (* 0x600000 *) + | SAlign64Bytes (* 0x700000 *) + | SAlign128Bytes (* 0x800000 *) + | SAlign256Bytes (* 0x900000 *) + | SAlign512Bytes (* 0xA00000 *) + | SAlign1024Bytes (* 0xB00000 *) + | SAlign2048Bytes (* 0xC00000 *) + | SAlign4096Bytes (* 0xD00000 *) + | SAlign8192Bytes (* 0xE00000 *) + | SHasExtRelocs (* 0x1000000 *) + (* section contains extended relocations *) + | SCanDiscard (* 0x02000000 *) + (* section can be discarded as needed *) + | SNotCached (* 0x04000000 *) + (* section cannot be cached *) + | SNotPaged (* 0x08000000 *) + (* section is not pageable *) + | SShared (* 0x10000000 *) + (* section can be shared in memory *) + | SExec (* 0x20000000 *) + (* section can be executed as code *) + | SRead (* 0x40000000 *) + (* section can be read *) + | SWrite (* 0x80000000 *) + (* section can be written to *) + +type pe_section = { + s_name : string; + (* an 8-byte, null-padded UTF-8 encoded string *) + s_vsize : size_t_file; + (* the total size of the section when loaded into memory. *) + (* if less than s_rawsize, the section is zero-padded *) + (* should be set to 0 on object files *) + s_vaddr : rva; + (* the RVA of the beginning of the section *) + s_raw_size : size_t_file; + (* the size of the initialized data on disk, rounded up to a multiple *) + (* of the file alignment value. If it's less than s_vsize, it should be *) + (* zero filled. It may happen that rawsize is greater than vsize. *) + s_raw_pointer : pointer_file; + (* the file pointer to the first page of the section within the COFF file *) + (* on executable images, this must be a multiple of file aignment value. *) + (* for object files, it should be aligned on a 4byte boundary *) + s_reloc_pointer : pointer_file; + (* the file pointer to the beginning of relocation entries for this section *) + (* this is set to zero for executable images or if there are no relocations *) + s_line_num_pointer : pointer_file; + (* the file pointer to the beginning of line-number entries for this section *) + (* must be 0 : COFF debugging image is deprecated *) + s_nrelocs : int; + (* number of relocation entries *) + s_nline_nums : int; + (* number of line number entries *) + s_props : section_prop list; + (* properties of the section *) +} + +(* The size of the PE header is not fixed. It depends on the number of data directories defined in the header *) +(* and is specified in the optheader_size in the COFF header *) +(* object files don't have this; but it's required for image files *) +type pe_header = { + pe_coff_header : coff_header; + (* Standard fields *) + pe_magic : pe_magic; + pe_major : int; + pe_minor : int; + pe_code_size : int; + (* size of the code section (.text) or the sum of all code sections, *) + (* if multiple sections exist. The IL assembler always emits a single code section *) + pe_init_size : int; + pe_uinit_size : int; + pe_entry_addr : rva; + (* RVA of the beginning of the entry point function. For unmanaged DLLs, this can be 0 *) + (* For managed PE files, this always points to the CLR invocation stub *) + pe_base_code : rva; + (* The address that is relative to the image base of the beginning-of-code section *) + (* when it's loaded into memory *) + pe_base_data : rva; + (* The address that is relative to the image base of the beginning-of-data section *) + (* when it's loaded into memory *) + + (* COFF Windows extension *) + pe_image_base : pointer; + (* The preferred address of the first byte of image when loaded into memory. *) + (* Should be a multiple of 64K *) + pe_section_alignment : int; + (* The alignment in bytes of sections when they are loaded into memory *) + (* It must be greater than or equal to FileAlignment. The default is the page size *) + (* for the architecture *) + (* x86 MPE files should have an alignment of 8KB, even though only 4KB would be needed *) + (* for compatibility with 64-bits *) + pe_file_alignment : int; + (* The alignment factor in bytes that is used to align the raw data of sections *) + (* in the image file. The value should be a POT between 512 and 64K. *) + (* If secion_alignment is less than architecture's page size, file_alignment must match *) + (* secion_alignment *) + pe_major_osver : int; + pe_minor_osver : int; + pe_major_imgver : int; + pe_minor_imgver : int; + pe_major_subsysver : int; + pe_minor_subsysver : int; + pe_image_size : int; + (* the size of the image in bytes, as the image is loaded into memory *) + (* must be a multiple of section_alignment *) + pe_headers_size : int; + (* the combined size of an MSDOS stub, PE header, and section headers *) + (* rounded up to a multiple of FileAlignment *) + pe_checksum : int32; + pe_subsystem : subsystem; + pe_dll_props : dll_prop list; + (* in MPE files of v1.0, always set to 0; In MPE of v1.1 and later, *) + (* always set to 0x400 (DNoSeh) *) + pe_stack_reserve : size_t; + (* the size of the stack to reserve. Only pe_stack_commit is committed *) + pe_stack_commit : size_t; + (* the size of the stack to commit *) + pe_heap_reserve : size_t; + (* the size of the local heap space to reserve. Only pe_heap_commit is committed *) + pe_heap_commit : size_t; + (* the size of the heap to commit *) + pe_ndata_dir : int; + (* the number of data-directory entries in the remainder of the optional header *) + (* should be at least 16. Although is possible to emit more than 16 data directories, *) + (* all existing managed compilers emit exactly 16 data directories, with the last never *) + (* used (reserved) *) + pe_data_dirs : (rva * size_t_file) array; + (* data directories are RVA's that point to sections on the PE that have special significance *) + (* see directory_type docs *) + + (* sections *) + pe_sections : pe_section array; +} + +(* raw .idata table *) +(* not used : only here for documentation purposes *) +type idata_table_raw = { + impr_lookup_table : rva; + (* the RVA of the lookup table *) + impr_timestamp : int32; + (* on bound images, it's set to the timestamp of the DLL *) + impr_fchain : int32; + (* the index of the first forwarder reference - which are references *) + (* that are both imported and exported *) + impr_name : rva; + (* the RVA to an ASCII string that contains the name of the DLL *) + impr_address_table : rva; + (* RVA of the import address table. The contents are identical to the imp_lookup_table *) + (* until the image is bound *) +} + +(* a symbol lookup can happen either by name, or by ordinal. *) +(* lookup by name happens to be an extra indirection, as the loader *) +(* uses the name to look up the export ordinal anyway. *) +(* Most (if not all) MPE will do a lookup by name, though *) +type symbol_lookup = + | SName of int * string + | SOrdinal of int + +type idata_table = { + imp_name : string; + (* ASCII string that contains the name of the DLL *) + imp_imports : symbol_lookup list; +} + +type clr_flag = + | FIlOnly (* 0x1 *) + (* the image file contains IL code only, with no embedded native unmanaged code *) + (* this can cause some problems on WXP+, because the .reloc section is ignored when this flag is set *) + (* e.g. if native TLS support is used. In this case the VC++ compiler unsets this flag *) + | F32BitRequired (* 0x2 *) + (* the file can be only loaded into a 32-bit process *) + | FIlLibrary (* 0x4 *) + (* obsolete *) + | FSigned (* 0x8 *) + (* the image file is protected with a strong name signature *) + | FNativeEntry (* 0x10 *) + (* the executable's entry point is an unmanaged method. *) + (* the EntryPointToken / EntryPointRVA field of the CLR header *) + (* contains the RVA of this native method *) + | FTrackDebug (* 0x10000 *) + (* the CLR loader is required to track debug information about the methods. This flag is not used *) + +type clr_header = { + clr_cb : int; + (* size of header *) + clr_major : int; + clr_minor : int; + + (* symbol table and startup information *) + clr_meta : rva * size_t_file; + clr_flags : clr_flag list; + clr_entry_point : rva; + (* metadata identifier (token) of the entry point for the image file *) + (* can be 0 for DLL images. This field identifies a method belonging to this module *) + (* or a module containing the entry point method. This field may contain RVA of the *) + (* embedded native entry point method, if FNativeEntry flag is set *) + + (* binding information *) + clr_res : rva * size_t_file; + (* RVA of managed resources *) + clr_sig : rva * size_t_file; + (* RVA of the hash data for this PE file, used by the loader for binding and versioning *) + + (* regular fixup and binding information *) + clr_codeman : rva * size_t_file; + (* code manager table - RESERVED and should be 0 *) + clr_vtable_fix : rva * size_t_file; + (* RVA of an array of vtable fixups. Only VC++ linker and IL assembler produce data in this array *) + clr_export_address : rva * size_t_file; + (* rva of addresses of jump thunks. obsolete and should be set to 0 *) +} + +(* unused structure: documentation purposes only *) +type clr_stream_header = { + str_offset : pointer_file; + (* the (relative to the start of metadata) offset in the file for this stream *) + str_size : size_t_file; + (* the size of the stream in bytes *) + str_name : string; + (* name of the stream - a zero-terminated ASCII string no longer than 31 characters (plus 0 terminator) *) + (* if the stream name is smaller, it can be reduced - but must be padded to the 4-byte boundary *) +} + +(* unused structure: documentation purposes only *) +type clr_meta_table = { + (* storage signature *) + meta_magic : string; + (* always BSJB *) + meta_major : int; + meta_minor : int; + (* meta_extra : int; *) + (* reserved; always 0 *) + meta_ver : string; + (* encoded by first passing its length *) + + (* storage header *) + (* meta_flags : int; *) + (* reserved; always 0 *) + meta_nstreams : int; + (* number of streams *) + meta_strings_stream : clr_stream_header; + (* #Strings: a string heap containing the names of metadata items *) + meta_blob_stream : clr_stream_header; + (* #Blob: blob heap containing internal metadata binary object, such as default values, signatures, etc *) + meta_guid_stream : clr_stream_header; + (* #GUID: a GUID heap *) + meta_us_stream : clr_stream_header; + (* #US: user-defined strings *) + meta_meta_stream : clr_stream_header; + (* may be either: *) + (* #~: compressed (optimized) metadata stream *) + (* #-: uncompressed (unoptimized) metadata stream *) + meta_streams : clr_stream_header list; + (* custom streams *) +} diff --git a/libs/ilib/peDataDebug.ml b/libs/ilib/peDataDebug.ml new file mode 100644 index 0000000000000000000000000000000000000000..50a7605199c4b5e782e2c859277957960734dc9f --- /dev/null +++ b/libs/ilib/peDataDebug.ml @@ -0,0 +1,184 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) +open PeData;; +open Printf;; + +let machine_type_s m = match m with + | TUnknown -> "TUnknown" + | Ti386 -> "Ti386" + | TR3000 -> "TR3000" + | TR4000 -> "TR4000" + | TR10000 -> "TR10000" + | TWCeMipsV2 -> "TWCeMipsV2" + | TAlpha -> "TAlpha" + | TSh3 -> "TSh3" + | TSh3Dsp -> "TSh3Dsp" + | TSh3e -> "TSh3e" + | TSh4 -> "TSh4" + | TSh5 -> "TSh5" + | TArm -> "TArm" + | TArmN -> "TArmN" + | TArm64 -> "TArm64" + | TEbc -> "TEbc" + | TThumb -> "TThumb" + | TAm33 -> "TAm33" + | TPowerPC -> "TPowerPC" + | TPowerPCFP -> "TPowerPCFP" + | TItanium64 -> "TItanium64" + | TMips16 -> "TMips16" + | TAlpha64 -> "TAlpha64" + | TMipsFpu -> "TMipsFpu" + | TMipsFpu16 -> "TMipsFpu16" + | TTriCore -> "TTriCore" + | TAmd64 -> "TAmd64" + | TM32R -> "TM32R" + +let coff_prop_s p = match p with + | RelocsStripped -> "RelocsStripped" + | ExecutableImage -> "ExecutableImage" + | LineNumsStripped -> "LineNumsStripped" + | LocalSymsStripped -> "LocalSymsStripped" + | AgressiveWsTrim -> "AgressiveWsTrim" + | LargeAddressAware -> "LargeAddressAware" + | BytesReversedLO -> "BytesReversedLO" + | Machine32Bit -> "Machine32Bit" + | DebugStripped -> "DebugStripped" + | RemovableRunFromSwap -> "RemovableRunFromSwap" + | NetRunFromSwap -> "NetRunFromSwap" + | FileSystem -> "FileSystem" + | FileDll -> "FileDll" + | UpSystemOnly -> "UpSystemOnly" + | BytesReversedHI -> "BytesReversedHI" + +let coff_header_s h = + sprintf "#COFF_HEADER\n\tmachine: %s\n\tnsections: %d\n\ttimestamp: %ld\n\tsymbol_tbl_pointer: %ld\n\tnsymbols: %d\n\toptheader_size: %x\n\tprops: [%s]\n" + (machine_type_s h.coff_machine) + h.coff_nsections + h.coff_timestamp + h.coff_symbol_table_pointer + h.coff_nsymbols + h.coff_optheader_size + (String.concat ", " (List.map coff_prop_s h.coff_props)) + +let pe_magic_s = function + | P32 -> "P32" + | PRom -> "PRom" + | P64 -> "P64" + +let subsystem_s = function + | SUnknown -> "SUnknown" (* 0 *) + | SNative -> "SNative" (* 1 *) + | SWGui -> "SWGui" (* 2 *) + | SWCui -> "SWCui" (* 3 *) + | SPCui -> "SPCui" (* 7 *) + | SWCeGui -> "SWCeGui" (* 9 *) + | SEfi -> "SEfi" (* 10 *) + | SEfiBoot -> "SEfiBoot" (* 11 *) + | SEfiRuntime -> "SEfiRuntime" (* 12 *) + | SEfiRom -> "SEfiRom" (* 13 *) + | SXbox -> "SXbox" (* 14 *) + +let dll_prop_s = function + | DDynamicBase -> "DDynamicBase" (* 0x0040 *) + | DForceIntegrity -> "DForceIntegrity" (* 0x0080 *) + | DNxCompat -> "DNxCompat" (* 0x0100 *) + | DNoIsolation -> "DNoIsolation" (* 0x0200 *) + | DNoSeh -> "DNoSeh" (* 0x0400 *) + | DNoBind -> "DNoBind" (* 0x0800 *) + | DWdmDriver -> "DWdmDriver" (* 0x2000 *) + | DTerminalServer -> "DTerminalServer" (* 0x8000 *) + +let section_prop_s = function + | SNoPad -> "SNoPad" + | SHasCode -> "SHasCode" + | SHasIData -> "SHasIData" + | SHasData -> "SHasData" + | SHasLinkInfo -> "SHasLinkInfo" + | SLinkRemove -> "SLinkRemove" + | SGlobalRel -> "SGlobalRel" + | SHas16BitMem -> "SHas16BitMem" + | SAlign1Bytes -> "SAlign1Bytes" + | SAlign2Bytes -> "SAlign2Bytes" + | SAlign4Bytes -> "SAlign4Bytes" + | SAlign8Bytes -> "SAlign8Bytes" + | SAlign16Bytes -> "SAlign16Bytes" + | SAlign32Bytes -> "SAlign32Bytes" + | SAlign64Bytes -> "SAlign64Bytes" + | SAlign128Bytes -> "SAlign128Bytes" + | SAlign256Bytes -> "SAlign256Bytes" + | SAlign512Bytes -> "SAlign512Bytes" + | SAlign1024Bytes -> "SAlign1024Bytes" + | SAlign2048Bytes -> "SAlign2048Bytes" + | SAlign4096Bytes -> "SAlign4096Bytes" + | SAlign8192Bytes -> "SAlign8192Bytes" + | SHasExtRelocs -> "SHasExtRelocs" + | SCanDiscard -> "SCanDiscard" + | SNotCached -> "SNotCached" + | SNotPaged -> "SNotPaged" + | SShared -> "SShared" + | SExec -> "SExec" + | SRead -> "SRead" + | SWrite -> "SWrite" + +let pe_section_s s = + Printf.sprintf "\t%s :\n\t\trva: %lx\n\t\traw size: %lx\n\t\tprops: [%s]" + s.s_name + s.s_vaddr + s.s_raw_size + (String.concat ", " (List.map section_prop_s s.s_props)) + +let data_dirs_s a = + let lst = Array.to_list (Array.mapi (fun i (r,l) -> + let _,s = directory_type_info (directory_type_of_int i) in + Printf.sprintf "%s: %lx (%lx)" s r l + ) a) in + String.concat "\n\t\t" lst + +let pe_header_s h = + sprintf "#PE_HEADER\n\tmagic: %s\n\tmajor.minor %d.%d\n\tsubsystem: %s\n\tdll props: [%s]\n\tndata_dir: %i\n\t\t%s\n#SECTIONS\n%s" + (pe_magic_s h.pe_magic) + h.pe_major h.pe_minor + (subsystem_s h.pe_subsystem) + (String.concat ", " (List.map dll_prop_s h.pe_dll_props)) + h.pe_ndata_dir + (data_dirs_s h.pe_data_dirs) + (String.concat "\n" (List.map pe_section_s (Array.to_list h.pe_sections))) + +let symbol_lookup_s = function + | SName (hint,s) -> "SName(" ^ string_of_int hint ^ ", " ^ s ^ ")" + | SOrdinal i -> "SOrdinal(" ^ string_of_int i ^ ")" + +let idata_table_s t = + sprintf "#IMPORT %s:\n\t%s" + t.imp_name + (String.concat "\n\t" (List.map symbol_lookup_s t.imp_imports)) + +let clr_flag_s = function + | FIlOnly -> "FIlOnly" (* 0x1 *) + | F32BitRequired -> "F32BitRequired" (* 0x2 *) + | FIlLibrary -> "FIlLibrary" (* 0x4 *) + | FSigned -> "FSigned" (* 0x8 *) + | FNativeEntry -> "FNativeEntry" (* 0x10 *) + | FTrackDebug -> "FTrackDebug" (* 0x10000 *) + +let clr_header_s h = + sprintf "#CLR v%d.%d\n\tflags: %s" + h.clr_major + h.clr_minor + (String.concat ", " (List.map clr_flag_s h.clr_flags)) diff --git a/libs/ilib/peReader.ml b/libs/ilib/peReader.ml new file mode 100644 index 0000000000000000000000000000000000000000..6016ff192201382909ab12960501c23667a771ad --- /dev/null +++ b/libs/ilib/peReader.ml @@ -0,0 +1,493 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +open PeData;; +open IO;; +open ExtString;; +open ExtList;; + +exception Error_message of string + +type reader_ctx = { + ch : Pervasives.in_channel; + i : IO.input; + verbose : bool; +} + +type ctx = { + r : reader_ctx; + pe_header : pe_header; + read_word : IO.input -> pointer; +} + +let error msg = raise (Error_message msg) + +let seek r pos = + seek_in r.ch pos + +let pos r = + Pervasives.pos_in r.ch + +let info r msg = + if r.verbose then + print_endline (msg()) + +let machine_type_of_int i = match i with + | 0x0 -> TUnknown (* 0 - unmanaged PE files only *) + | 0x014c -> Ti386 (* 0x014c - i386 *) + | 0x0162 -> TR3000 (* 0x0162 - R3000 MIPS Little Endian *) + | 0x0166 -> TR4000 (* 0x0166 - R4000 MIPS Little Endian *) + | 0x0168 -> TR10000 (* 0x0168 - R10000 MIPS Little Endian *) + | 0x0169 -> TWCeMipsV2 (* 0x0169 - MIPS Litlte Endian running MS Windows CE 2 *) + | 0x0184 -> TAlpha (* 0x0184 - Alpha AXP *) + | 0x01a2 -> TSh3 (* 0x01a2 - SH3 Little Endian *) + | 0x01a3 -> TSh3Dsp (* 0x01a3 SH3DSP Little Endian *) + | 0x01a4 -> TSh3e (* 0x01a4 SH3E Little Endian *) + | 0x01a6 -> TSh4 (* 0x01a6 SH4 Little Endian *) + | 0x01a8 -> TSh5 + | 0x01c0 -> TArm (* 0x1c0 ARM Little Endian *) + | 0x01c2 -> TThumb (* 0x1c2 ARM processor with Thumb decompressor *) + | 0x01c4 -> TArmN (* 0x1c0 ARM Little Endian *) + | 0xaa64 -> TArm64 + | 0xebc -> TEbc + | 0x01d3 -> TAm33 (* 0x1d3 AM33 processor *) + | 0x01f0 -> TPowerPC (* 0x01f0 IBM PowerPC Little Endian *) + | 0x01f1 -> TPowerPCFP (* 0x01f1 IBM PowerPC with FPU *) + | 0x0200 -> TItanium64 (* 0x0200 Intel IA64 (Itanium( *) + | 0x0266 -> TMips16 (* 0x0266 MIPS *) + | 0x0284 -> TAlpha64 (* 0x0284 Alpha AXP64 *) + | 0x0366 -> TMipsFpu (* 0x0366 MIPS with FPU *) + | 0x0466 -> TMipsFpu16 (* 0x0466 MIPS16 with FPU *) + | 0x0520 -> TTriCore (* 0x0520 Infineon *) + | 0x8664 -> TAmd64 (* 0x8664 AMD x64 and Intel E64T *) + | 0x9041 -> TM32R (* 0x9041 M32R *) + | _ -> assert false + +let coff_props_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x1 -> RelocsStripped (* 0x1 *) + | 0x2 -> ExecutableImage (* 0x2 *) + | 0x4 -> LineNumsStripped (* 0x4 *) + | 0x8 -> LocalSymsStripped (* 0x8 *) + | 0x10 -> AgressiveWsTrim (* 0x10 *) + | 0x20 -> LargeAddressAware (* 0x20 *) + | 0x80 -> BytesReversedLO (* 0x80 *) + | 0x100 -> Machine32Bit (* 0x100 *) + | 0x200 -> DebugStripped (* 0x200 *) + | 0x400 -> RemovableRunFromSwap (* 0x400 *) + | 0x800 -> NetRunFromSwap (* 0x800 *) + | 0x1000 -> FileSystem (* 0x1000 *) + | 0x2000 -> FileDll (* 0x2000 *) + | 0x4000 -> UpSystemOnly (* 0x4000 *) + | 0x8000 -> BytesReversedHI (* 0x8000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1;0x2;0x4;0x8;0x10;0x20;0x80;0x100;0x200;0x400;0x800;0x1000;0x2000;0x4000;0x8000] + +let section_props_of_int32 props = List.fold_left (fun acc i -> + if (Int32.logand props i) = i then (match i with + | 0x8l -> SNoPad + | 0x20l -> SHasCode + | 0x40l -> SHasIData + | 0x80l -> SHasData + | 0x200l -> SHasLinkInfo + | 0x1000l -> SLinkRemove + | 0x8000l -> SGlobalRel + | 0x20000l -> SHas16BitMem + | 0x100000l -> SAlign1Bytes + | 0x200000l -> SAlign2Bytes + | 0x300000l -> SAlign4Bytes + | 0x400000l -> SAlign8Bytes + | 0x500000l -> SAlign16Bytes + | 0x600000l -> SAlign32Bytes + | 0x700000l -> SAlign64Bytes + | 0x800000l -> SAlign128Bytes + | 0x900000l -> SAlign256Bytes + | 0xA00000l -> SAlign512Bytes + | 0xB00000l -> SAlign1024Bytes + | 0xC00000l -> SAlign2048Bytes + | 0xD00000l -> SAlign4096Bytes + | 0xE00000l -> SAlign8192Bytes + | 0x1000000l -> SHasExtRelocs + | 0x02000000l -> SCanDiscard + | 0x04000000l -> SNotCached + | 0x08000000l -> SNotPaged + | 0x10000000l -> SShared + | 0x20000000l -> SExec + | 0x40000000l -> SRead + | 0x80000000l -> SWrite + | _ -> assert false) :: acc + else + acc) [] [ 0x8l; 0x20l; 0x40l; 0x80l; 0x200l; 0x1000l; 0x8000l; 0x20000l; 0x100000l; 0x200000l; 0x300000l; 0x400000l; 0x500000l; 0x600000l; 0x700000l; 0x800000l; 0x900000l; 0xA00000l; 0xB00000l; 0xC00000l; 0xD00000l; 0xE00000l; 0x1000000l; 0x02000000l; 0x04000000l; 0x08000000l; 0x10000000l; 0x20000000l; 0x40000000l; 0x80000000l; ] + +let subsystem_of_int i = match i with + | 0 -> SUnknown (* 0 *) + | 1 -> SNative (* 1 *) + | 2 -> SWGui (* 2 *) + | 3 -> SWCui (* 3 *) + | 7 -> SPCui (* 7 *) + | 9 -> SWCeGui (* 9 *) + | 10 -> SEfi (* 10 *) + | 11 -> SEfiBoot (* 11 *) + | 12 -> SEfiRuntime (* 12 *) + | 13 -> SEfiRom (* 13 *) + | 14 -> SXbox (* 14 *) + | _ -> error ("Unknown subsystem " ^ string_of_int i) + +let dll_props_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x0040 -> DDynamicBase (* 0x0040 *) + | 0x0080 -> DForceIntegrity (* 0x0080 *) + | 0x0100 -> DNxCompat (* 0x0100 *) + | 0x0200 -> DNoIsolation (* 0x0200 *) + | 0x0400 -> DNoSeh (* 0x0400 *) + | 0x0800 -> DNoBind (* 0x0800 *) + | 0x2000 -> DWdmDriver (* 0x2000 *) + | 0x8000 -> DTerminalServer (* 0x8000 *) + | _ -> assert false) :: acc + else + acc) [] [0x40;0x80;0x100;0x200;0x400;0x800;0x2000;0x8000] + +let pe_magic_of_int i = match i with + | 0x10b -> P32 + | 0x107 -> PRom + | 0x20b -> P64 + | _ -> error ("Unknown PE magic number: " ^ string_of_int i) + +let clr_flags_of_int iprops = List.fold_left (fun acc i -> + if (iprops land i) = i then (match i with + | 0x1 -> FIlOnly (* 0x1 *) + | 0x2 -> F32BitRequired (* 0x2 *) + | 0x4 -> FIlLibrary (* 0x4 *) + | 0x8 -> FSigned (* 0x8 *) + | 0x10 -> FNativeEntry (* 0x10 *) + | 0x10000 -> FTrackDebug (* 0x10000 *) + | _ -> assert false) :: acc + else + acc) [] [0x1;0x2;0x4;0x8;0x10;0x10000] + +let get_dir dir ctx = + let idx,name = directory_type_info dir in + try + ctx.pe_header.pe_data_dirs.(idx) + with + | Invalid_argument _ -> + error (Printf.sprintf "The directory '%s' of index '%i' is required but is missing on this file" name idx) + +let read_rva = read_real_i32 + +let read_word is64 i = + if is64 then read_i64 i else Int64.logand (Int64.of_int32 (read_real_i32 i)) 0xFFFFFFFFL + +let read_coff_header i = + let machine = machine_type_of_int (read_ui16 i) in + let nsections = read_ui16 i in + let stamp = read_real_i32 i in + let symbol_table_pointer = read_rva i in + let nsymbols = read_i32 i in + let optheader_size = read_ui16 i in + let props = read_ui16 i in + let props = coff_props_of_int (props) in + { + coff_machine = machine; + coff_nsections = nsections; + coff_timestamp = stamp; + coff_symbol_table_pointer = symbol_table_pointer; + coff_nsymbols = nsymbols; + coff_optheader_size = optheader_size; + coff_props = props; + } + +let read_pe_header r header = + let i = r.i in + let sections_offset = (pos r) + header.coff_optheader_size in + let magic = pe_magic_of_int (read_ui16 i) in + let major = read_byte i in + let minor = read_byte i in + let code_size = read_i32 i in + let init_size = read_i32 i in + let uinit_size = read_i32 i in + let entry_addr = read_rva i in + let base_code = read_rva i in + let base_data, read_word = match magic with + | P32 | PRom -> + read_rva i, read_word false + | P64 -> + Int32.zero, read_word true + in + + (* COFF Windows extension *) + let image_base = read_word i in + let section_alignment = read_i32 i in + let file_alignment = read_i32 i in + let major_osver = read_ui16 i in + let minor_osver = read_ui16 i in + let major_imgver = read_ui16 i in + let minor_imgver = read_ui16 i in + let major_subsysver = read_ui16 i in + let minor_subsysver = read_ui16 i in + ignore (read_i32 i); (* reserved *) + let image_size = read_i32 i in + let headers_size = read_i32 i in + let checksum = read_real_i32 i in + let subsystem = subsystem_of_int (read_ui16 i) in + let dll_props = dll_props_of_int (read_ui16 i) in + let stack_reserve = read_word i in + let stack_commit = read_word i in + let heap_reserve = read_word i in + let heap_commit = read_word i in + ignore (read_i32 i); (* reserved *) + let ndata_dir = read_i32 i in + let data_dirs = Array.init ndata_dir (fun n -> + let addr = read_rva i in + let size = read_rva i in + addr,size) + in + (* sections *) + let nsections = header.coff_nsections in + seek r sections_offset; + let sections = Array.init nsections (fun n -> + let name = nread i 8 in + let name = try + let index = String.index name '\x00' in + String.sub name 0 index + with | Not_found -> + name + in + (*TODO check for slash names *) + let vsize = read_rva i in + let vaddr = read_rva i in + let raw_size = read_rva i in + let raw_pointer = read_i32 i in + let reloc_pointer = read_i32 i in + let line_num_pointer = read_i32 i in + let nrelocs = read_ui16 i in + let nline_nums = read_ui16 i in + let props = section_props_of_int32 (read_rva i) in + { + s_name = name; + s_vsize =vsize; + s_vaddr =vaddr; + s_raw_size =raw_size; + s_raw_pointer =raw_pointer; + s_reloc_pointer =reloc_pointer; + s_line_num_pointer =line_num_pointer; + s_nrelocs =nrelocs; + s_nline_nums =nline_nums; + s_props =props; + } + ) in + { + pe_coff_header = header; + pe_magic = magic; + pe_major = major; + pe_minor = minor; + pe_code_size = code_size; + pe_init_size = init_size; + pe_uinit_size = uinit_size; + pe_entry_addr = entry_addr; + pe_base_code = base_code; + pe_base_data = base_data; + pe_image_base = image_base; + pe_section_alignment = section_alignment; + pe_file_alignment = file_alignment; + pe_major_osver = major_osver; + pe_minor_osver = minor_osver; + pe_major_imgver = major_imgver; + pe_minor_imgver = minor_imgver; + pe_major_subsysver = major_subsysver; + pe_minor_subsysver = minor_subsysver; + pe_image_size = image_size; + pe_headers_size = headers_size; + pe_checksum = checksum; + pe_subsystem = subsystem; + pe_dll_props = dll_props; + pe_stack_reserve = stack_reserve; + pe_stack_commit = stack_commit; + pe_heap_reserve = heap_reserve; + pe_heap_commit = heap_commit; + pe_ndata_dir = ndata_dir; + pe_data_dirs = data_dirs; + pe_sections = sections; + } + +let create_r ch props = + let verbose = PMap.mem "IL_VERBOSE" props in + let i = IO.input_channel ch in + { + ch = ch; + i = i; + verbose = verbose; + } + +(* converts an RVA into a file offset. *) +let convert_rva ctx rva = + let sections = ctx.pe_header.pe_sections in + let nsections = Array.length sections in + let sec = + (* linear search. TODO maybe binary search for many sections? *) + let rec loop n = + if n >= nsections then error (Printf.sprintf "The RVA %lx is outside sections bounds!" rva); + let sec = sections.(n) in + if rva >= sec.s_vaddr && (rva < (Int32.add sec.s_vaddr sec.s_raw_size)) then + sec + else + loop (n+1) + in + loop 0 + in + let diff = Int32.to_int (Int32.sub rva sec.s_vaddr) in + sec.s_raw_pointer + diff + +let seek_rva ctx rva = seek ctx.r (convert_rva ctx rva) + +let read_cstring i = + let ret = Buffer.create 8 in + let rec loop () = + let chr = read i in + if chr = '\x00' then + Buffer.contents ret + else begin + Buffer.add_char ret chr; + loop() + end + in + loop() + +(* reads import data *) +let read_idata ctx = match get_dir ImportTable ctx with + | 0l,_ | _,0l -> + [] + | rva,size -> + seek_rva ctx rva; + let i = ctx.r.i in + let rec loop acc = + let lookup_table = read_rva i in + if lookup_table = Int32.zero then + acc + else begin + let timestamp = read_real_i32 i in + let fchain = read_real_i32 i in + let name_rva = read_rva i in + let addr_table = read_rva i in + ignore addr_table; ignore fchain; ignore timestamp; + loop ((lookup_table,name_rva) :: acc) + end + in + let tables = loop [] in + List.rev_map (function (lookup_table,name_rva) -> + seek_rva ctx lookup_table; + let is_64 = ctx.pe_header.pe_magic = P64 in + let imports_data = if not is_64 then + let rec loop acc = + let flags = read_real_i32 i in + if flags = Int32.zero then + acc + else begin + let is_ordinal = Int32.logand flags 0x80000000l = 0x80000000l in + loop ( (is_ordinal, if is_ordinal then Int32.logand flags 0xFFFFl else Int32.logand flags 0x7FFFFFFFl) :: acc ) + end + in + loop [] + else + let rec loop acc = + let flags = read_i64 i in + if flags = Int64.zero then + acc + else begin + let is_ordinal = Int64.logand flags 0x8000000000000000L = 0x8000000000000000L in + loop ( (is_ordinal, Int64.to_int32 (if is_ordinal then Int64.logand flags 0xFFFFL else Int64.logand flags 0x7FFFFFFFL)) :: acc ) + end + in + loop [] + in + let imports = List.rev_map (function + | true, ord -> + SOrdinal (Int32.to_int ord) + | false, rva -> + seek_rva ctx rva; + let hint = read_ui16 i in + SName (hint, read_cstring i) + ) imports_data in + seek_rva ctx name_rva; + let name = read_cstring i in + { + imp_name = name; + imp_imports = imports; + } + ) tables + +let has_clr_header ctx = match get_dir ClrRuntimeHeader ctx with + | 0l,_ | _,0l -> + false + | _ -> + true + +let read_clr_header ctx = match get_dir ClrRuntimeHeader ctx with + | 0l,_ | _,0l -> + error "This PE file does not have managed content" + | rva,size -> + seek_rva ctx rva; + let i = ctx.r.i in + let cb = read_i32 i in + let major = read_ui16 i in + let minor = read_ui16 i in + let read_tbl i = + let rva = read_rva i in + let size = read_real_i32 i in + rva,size + in + let meta = read_tbl i in + let corflags = clr_flags_of_int (read_i32 i) in + let entry_point = read_rva i in + let res = read_tbl i in + let clrsig = read_tbl i in + let codeman = read_tbl i in + let vtable_fix = read_tbl i in + let export_addr = read_tbl i in + { + clr_cb = cb; + clr_major = major; + clr_minor = minor; + clr_meta = meta; + clr_flags = corflags; + clr_entry_point = entry_point; + clr_res = res; + clr_sig = clrsig; + clr_codeman = codeman; + clr_vtable_fix = vtable_fix; + clr_export_address = export_addr; + } + +let read r = + let i = r.i in + if read i <> 'M' || read i <> 'Z' then + error "MZ magic header not found: Is the target file really a PE?"; + seek r 0x3c; + let pe_sig_offset = read_i32 i in + seek r pe_sig_offset; + if really_nread i 4 <> "PE\x00\x00" then + error "Invalid PE header signature: PE expected"; + let header = read_coff_header i in + let pe_header = read_pe_header r header in + { + r = r; + pe_header = pe_header; + read_word = read_word (pe_header.pe_magic = P64); + } diff --git a/libs/ilib/peWriter.ml b/libs/ilib/peWriter.ml new file mode 100644 index 0000000000000000000000000000000000000000..cd8d40919edc9eafbe55c1a70f090a00ea4237cd --- /dev/null +++ b/libs/ilib/peWriter.ml @@ -0,0 +1,158 @@ +(* + * This file is part of ilLib + * Copyright (c)2004-2013 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + *) + +open PeData;; +open IO;; +open ExtString;; +open ExtList;; + +exception Error_message of string + +let error msg = raise (Error_message msg) + +type 'a writer_ctx = { + out : 'a IO.output; +} + +let int_of_machine_type t = match t with + | TUnknown -> 0x0 (* 0 - unmanaged PE files only *) + | Ti386 -> 0x014c (* 0x014c - i386 *) + | TR3000 -> 0x0162 (* 0x0162 - R3000 MIPS Little Endian *) + | TR4000 -> 0x0166 (* 0x0166 - R4000 MIPS Little Endian *) + | TR10000 -> 0x0168 (* 0x0168 - R10000 MIPS Little Endian *) + | TWCeMipsV2 -> 0x0169 (* 0x0169 - MIPS Litlte Endian running MS Windows CE 2 *) + | TAlpha -> 0x0184 (* 0x0184 - Alpha AXP *) + | TSh3 -> 0x01a2 (* 0x01a2 - SH3 Little Endian *) + | TSh3Dsp -> 0x01a3 (* 0x01a3 SH3DSP Little Endian *) + | TSh3e -> 0x01a4 (* 0x01a4 SH3E Little Endian *) + | TSh4 -> 0x01a6 (* 0x01a6 SH4 Little Endian *) + | TSh5 -> 0x01a8 + | TArm -> 0x01c0 (* 0x1c0 ARM Little Endian *) + | TArmN -> 0x01c4 (* 0x1c0 ARM Little Endian *) + | TArm64 -> 0xaa64 (* 0x1c0 ARM Little Endian *) + | TEbc -> 0xebc + | TThumb -> 0x01c2 (* 0x1c2 ARM processor with Thumb decompressor *) + | TAm33 -> 0x01d3 (* 0x1d3 AM33 processor *) + | TPowerPC -> 0x01f0 (* 0x01f0 IBM PowerPC Little Endian *) + | TPowerPCFP -> 0x01f1 (* 0x01f1 IBM PowerPC with FPU *) + | TItanium64 -> 0x0200 (* 0x0200 Intel IA64 (Itanium( *) + | TMips16 -> 0x0266 (* 0x0266 MIPS *) + | TAlpha64 -> 0x0284 (* 0x0284 Alpha AXP64 *) + | TMipsFpu -> 0x0366 (* 0x0366 MIPS with FPU *) + | TMipsFpu16 -> 0x0466 (* 0x0466 MIPS16 with FPU *) + | TTriCore -> 0x0520 (* 0x0520 Infineon *) + | TAmd64 -> 0x8664 (* 0x8664 AMD x64 and Intel E64T *) + | TM32R -> 0x9041 (* 0x9041 M32R *) + +let int_of_coff_props props = List.fold_left (fun acc prop -> + (match prop with + | RelocsStripped -> 0x1 (* 0x1 *) + | ExecutableImage -> 0x2 (* 0x2 *) + | LineNumsStripped -> 0x4 (* 0x4 *) + | LocalSymsStripped -> 0x8 (* 0x8 *) + | AgressiveWsTrim -> 0x10 (* 0x10 *) + | LargeAddressAware -> 0x20 (* 0x20 *) + | BytesReversedLO -> 0x80 (* 0x80 *) + | Machine32Bit -> 0x100 (* 0x100 *) + | DebugStripped -> 0x200 (* 0x200 *) + | RemovableRunFromSwap -> 0x400 (* 0x400 *) + | NetRunFromSwap -> 0x800 (* 0x800 *) + | FileSystem -> 0x1000 (* 0x1000 *) + | FileDll -> 0x2000 (* 0x2000 *) + | UpSystemOnly -> 0x4000 (* 0x4000 *) + | BytesReversedHI -> 0x8000 (* 0x8000 *) + ) lor acc + ) 0 props + +let int32_of_section_prop props = List.fold_left (fun acc prop -> + Int32.logor (match prop with + | SNoPad -> 0x8l (* 0x8 *) + | SHasCode -> 0x20l (* 0x20 *) + | SHasIData -> 0x40l (* 0x40 *) + | SHasData -> 0x80l (* 0x80 *) + | SHasLinkInfo -> 0x200l (* 0x200 *) + | SLinkRemove -> 0x1000l (* 0x1000 *) + | SGlobalRel -> 0x8000l (* 0x8000 *) + | SHas16BitMem -> 0x20000l (* 0x20000 *) + | SAlign1Bytes -> 0x100000l (* 0x100000 *) + | SAlign2Bytes -> 0x200000l (* 0x200000 *) + | SAlign4Bytes -> 0x300000l (* 0x300000 *) + | SAlign8Bytes -> 0x400000l (* 0x400000 *) + | SAlign16Bytes -> 0x500000l (* 0x500000 *) + | SAlign32Bytes -> 0x600000l (* 0x600000 *) + | SAlign64Bytes -> 0x700000l (* 0x700000 *) + | SAlign128Bytes -> 0x800000l (* 0x800000 *) + | SAlign256Bytes -> 0x900000l (* 0x900000 *) + | SAlign512Bytes -> 0xA00000l (* 0xA00000 *) + | SAlign1024Bytes -> 0xB00000l (* 0xB00000 *) + | SAlign2048Bytes -> 0xC00000l (* 0xC00000 *) + | SAlign4096Bytes -> 0xD00000l (* 0xD00000 *) + | SAlign8192Bytes -> 0xE00000l (* 0xE00000 *) + | SHasExtRelocs -> 0x1000000l (* 0x1000000 *) + | SCanDiscard -> 0x02000000l (* 0x02000000 *) + | SNotCached -> 0x04000000l (* 0x04000000 *) + | SNotPaged -> 0x08000000l (* 0x08000000 *) + | SShared -> 0x10000000l (* 0x10000000 *) + | SExec -> 0x20000000l (* 0x20000000 *) + | SRead -> 0x40000000l (* 0x40000000 *) + | SWrite -> 0x80000000l (* 0x80000000 *) + ) acc + ) 0l props + +let int_of_pe_magic m = match m with + | P32 -> 0x10b + | PRom -> 0x107 + | P64 -> 0x20b + +let int_of_subsystem s = match s with + | SUnknown -> 0 (* 0 *) + | SNative -> 1 (* 1 *) + | SWGui -> 2 (* 2 *) + | SWCui -> 3 (* 3 *) + | SPCui -> 7 (* 7 *) + | SWCeGui -> 9 (* 9 *) + | SEfi -> 10 (* 10 *) + | SEfiBoot -> 11 (* 11 *) + | SEfiRuntime -> 12 (* 12 *) + | SEfiRom -> 13 (* 13 *) + | SXbox -> 14 (* 14 *) + +let int_of_dll_props props = List.fold_left (fun acc prop -> + (match prop with + | DDynamicBase -> 0x0040 (* 0x0040 *) + | DForceIntegrity -> 0x0080 (* 0x0080 *) + | DNxCompat -> 0x0100 (* 0x0100 *) + | DNoIsolation -> 0x0200 (* 0x0200 *) + | DNoSeh -> 0x0400 (* 0x0400 *) + | DNoBind -> 0x0800 (* 0x0800 *) + | DWdmDriver -> 0x2000 (* 0x2000 *) + | DTerminalServer -> 0x8000 (* 0x8000 *) + ) lor acc + ) 0 props + +let int_of_clr_flags props = List.fold_left (fun acc prop -> + (match prop with + | FIlOnly -> 0x1 (* 0x1 *) + | F32BitRequired -> 0x2 (* 0x2 *) + | FIlLibrary -> 0x4 (* 0x4 *) + | FSigned -> 0x8 (* 0x8 *) + | FNativeEntry -> 0x10 (* 0x10 *) + | FTrackDebug -> 0x10000 (* 0x10000 *) + ) lor acc + ) 0 props diff --git a/libs/javalib/Makefile b/libs/javalib/Makefile index a0b789a2dcdbdca98e256b992802d7a3f10c012d..2032fc62ae7b921c016a8df71c1ff3c63cc51bd0 100644 --- a/libs/javalib/Makefile +++ b/libs/javalib/Makefile @@ -1,5 +1,22 @@ -all: - ocamlopt -g -I ../extlib -a -o java.cmxa jData.ml jReader.ml - +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +SRC=jData.ml jReader.ml + +all: bytecode native + +native: java.cmxa +bytecode: java.cma + +java.cmxa: $(SRC) + $(OCAMLOPT) -g -I ../extlib -a -o java.cmxa $(SRC) + +java.cma: $(SRC) + $(OCAMLC) -g -I ../extlib -a -o java.cma $(SRC) + clean: - rm -rf java.cmxa java.lib java.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) + rm -rf java.cmxa java.cma java.lib java.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cmo) + +.PHONY: all bytecode native clean + +Makefile: ; +$(SRC): ; diff --git a/libs/javalib/jReader.ml b/libs/javalib/jReader.ml index 5c0d5b17d6e605b0a934d1c2e9df54d033b15573..6752d40fd841e6760d66173504d42586de17d44e 100644 --- a/libs/javalib/jReader.ml +++ b/libs/javalib/jReader.ml @@ -82,7 +82,7 @@ let parse_constant max idx ch = (* TODO: correctly decode modified UTF8 *) KUtf8String str | 15 -> - let reft = get_reference_type (read_ui16 ch) idx in + let reft = get_reference_type (IO.read_byte ch) idx in let dynref = index() in KMethodHandle (reft, dynref) | 16 -> @@ -575,6 +575,7 @@ let parse_class ch = None | _ -> do_default() ) consts ch attribs in + IO.close_in ch; { cversion = majorv, minorv; cpath = this; diff --git a/libs/neko/Makefile b/libs/neko/Makefile index 5b592cde29fd89a916c6fb0d69f66acf990e6445..793fc470ccc1594013119948ec0f1d65467dfa69 100644 --- a/libs/neko/Makefile +++ b/libs/neko/Makefile @@ -1,5 +1,23 @@ -all: - ocamlopt -I ../extlib -a -o neko.cmxa nast.ml nxml.ml binast.ml nbytecode.ml ncompile.ml +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +SRC=nast.ml nxml.ml binast.ml nbytecode.ml ncompile.ml + +all: bytecode native + +native: neko.cmxa + +bytecode: neko.cma + +neko.cmxa: $(SRC) + $(OCAMLOPT) -I ../extlib -a -o neko.cmxa $(SRC) + +neko.cma: $(SRC) + $(OCAMLC) -I ../extlib -a -o neko.cma $(SRC) clean: - rm -rf neko.cmxa neko.lib neko.a $(wilcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) \ No newline at end of file + rm -rf neko.cmxa neko.cma neko.lib neko.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cmo) + +.PHONY: all bytecode native clean + +Makefile: ; +$(SRC): ; diff --git a/libs/neko/binast.ml b/libs/neko/binast.ml index 4af62f60e64b4391b835fec3ebddd275b125649b..26b5cf86da7ac3fcd0328602aa2bfdbf8001ef41 100644 --- a/libs/neko/binast.ml +++ b/libs/neko/binast.ml @@ -73,7 +73,7 @@ let write_constant ctx = function b ctx 9; write_string ctx s | Int32 n -> - b ctx 10; + b ctx 5; (* same as Int *) IO.write_real_i32 ctx.ch n let write_op ctx op = diff --git a/libs/neko/ncompile.ml b/libs/neko/ncompile.ml index cb367205d4ea27300596982d5b3cd4138533a4d9..98bbdab9b4b5468d42a9a08b6b0bd96d33c495c0 100644 --- a/libs/neko/ncompile.ml +++ b/libs/neko/ncompile.ml @@ -51,6 +51,7 @@ type context = { mutable nenv : int; mutable stack : int; mutable loop_limit : int; + mutable loop_traps : int; mutable limit : int; mutable traps : int list; mutable breaks : ((unit -> unit) * pos) list; @@ -200,18 +201,21 @@ let save_breaks ctx = let oldc = ctx.continues in let oldb = ctx.breaks in let oldl = ctx.loop_limit in + let oldt = ctx.loop_traps in + ctx.loop_traps <- List.length ctx.traps; ctx.loop_limit <- ctx.stack; ctx.breaks <- []; ctx.continues <- []; - (ctx , oldc, oldb , oldl) + (ctx , oldc, oldb , oldl, oldt) -let process_continues (ctx,oldc,_,_) = +let process_continues (ctx,oldc,_,_,_) = List.iter (fun (f,_) -> f()) ctx.continues; ctx.continues <- oldc -let process_breaks (ctx,_,oldb,oldl) = +let process_breaks (ctx,_,oldb,oldl, oldt) = List.iter (fun (f,_) -> f()) ctx.breaks; ctx.loop_limit <- oldl; + ctx.loop_traps <- oldt; ctx.breaks <- oldb let check_breaks ctx = @@ -570,6 +574,7 @@ and compile_function main params e = env = PMap.empty; nenv = 0; traps = []; + loop_traps = 0; limit = main.stack; (* // dup *) version = main.version; @@ -841,16 +846,8 @@ and compile ctx tail (e,p) = jend()) | ETry (e,v,ecatch) -> let trap = trap ctx in - let breaks = ctx.breaks in - let continues = ctx.continues in - ctx.breaks <- []; - ctx.continues <- []; ctx.traps <- ctx.stack :: ctx.traps; compile ctx false e; - if ctx.breaks <> [] then error "Break in try...catch is not allowed" p; - if ctx.continues <> [] then error "Continue in try...catch is not allowed" p; - ctx.breaks <- breaks; - ctx.continues <- continues; write ctx EndTrap; ctx.traps <- (match ctx.traps with [] -> assert false | _ :: l -> l); let jend = jmp ctx in @@ -877,18 +874,30 @@ and compile ctx tail (e,p) = (match e with | None -> () | Some e -> compile ctx false e); - if ctx.loop_limit <> ctx.stack then begin - let s = ctx.stack in - write ctx (Pop(ctx.stack - ctx.loop_limit)); - ctx.stack <- s; - end; + let s = ctx.stack in + let n = ref (List.length ctx.traps - ctx.loop_traps) in + List.iter (fun t -> + if !n > 0 then begin + decr n; + if ctx.stack > t then write ctx (Pop(ctx.stack - t)); + write ctx EndTrap; + end + ) ctx.traps; + if ctx.loop_limit <> ctx.stack then write ctx (Pop(ctx.stack - ctx.loop_limit)); + ctx.stack <- s; ctx.breaks <- (jmp ctx , p) :: ctx.breaks | EContinue -> - if ctx.loop_limit <> ctx.stack then begin - let s = ctx.stack in - write ctx (Pop(ctx.stack - ctx.loop_limit)); - ctx.stack <- s; - end; + let s = ctx.stack in + let n = ref (List.length ctx.traps - ctx.loop_traps) in + List.iter (fun t -> + if !n > 0 then begin + decr n; + if ctx.stack > t then write ctx (Pop(ctx.stack - t)); + write ctx EndTrap; + end + ) ctx.traps; + if ctx.loop_limit <> ctx.stack then write ctx (Pop(ctx.stack - ctx.loop_limit)); + ctx.stack <- s; ctx.continues <- (jmp ctx , p) :: ctx.continues | EFunction (params,e) -> compile_function ctx params e @@ -993,6 +1002,7 @@ let compile version ast = version = version; stack = 0; loop_limit = 0; + loop_traps = 0; limit = -1; locals = PMap.empty; ops = DynArray.create(); diff --git a/libs/objsize/META b/libs/objsize/META new file mode 100644 index 0000000000000000000000000000000000000000..ee9947a94b82d556beb2583657e1cfd54aeb9a2a --- /dev/null +++ b/libs/objsize/META @@ -0,0 +1,3 @@ +version="0.16" +archive(byte)="objsize.cma" +archive(native)="objsize.cmxa" diff --git a/libs/objsize/Makefile b/libs/objsize/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..93f3b8ebb89afa7351de6de7fb15e1f9a2d2c2ca --- /dev/null +++ b/libs/objsize/Makefile @@ -0,0 +1,29 @@ +CFLAGS = -I . +LIBS = +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +SRC=objsize.mli objsize.ml + +all: bytecode native + +bytecode: objsize.cma + +native: objsize.cmxa + +objsize.cma: c_objsize.o $(SRC) + $(OCAMLC) -a -o objsize.cma $(LIBS) $(SRC) + +objsize.cmxa: c_objsize.o $(SRC) + $(OCAMLOPT) -a -o objsize.cmxa $(LIBS) $(SRC) + +c_objsize.o: c_objsize.c + $(OCAMLC) $(CFLAGS) c_objsize.c + +clean: + rm -rf $(wildcard *.cma) $(wildcard *.cmxa) $(wildcard *.cmx) $(wildcard *.cmi) $(wildcard *.cmo) $(wildcard *.obj) $(wildcard *.o) + +.PHONY: all bytecode native clean + +Makefile: ; +$(SRC): ; +c_objsize.c: ; diff --git a/libs/objsize/README b/libs/objsize/README new file mode 100644 index 0000000000000000000000000000000000000000..12789575167508673af5fedec1c2a1d3064d9d28 --- /dev/null +++ b/libs/objsize/README @@ -0,0 +1,89 @@ +What is this? + + This is a small OCaml library for computing size of OCaml values. + It computes count of words used for values, count of values' headers, + maximal depth of values. There are functions to get size of values + in bytes too. + + +How to use it? + + See objsize.mli for documentation. + + +How to compile/install it? + + Run "make " in this directory. Useful make targets are: + - lib : build objsize library + - tests : build tests with fresh-compiled library + - install : install package "objsize" using findlib + - uninstall : uninstall package "objsize" + - clean : clean working directory + - tests-installed : clean working directory and build test programs + assuming you have installed package "objsize" using findlib. + + +How it works? + + C-function walks through values and uses header's field "color" + to mark visited values, then restores original values' "color". + Colors are stored using rle-like compression to decrease memory + usage. + + +Bugs? + + 1. Some constant values (like lists of integers) are + constructed at compile time and placed outside of both heaps, + and size of these values will be returned as 0. + + 2. Internal function is not fully tail-recursive, + so generally it uses stack proportionally to the depth + of the value. + + There is an optimization to handle long lists and some + other datastructures: when objsize walks through the + structured block, the goto is used instead of recursive + call to walk into the last value that should be visited. + + This optimization is not general, and the best solution + would be to use heap memory instead of stack memory to store + "walk path", but I don't need it now (please contribute + if you want). + + 3. It requires gnu make. It's possible to write Makefile for + nmake, but I have no MSVC to test. The best solution is + to use ocamlbuild. Either I will write ocamlbuild script + later, or you will contribute it. But it's possible + to build without any makefiles: see original Makefile for + details. + + 4. OCaml 3.11 has new implementation of heap. Versions of + objsize >= 0.12 work only with OCaml 3.11 heap, versions + of objsize <= 0.11 work only with OCaml <= 3.10.2 heap. + Runtime failure will be raised if you link objsize >= 0.12 + with OCaml < 3.11. + + 5. "Bugs" section is too long. + + +License? + + Dual: BSD/GPL. + + +Changes? + + 0.1 - 2007-12-13 - Initial public release. + 0.11 - 2007-12-14 - "configure" made right. Now it works on 64-bits too. + 0.12 - 2009-04-08 - Works with OCaml 3.11, installs with findlib. + 0.13 - 2009-09-01 - Tiny change about so/dll suffix for unix/windows. + 0.14 - 2010-01-26 - Fixing so/dll again. + Some stack usage optimization, + see the modified Bug #2 description. + 0.15 - 2010-04-15 - Fixing bug appeared in 0.14. (thanks to Steven Ramsay) + 0.16 - 2010-08-11 - Fixing bug appeared in 0.14. (thanks to SerP) + +Author? + + Dmitry Grebeniuk diff --git a/libs/objsize/alloc.c b/libs/objsize/alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..2e7181743df2de2d77652e436c10038f2f9c630e --- /dev/null +++ b/libs/objsize/alloc.c @@ -0,0 +1,40 @@ +#if (!defined(ALLOC_PRF) || !defined(ALLOC_TYPE)) +#error +#endif + +#include "util.h" +#include +#include + + +ALLOC_TYPE* ALLOC_PRF(_alloc)(size_t count) + { + return malloc(count * sizeof(ALLOC_TYPE)); + } + +void ALLOC_PRF(_free)(ALLOC_TYPE* arr) + { + free(arr); + } + +ALLOC_TYPE* ALLOC_PRF(_realloc)(ALLOC_TYPE* arr, size_t count) + { + size_t newsz = count * sizeof(ALLOC_TYPE); + ALLOC_TYPE* newarr = realloc(arr, newsz); + if (count != 0 && newarr == NULL) + { + static char msg[128]; + sprintf + ( msg + , "realloc(%p, %u*%u=%u) failed: to provide an alternative behaviour." + , arr, (unsigned int) count, (unsigned int) sizeof(ALLOC_TYPE) + , (unsigned int) newsz + ); + ABORT(msg); + }; + return newarr; + } + + +#undef ALLOC_PRF +#undef ALLOC_TYPE diff --git a/libs/objsize/bitarray.c b/libs/objsize/bitarray.c new file mode 100644 index 0000000000000000000000000000000000000000..1944289380fdc2c8003e7c767c93adda671749b1 --- /dev/null +++ b/libs/objsize/bitarray.c @@ -0,0 +1,103 @@ +#if ((!defined(PRF))) +#error +#endif + +#define BITS_OF_CHAR 8 + +/* +size_t PRF(_sizebytes)(size_t n); +TYPE PRF(_get)(TYPE arr[], size_t i); +void PRF(_set)(TYPE arr[], size_t i, TYPE val); +*/ + +#define ALPRF(x) bitarrayalloc##x + +#define ALLOC_TYPE unsigned char +#define ALLOC_PRF(x) ALPRF(x) +#include "alloc.c" + + +size_t wordalign(size_t n) + { + size_t al = sizeof(int); + size_t m = al % n; + if (m == 0) + { + return n; + } + else + { + return n + al - m; + } + } + + +size_t PRF(_sizebytes)(size_t n) + { + return wordalign(n/BITS_OF_CHAR); + } + + +unsigned char* PRF(_alloc)(size_t count) + { + return ALPRF(_alloc)(PRF(_sizebytes)(count)); + } + + +void PRF(_free)(unsigned char* arr) + { + ALPRF(_free)(arr); + } + + +unsigned char* PRF(_realloc)(unsigned char* arr, size_t newcount) + { + return ALPRF(_realloc)(arr, PRF(_sizebytes)(newcount)); + } + + +#define LVAL(arr, i) ((arr)[(i)/BITS_OF_CHAR]) +#define MASK(i) (1<<((i)%BITS_OF_CHAR)) + +int PRF(_get)(unsigned char arr[], size_t i) + { + return ((LVAL(arr,i) & MASK(i)) ? 1 : 0); + } + +void PRF(_set)(unsigned char arr[], size_t i, int val) + { + unsigned char mask = MASK(i); + if (val) + { + LVAL(arr,i) |= mask; + } + else + { + LVAL(arr,i) &= ~mask; + } + return; + } + +void PRF(_init)(unsigned char arr[], size_t sz, int val) + { + size_t bytesize = sz/BITS_OF_CHAR; + size_t i; + unsigned char valbyte = val ? (-1) : 0; + for (i=0; i + +// FROM byterun/gc.h +#define Caml_white (0 << 8) +#define Caml_gray (1 << 8) +#define Caml_blue (2 << 8) +#define Caml_black (3 << 8) +#define Colornum_hd(hd) ((color_t) (((hd) >> 8) & 3)) +#define Coloredhd_hd(hd,colnum) (((hd) & ~Caml_black) | ((colnum) << 8)) + +#define Col_white (Caml_white >> 8) +#define Col_gray (Caml_gray >> 8) +#define Col_blue (Caml_blue >> 8) +#define Col_black (Caml_black >> 8) + + +#define COLORS_INIT_COUNT 256 + +//-------------------------------------------------------- +// From byterun/memory.h: + +#define Not_in_heap 0 +#define In_heap 1 +#define In_young 2 +#define In_static_data 4 +#define In_code_area 8 + +#ifdef ARCH_SIXTYFOUR + +// 64 bits: Represent page table as a sparse hash table +int caml_page_table_lookup(void * addr); +#define Classify_addr(a) (caml_page_table_lookup((void *)(a))) + +#else + +// 32 bits: Represent page table as a 2-level array +#define Pagetable2_log 11 +#define Pagetable2_size (1 << Pagetable2_log) +#define Pagetable1_log (Page_log + Pagetable2_log) +#define Pagetable1_size (1 << (32 - Pagetable1_log)) +CAMLextern unsigned char * caml_page_table[Pagetable1_size]; + +#define Pagetable_index1(a) (((uintnat)(a)) >> Pagetable1_log) +#define Pagetable_index2(a) \ + ((((uintnat)(a)) >> Page_log) & (Pagetable2_size - 1)) +#define Classify_addr(a) \ + caml_page_table[Pagetable_index1(a)][Pagetable_index2(a)] + +#endif + +#define Is_in_heap_or_young(a) (Classify_addr(a) & (In_heap | In_young)) + +//-------------------------------------------------------- + + +unsigned char* colors = NULL; +size_t colors_bitcap = 0; +size_t colors_writeindex = 0; +size_t colors_readindex = 0; + + +void colors_init(void) + { + ASSERT(colors==NULL, "colors_init"); + colors_bitcap = COLORS_INIT_COUNT*2; + colors = bitarray_alloc(colors_bitcap); + colors_writeindex = 0; + colors_readindex = 0; + return; + } + + +void colors_deinit(void) + { + bitarray_free(colors); + colors = NULL; + return; + } + + +void writebit(int bit) + { + if (colors_writeindex == colors_bitcap) + { + size_t colors_new_bitcap = colors_bitcap * 2; + unsigned char* newarr = bitarray_realloc(colors, colors_new_bitcap); + ASSERT(newarr != NULL, "realloc"); + colors = newarr; + colors_bitcap = colors_new_bitcap; + }; + ASSERT(colors_writeindex < colors_bitcap, "bound on write"); + bitarray_set(colors, colors_writeindex++, bit); + return; + } + + +int readbit(void) + { + int res; + ASSERT(colors_readindex < colors_writeindex, "bound on read"); + res = bitarray_get(colors, colors_readindex++); + ASSERT(res == 0 || res == 1, "bitarray_get"); + return res; + } + + +void writeint(unsigned int arg, unsigned int width) + { + while(width-- > 0) + { + writebit(arg&1); + arg >>= 1; + }; + ASSERT(arg == 0, "writeint"); + return; + } + + +unsigned int readint(unsigned int width) + { + unsigned int acc = 0; + unsigned int hibit = 1 << (width-1); + ASSERT(width > 0, "readint width"); + while(width-- > 0) + { + int bit = readbit(); + acc >>= 1; + if (bit) acc |= hibit; + }; + return acc; + } + + +int prev_color = 0; +int repeat_count = 0; + +#define BITS_FOR_COUNT 5 +#define BITS_FOR_ORDER 4 + +#define MAX_REPEAT_COUNT (1<= MAX_REPEAT_COUNT) + { + unsigned int ord = 0; + + while(ord < MAX_REPEAT_ORDER-1 && (1< 0) + { + writeint(Col_blue, 2); + writeint(0, 1); + writeint(repeat_count, BITS_FOR_COUNT); + repeat_count = 0; + }; + + return; + } + + +void rle_write_flush(void) + { + if (repeat_count > 0) + { + rle_write_repeats(); + }; + ASSERT(repeat_count == 0, "rle_write_flush"); + return; + } + + +void rle_read_flush(void) + { + DBG(printf("rle_read_flush: repeat_count=%i, ri=%i, wi=%i\n", + repeat_count, colors_readindex, colors_writeindex) + ); + + ASSERT + ( repeat_count == 0 + && colors_readindex == colors_writeindex + , "rle_reader_flush" + ); + return; + } + + +void rle_write(int color) + { + if (prev_color == color) + { + ++repeat_count; + } + else + { + rle_write_flush(); + ASSERT(color != Col_blue, "rle_write"); + writeint(color, 2); + prev_color = color; + }; + } + + +int rle_read(void); +int rle_read(void) + { + if (repeat_count > 0) + { + --repeat_count; + return prev_color; + } + else + { + int c = readint(2); + if (c == Col_blue) + { + int rk = readint(1); + if (rk == 0) + { repeat_count = readint(BITS_FOR_COUNT); } + else + { repeat_count = 1 << readint(BITS_FOR_ORDER); }; + ASSERT(repeat_count > 0, "rle_read"); + return rle_read(); + } + else + { + prev_color = c; + return c; + }; + }; + } + + +void rle_init(void) + { + prev_color = 0; + repeat_count = 0; + return; + } + + + +void writecolor(int col) + { + ASSERT(col >= 0 && col <= 3 && col != Col_blue, "writecolor"); + rle_write(col); + return; + } + + +int readcolor(void) + { + int res = rle_read(); + ASSERT(res >= 0 && res <= 3 && res != Col_blue, "readcolor"); + return res; + } + + +size_t acc_hdrs; +size_t acc_data; +size_t acc_depth; + + +#define COND_BLOCK(q) \ + ( Is_block(q) \ + && (Is_in_heap_or_young(q)) \ + ) + +#define GEN_COND_NOTVISITED(v, op) \ + ( Colornum_hd(Hd_val(v)) op Col_blue ) + +#define ENTERING_COND_NOTVISITED(v) GEN_COND_NOTVISITED(v, != ) + +#define RESTORING_COND_NOTVISITED(v) GEN_COND_NOTVISITED(v, == ) + +#define REC_WALK(cond_notvisited, rec_call, rec_goto) \ + size_t i; \ + value prev_block; \ + value f; \ + prev_block = Val_unit; \ + \ + for (i=0; i acc_depth) { acc_depth = depth; }; + + hd = Hd_val(v); + col = Colornum_hd(hd); + writecolor(col); + + DBG(printf("COL: w %08lx %i\n", v, col)); + + Hd_val(v) = Coloredhd_hd(hd, Col_blue); + + if (Tag_val(v) < No_scan_tag) + { + REC_WALK + ( ENTERING_COND_NOTVISITED + , c_rec_objsize(prev_block, (depth+1)); + , v = prev_block; \ + depth = depth + 1; \ + DBG(printf("goto, depth=%i, v=%p\n", depth, (void*)v)); \ + goto rec_enter; + ) + }; /* (Tag_val(v) < No_scan_tag) */ + + return; + } + + +void restore_colors(value v) + { + int col; + + rec_restore: + + col = readcolor(); + DBG(printf("COL: r %08lx %i\n", v, col)); + Hd_val(v) = Coloredhd_hd(Hd_val(v), col); + + if (Tag_val(v) < No_scan_tag) + { + size_t sz = Wosize_val(v); + + REC_WALK + ( RESTORING_COND_NOTVISITED + , restore_colors(prev_block); + , v = prev_block; \ + goto rec_restore; + ) + + }; + + return; + } + + +int c_objsize(value v, value scan, value reach, size_t* headers, size_t* data, size_t* depth) + { + value head; + int reached = 0; + colors_init(); + rle_init(); + /* + DBG(printf("young heap from %p to %p\n", caml_young_start, caml_young_end)); + DBG(printf("old heap from %p to %p\n", caml_heap_start, caml_heap_end)); + */ + DBG(printf("COL writing\n")); + + head = scan; + while( COND_BLOCK(head) ) { + value v = Field(head,0); + header_t hd = Hd_val(v); + int col = Colornum_hd(hd); + head = Field(head,1); + if( col == Col_blue ) continue; + writecolor(col); + Hd_val(v) = Coloredhd_hd(hd, Col_blue); + } + + acc_data = 0; + acc_hdrs = 0; + acc_depth = 0; + if ( COND_BLOCK(v) && Colornum_hd(Hd_val(v)) != Col_blue ) + { + c_rec_objsize(v, 0); + }; + if( headers != NULL ) { + *headers = acc_hdrs; + *data = acc_data; + *depth = acc_depth; + } + + rle_write_flush(); + DBG(printf("COL reading\n")); + rle_init(); + + head = scan; + while( COND_BLOCK(head) ) { + value v = Field(head,0); + int col; + head = Field(head,1); + if( Colornum_hd(Hd_val(v)) != Col_blue ) continue; + col = readcolor(); + Hd_val(v) = Coloredhd_hd(Hd_val(v), col); + } + + while( COND_BLOCK(reach) ) { + value v = Field(reach,0); + if( Colornum_hd(Hd_val(v)) == Col_blue ) { + reached = 1; + break; + } + reach = Field(reach,1); + } + + if ( COND_BLOCK(v) && Colornum_hd(Hd_val(v)) == Col_blue ) + { + restore_colors(v); + }; + rle_read_flush(); + +#if DUMP + printf("objsize: bytes for rle data = %i\n", colors_readindex/8); + fflush(stdout); + + { + FILE* f = fopen("colors-dump", "w"); + fwrite(colors, 1, colors_readindex/8, f); + fclose(f); + }; +#endif + + colors_deinit(); + DBG(printf("c_objsize done.\n")); + + return reached; + } + + +#include + +value ml_objsize(value start,value scan,value reach) + { + CAMLparam2(start,scan); + CAMLlocal1(res); + size_t hdrs, data, depth; + int reached = c_objsize(start, scan, reach, &hdrs, &data, &depth); + + res = caml_alloc_small(4, 0); + Field(res, 0) = Val_int(data); + Field(res, 1) = Val_int(hdrs); + Field(res, 2) = Val_int(depth); + Field(res, 3) = Val_bool(reached); + + CAMLreturn(res); + } + diff --git a/libs/objsize/objsize.ml b/libs/objsize/objsize.ml new file mode 100644 index 0000000000000000000000000000000000000000..626055fa19a291f54b993aacfb47179d3f32ac01 --- /dev/null +++ b/libs/objsize/objsize.ml @@ -0,0 +1,19 @@ +if Sys.ocaml_version < "3.11" +then + failwith "Objsize >=0.12 can only be used with OCaml >=3.11" + +type info = + { data : int + ; headers : int + ; depth : int + ; reached : bool + } + +external internal_objsize : Obj.t -> Obj.t list -> Obj.t list -> info = "ml_objsize" + +let objsize obj exclude reach = internal_objsize (Obj.repr obj) exclude reach + +let size_with_headers i = (Sys.word_size/8) * (i.data + i.headers) + +let size_without_headers i = (Sys.word_size/8) * i.data + diff --git a/libs/objsize/objsize.mli b/libs/objsize/objsize.mli new file mode 100644 index 0000000000000000000000000000000000000000..dc61627e60a067dc75c94b60b704e37e56c15c8f --- /dev/null +++ b/libs/objsize/objsize.mli @@ -0,0 +1,14 @@ +(* Information gathered while walking through values. *) +type info = + { data : int + ; headers : int + ; depth : int + ; reached : bool + } + +(* Returns information for first argument, excluding the second arg list and telling if we can reach the third arg list *) +val objsize : 'a -> Obj.t list -> Obj.t list -> info + +(* Calculates sizes in bytes: *) +val size_with_headers : info -> int +val size_without_headers : info -> int diff --git a/libs/objsize/tests.ml b/libs/objsize/tests.ml new file mode 100644 index 0000000000000000000000000000000000000000..388214f749db14f5c1241a532634646e9377bdff --- /dev/null +++ b/libs/objsize/tests.ml @@ -0,0 +1,60 @@ +open Printf +;; + +let print title vl = + let i = Objsize.objsize vl in + printf "%S : data_words=%i headers=%i depth=%i\n \ +bytes_without_headers=%i bytes_with_headers=%i\n%!" + title i.Objsize.data i.Objsize.headers i.Objsize.depth + (Objsize.size_without_headers i) + (Objsize.size_with_headers i) +in + +print "string of 13 chars" ("0123456" ^ "789012") +; +print "some object" + ( object method x = 123; method y = print_int; end + ) +; + +print "some float" (Random.float 1.) +; +(* +let rec cyc = [1 :: [2 :: [3 :: cyc]]] in + +print "cyclic list" cyc +; +*) +let genlist n = + let rec inner acc n = + if n <= 0 + then acc + else inner (n :: acc) (n-1) + in + inner [] n +in + +print "big list" (genlist 300000) +; + +print "big array" (Array.make 30000 true) +; + +print "statically created value" [1; 2; 3] +; + +print "objsize 0.14 bug" + (let rec val_a = (val_z, val_z) + and val_z = (123, val_y) + and val_y = (234, 345) + in + val_a + ) +; + +print "objsize 0.15 bug" + (let val_z = ((), ()) in + let val_y = (val_z, val_z, fun x -> x) in + val_y + ) +; diff --git a/libs/objsize/util.h b/libs/objsize/util.h new file mode 100644 index 0000000000000000000000000000000000000000..a8de642e6d5212c891526579729608972f4904f7 --- /dev/null +++ b/libs/objsize/util.h @@ -0,0 +1,14 @@ +#ifndef UTIL_H +#define UTIL_H + +#define ABORT(x) do { \ + fprintf(stderr, "aborted at %s:%i: %s\n", __FILE__, __LINE__, x); \ + exit(1); } while(0) + +#define ASSERT(b, err) do { \ + if (!(b)) \ + { ABORT("assert_failed: " err); \ + }; \ + } while(0) + +#endif diff --git a/libs/swflib/Makefile b/libs/swflib/Makefile index 1c7c70bd77e95f14db552fb2dc6989621ca830d0..f299a1e7f77854bd57a0b2e9b86a8c18c91d7e9d 100644 --- a/libs/swflib/Makefile +++ b/libs/swflib/Makefile @@ -1,49 +1,73 @@ # Makefile generated by OCamake # http://tech.motion-twin.com +OCAMLOPT=ocamlopt +OCAMLC=ocamlc .SUFFIXES : .ml .mli .cmo .cmi .cmx .mll .mly CFLAGS= -I ../extlib -I ../extc -g LIBS= -LFLAGS= -o swflib.cmxa -a + +SRC=actionScript.ml as3hl.mli as3.mli png.ml swflib.sln swf.ml swfPic.ml as3code.ml as3hlparse.ml as3parse.ml png.mli swfParser.ml MODULES=as3code.cmx png.cmx swf.cmx actionScript.cmx as3parse.cmx swfPic.cmx as3hlparse.cmx swfParser.cmx -all: swflib.cmxa +all: native bytecode + +native: swflib.cmxa + +bytecode: swflib.cma swflib.cmxa: $(MODULES) - ocamlopt $(LFLAGS) $(LIBS) $(MODULES) + $(OCAMLOPT) -o swflib.cmxa -a $(LIBS) $(MODULES) + +swflib.cma: $(MODULES:.cmx=.cmo) + $(OCAMLC) -o swflib.cma -a $(LFLAGS) $(LIBS) $(MODULES:.cmx=.cmo) actionScript.cmx: swf.cmx +actionScript.cmo: swf.cmi + +as3code.cmo: as3.cmi + as3code.cmx: as3.cmi as3hl.cmi: as3.cmi +as3hlparse.cmo: as3parse.cmo as3hl.cmi as3code.cmo as3.cmi + as3hlparse.cmx: as3parse.cmx as3hl.cmi as3code.cmx as3.cmi +as3parse.cmo: as3code.cmo as3.cmi + as3parse.cmx: as3code.cmx as3.cmi +png.cmo: png.cmi + png.cmx: png.cmi +swf.cmo: as3.cmi + swf.cmx: as3.cmi +swfParser.cmo: swf.cmo as3parse.cmo actionScript.cmo + swfParser.cmx: swf.cmx as3parse.cmx actionScript.cmx swfPic.cmx: swf.cmx png.cmi clean: - rm -f swflib.cmxa swflib.lib swflib.a as3.cmi as3hl.cmi - rm -f $(MODULES) $(MODULES:.cmx=.obj) $(MODULES:.cmx=.cmi) $(MODULES:.cmx=.o) + rm -f swflib.cmxa swflib.cma swflib.lib swflib.a as3.cmi as3hl.cmi + rm -f $(MODULES) $(MODULES:.cmx=.obj) $(MODULES:.cmx=.cmi) $(MODULES:.cmx=.o) $(MODULES:.cmx=.cmo) # SUFFIXES .ml.cmo: - ocamlc $(CFLAGS) -c $< + $(OCAMLC) $(CFLAGS) -c $< .ml.cmx: - ocamlopt $(CFLAGS) -c $< + $(OCAMLOPT) $(CFLAGS) -c $< .mli.cmi: - ocamlc $(CFLAGS) $< + $(OCAMLC) $(CFLAGS) $< .mll.ml: ocamllex $< @@ -51,3 +75,7 @@ clean: .mly.ml: ocamlyacc $< +.PHONY: all bytecode native clean + +Makefile: ; +$(SRC): ; diff --git a/libs/swflib/swflib.sln b/libs/swflib/swflib.sln new file mode 100644 index 0000000000000000000000000000000000000000..f54fa701975ffc2feee7371b4c44b323b6d6580e --- /dev/null +++ b/libs/swflib/swflib.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "swflib", "swflib.vcproj", "{A9DD9D90-85E1-4FCF-8C09-42BF78942849}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Bytecode = Bytecode + Native code = Native code + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Bytecode.ActiveCfg = Bytecode|Win32 + {A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Bytecode.Build.0 = Bytecode|Win32 + {A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Native code.ActiveCfg = Native code|Win32 + {A9DD9D90-85E1-4FCF-8C09-42BF78942849}.Native code.Build.0 = Native code|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/libs/swflib/swflib.vcproj b/libs/swflib/swflib.vcproj new file mode 100644 index 0000000000000000000000000000000000000000..c7a98a04a6e078d60356a7682d554c68ca989af3 --- /dev/null +++ b/libs/swflib/swflib.vcproj @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/ttflib/Makefile b/libs/ttflib/Makefile index bb56a41a0e0264f923dcf8a87963ff9bc52ac846..164c21618896d811bb7a21b573d7d9b43d0db1d2 100644 --- a/libs/ttflib/Makefile +++ b/libs/ttflib/Makefile @@ -1,14 +1,31 @@ +OCAMLOPT=ocamlopt +OCAMLC=ocamlc + FLAGS=-I ../extlib -I ../swflib FILES=tTFData tTFParser tTFTools tTFSwfWriter tTFCanvasWriter tTFJsonWriter LIBS=extLib swflib unix OUTPUT=ttf -all: - ocamlopt $(FLAGS) $(FILES:=.ml) -g -a -o ttf.cmxa +all: native bytecode + +native: ttf.cmxa + +bytecode: ttf.cma + +ttf.cmxa: $(FILES:=.ml) + $(OCAMLOPT) $(FLAGS) $(FILES:=.ml) -g -a -o ttf.cmxa + +ttf.cma: $(FILES:=.ml) + $(OCAMLC) $(FLAGS) $(FILES:=.ml) -g -a -o ttf.cma exec: - ocamlopt $(FLAGS) $(LIBS:=.cmxa) $(FILES:=.ml) main.ml -g -o $(OUTPUT) + $(OCAMLOPT) $(FLAGS) $(LIBS:=.cmxa) $(FILES:=.ml) main.ml -g -o $(OUTPUT) clean: - rm -rf ttf.cmxa ttf.lib ttf.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) \ No newline at end of file + rm -rf ttf.cmxa ttf.cma ttf.lib ttf.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cmo) + +.PHONY: all native bytecode clean exec + +Makefile: ; +$(FILES:=.ml): ; diff --git a/libs/ttflib/main.ml b/libs/ttflib/main.ml index 7e555d7896850427029238b117e5b6f7f50d3aa8..e5e4e71ec5b52bdccb44e3988fb4600c94414fb0 100644 --- a/libs/ttflib/main.ml +++ b/libs/ttflib/main.ml @@ -62,7 +62,11 @@ let process args = ("-swf",Arg.String (fun dir -> mk_dir_rec dir; let f ttf range_str = - let f2 = TTFSwfWriter.to_swf ttf range_str in + let config = { + ttfc_range_str = range_str; + ttfc_font_name = None; + } in + let f2 = TTFSwfWriter.to_swf ttf config in let ch = IO.output_channel (open_out_bin (dir ^ "/" ^ ttf.ttf_font_name ^ ".dat")) in let b = IO.output_bits ch in IO.write_i16 ch 1; diff --git a/libs/ttflib/tTFCanvasWriter.ml b/libs/ttflib/tTFCanvasWriter.ml index 74751cd7f555fc0588da864ed8a2a1d0a42b66e2..ba719e78bc86815424ed5c0c432b4fc9f902490b 100644 --- a/libs/ttflib/tTFCanvasWriter.ml +++ b/libs/ttflib/tTFCanvasWriter.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + open TTFData open TTFTools diff --git a/libs/ttflib/tTFData.ml b/libs/ttflib/tTFData.ml index e7c6e2f823f2d6396149529f15fd497fc67cb882..1be335cfb685edd6590f96a5bdb2ea3bf7e8a298 100644 --- a/libs/ttflib/tTFData.ml +++ b/libs/ttflib/tTFData.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + type header = { hd_major_version : int; hd_minor_version : int; @@ -320,4 +342,9 @@ type ttf = { ttf_name : name; ttf_os2 : os2; ttf_kern : kern option; +} + +type ttf_config = { + mutable ttfc_range_str : string; + mutable ttfc_font_name : string option; } \ No newline at end of file diff --git a/libs/ttflib/tTFJsonWriter.ml b/libs/ttflib/tTFJsonWriter.ml index 194950d92631a6d44a1fef77a8cc70d9a3221c5d..126cb6f073df8b502eac47d54ee1489d5416d892 100644 --- a/libs/ttflib/tTFJsonWriter.ml +++ b/libs/ttflib/tTFJsonWriter.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + open TTFData open TTFTools diff --git a/libs/ttflib/tTFParser.ml b/libs/ttflib/tTFParser.ml index 9c727a5164ce503f80ea4a65bdd5f23af9bcb13a..455485a8a2a0d2b2813d0b3ab080dcdf2ed9fdb6 100644 --- a/libs/ttflib/tTFParser.ml +++ b/libs/ttflib/tTFParser.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + open TTFData open IO @@ -224,7 +246,7 @@ let parse_cmap_table ctx = let start_code = Array.init seg_count (fun _ -> rdu16 ch) in let id_delta = Array.init seg_count (fun _ -> rdu16 ch) in let id_range_offset = Array.init seg_count (fun _ -> rdu16 ch) in - let count = length - (8 * seg_count + 16) / 2 in + let count = (length - (8 * seg_count + 16)) / 2 in let glyph_index = Array.init count (fun _ -> rdu16 ch) in Cmap4 { c4_format = format; diff --git a/libs/ttflib/tTFSwfWriter.ml b/libs/ttflib/tTFSwfWriter.ml index 28ed6ca5495a6c9fa796081e505dcbe9c3dfebfd..3b2de89cd107531bca04e65abfa8a19150a57233 100644 --- a/libs/ttflib/tTFSwfWriter.ml +++ b/libs/ttflib/tTFSwfWriter.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + open TTFData open Swf @@ -162,11 +184,11 @@ let write_font2 ch b f2 = Array.iter (fun g -> SwfParser.write_rect ch g.font_bounds;) f2.font_layout.font_glyphs_layout; IO.write_ui16 ch 0 (* TODO: optional FontKerningTable *) -let to_swf ttf range_str = +let to_swf ttf config = let ctx = { ttf = ttf; } in - let lut = TTFTools.build_lut ttf range_str in + let lut = TTFTools.build_lut ttf config.ttfc_range_str in let glyfs = Hashtbl.fold (fun k v acc -> (k,ctx.ttf.ttf_glyfs.(v)) :: acc) lut [] in let glyfs = List.stable_sort (fun a b -> compare (fst a) (fst b)) glyfs in let glyfs = List.map (fun (k,g) -> write_glyph ctx k g) glyfs in @@ -181,7 +203,7 @@ let to_swf ttf range_str = font_is_italic = false; font_is_bold = false; font_language = LCNone; - font_name = ttf.ttf_font_name; + font_name = (match config.ttfc_font_name with Some s -> s | None -> ttf.ttf_font_name); font_glyphs = glyfs; font_layout = glyfs_font_layout; } diff --git a/libs/ttflib/tTFTools.ml b/libs/ttflib/tTFTools.ml index ef034db008a693f3a13cf9e594b560f3b232846a..a4ea6539ddf7f2a6b89d0572ccd504e0e2418a51 100644 --- a/libs/ttflib/tTFTools.ml +++ b/libs/ttflib/tTFTools.ml @@ -1,3 +1,25 @@ +(* + * Copyright (C)2005-2014 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. + *) + open TTFData type glyf_transformation_matrix = { @@ -184,38 +206,24 @@ let map_char_code cc c4 = end let parse_range_str str = - let len = String.length str in - let last = ref str.[0] in - let offset = ref 1 in + let last = ref (Char.code '\\') in + let range = ref false in let lut = Hashtbl.create 0 in - if len = 1 then - Hashtbl.add lut (Char.code !last) true - else - while !offset < len do - let cur = str.[!offset] in - begin match cur with - | '-' when !last = '\\' -> - Hashtbl.replace lut (Char.code '-') true; - incr offset; - | c when !offset = len - 1 -> - Hashtbl.replace lut (Char.code !last) true; - Hashtbl.replace lut (Char.code cur) true; - incr offset - | '-' -> - let first, last = match Char.code !last, Char.code str.[!offset + 1] with - | first,last when first > last -> last,first - | first,last -> first,last - in - for i = first to last do - Hashtbl.add lut i true - done; - offset := !offset + 2; - | c -> - Hashtbl.replace lut (Char.code !last) true; - incr offset; - end; - last := cur; - done; + UTF8.iter (fun code -> + let code = UChar.code code in + if code = Char.code '-' && !last <> Char.code '\\' then + range := true + else if !range then begin + range := false; + for i = !last to code do + Hashtbl.replace lut i true; + done; + end else begin + Hashtbl.replace lut code true; + last := code; + end + ) str; + if !range then Hashtbl.replace lut (Char.code '-') true; lut let build_lut ttf range_str = diff --git a/libs/xml-light/META.in b/libs/xml-light/META.in index bbfb3d919eaf96eee84d193856979d22b88c2859..f198c6d334ac61b3f22f8adcbaa1d7106fc5eaf0 100644 --- a/libs/xml-light/META.in +++ b/libs/xml-light/META.in @@ -1,4 +1,3 @@ version="@VERSION@" -directory="+xml-light" archive(byte)="xml-light.cma" archive(native)="xml-light.cmxa" diff --git a/libs/xml-light/Makefile b/libs/xml-light/Makefile index c6117d1938659793f44ef7d1e0110e91dcbc0f97..a3b69dea5990fd5719555963798835d9cf0a2840 100644 --- a/libs/xml-light/Makefile +++ b/libs/xml-light/Makefile @@ -1,15 +1,26 @@ # Makefile generated by OCamake # http://tech.motion-twin.com +VERSION=2.3 +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +OCAMLFIND=ocamlfind + .SUFFIXES : .ml .mli .cmo .cmx .cmi .mll .mly -INSTALLDIR=`ocamlc -where` +INSTALLDIR=`$(OCAMLC) -where` CFLAGS= LFLAGS= -a LIBS= +SRC=dtd.mli xml.dsp xml_lexer.mli xml.ml xmlParser.ml xml_parser.mly dtd.ml test.ml xml.dsw xml_lexer.mll xml.mli xmlParser.mli + + +all: bytecode test.exe doc -all: xml-light.cma test.exe doc +opt: native -opt: xml-light.cmxa test_opt.exe +native: xml-light.cmxa + +bytecode: xml-light.cma installcommon: all cp xml.mli xmlParser.mli dtd.mli xml.cmi xmlParser.cmi dtd.cmi $(INSTALLDIR) @@ -25,21 +36,28 @@ install: installbyte installopt wininstall: all opt cp xml-light.cmxa xml-light.lib xml-light.cma xml.mli xmlParser.mli dtd.mli xml.cmi xmlParser.cmi dtd.cmi xml.cmx dtd.cmx xmlParser.cmx c:\ocaml\lib -doc: - mkdir doc +install_ocamlfind: all opt + cp META.in META + sed -itmp "s|@VERSION@|$(VERSION)|g" META + rm -rf METAtmp + $(OCAMLFIND) install xml-light META xml-light.a xml-light.cma xml-light.cmxa xml.cmx dtd.cmx xmlParser.cmx xml.mli xmlParser.mli dtd.mli xml.cmi xmlParser.cmi dtd.cmi + +doc: doc/index.html +doc/index.html: xml.mli dtd.mli xmlParser.mli + mkdir -p doc ocamldoc -sort -html -d doc xml.mli dtd.mli xmlParser.mli test.exe: xml-light.cma - ocamlc xml-light.cma test.ml -o test.exe - + $(OCAMLC) xml-light.cma test.ml -o test.exe + test_opt.exe: xml-light.cmxa - ocamlopt xml-light.cmxa test.ml -o test_opt.exe + $(OCAMLOPT) xml-light.cmxa test.ml -o test_opt.exe xml-light.cma: xml_parser.cmo xml_lexer.cmo dtd.cmo xmlParser.cmo xml.cmo - ocamlc -o xml-light.cma $(LFLAGS) $(LIBS) xml_parser.cmo xml_lexer.cmo dtd.cmo xmlParser.cmo xml.cmo + $(OCAMLC) -o xml-light.cma $(LFLAGS) $(LIBS) xml_parser.cmo xml_lexer.cmo dtd.cmo xmlParser.cmo xml.cmo xml-light.cmxa: xml_parser.cmx xml_lexer.cmx dtd.cmx xmlParser.cmx xml.cmx - ocamlopt -o xml-light.cmxa $(LFLAGS) $(LIBS) xml_parser.cmx xml_lexer.cmx dtd.cmx xmlParser.cmx xml.cmx + $(OCAMLOPT) -o xml-light.cmxa $(LFLAGS) $(LIBS) xml_parser.cmx xml_lexer.cmx dtd.cmx xmlParser.cmx xml.cmx dtd.cmo: xml.cmi xml_lexer.cmi dtd.cmi @@ -74,17 +92,18 @@ xml_lexer.cmx: xml_lexer.ml xml_lexer.cmi clean: rm -f xml-light.cma test.exe dtd.cmo dtd.cmi test.cmo test.cmi xml.cmo xml.cmi xmlParser.cmo xmlParser.cmi dtd.cmi xml.cmi xmlParser.cmi xml_lexer.cmi xml_lexer.cmo xml_lexer.ml xml_parser.mli xml_parser.cmi xml_parser.ml xml_parser.cmo rm -f xml-light.lib xml-light.a xml-light.cmxa test_opt.exe dtd.cmx dtd.obj dtd.o test.cmx test.obj test.o xml.cmx xml.obj xml.o xmlParser.cmx xmlParser.obj xmlParser.o xml_lexer.cmx xml_lexer.obj xml_lexer.o xml_parser.cmx xml_parser.obj xml_parser.o + rm -rf doc # SUFFIXES .ml.cmo: - ocamlc $(CFLAGS) -c $< + $(OCAMLC) $(CFLAGS) -c $< .ml.cmx: - ocamlopt $(CFLAGS) -c $< + $(OCAMLOPT) $(CFLAGS) -c $< .mli.cmi: - ocamlc $(CFLAGS) $< + $(OCAMLC) $(CFLAGS) $< .mll.ml: ocamllex $< @@ -92,3 +111,6 @@ clean: .mly.ml: ocamlyacc $< +Makefile: ; +$(SRC): ; +.PHONY: all opt native bytecode installcommon installbyte installopt install wininstall install_ocamlfind doc clean diff --git a/libs/xml-light/README b/libs/xml-light/README index 83fde267eacc7125e22eab60d97946e96562bb64..2056d86be25d56cbf8e84c2030c87527fa699312 100644 --- a/libs/xml-light/README +++ b/libs/xml-light/README @@ -1,4 +1,4 @@ -Xml-Light Version 2.2 : +Xml-Light Version 2.3 : ----------------------- Last version : http://tech.motion-twin.com diff --git a/libs/xml-light/makedoc.bat b/libs/xml-light/makedoc.bat new file mode 100644 index 0000000000000000000000000000000000000000..45d041079265d938dee1c0087ed85d4002be0483 --- /dev/null +++ b/libs/xml-light/makedoc.bat @@ -0,0 +1,2 @@ +@ocamldoc -sort -html -d doc xml.mli dtd.mli xmlParser.mli +@pause \ No newline at end of file diff --git a/libs/ziplib/Makefile b/libs/ziplib/Makefile index 6012f4afa53f3efe5f4e3510bbe166480ca5ae72..e532cbd95251099ba182b2ad01e90b8138cc113c 100644 --- a/libs/ziplib/Makefile +++ b/libs/ziplib/Makefile @@ -1,5 +1,22 @@ -all: - ocamlopt -g -I ../extlib -I ../extc -a -o zip.cmxa zlib.mli zlib.ml zip.mli zip.ml - +OCAMLOPT=ocamlopt +OCAMLC=ocamlc +SRC=zlib.mli zlib.ml zip.mli zip.ml + +all: native bytecode + +native: zip.cmxa +zip.cmxa: $(SRC) + $(OCAMLOPT) -g -I ../extlib -I ../extc -a -o zip.cmxa $(SRC) + +bytecode: zip.cma +zip.cma: $(SRC) + $(OCAMLC) -g -I ../extlib -I ../extc -a -o zip.cma $(SRC) + clean: - rm -rf zip.cmxa zip.lib zip.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) \ No newline at end of file + rm -rf zip.cmxa zip.cma zip.lib zip.a $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) $(wildcard *.cmo) + +.PHONY: all native bytecode clean + +Makefile: ; + +$(SRC): ; diff --git a/libs/ziplib/test/Makefile b/libs/ziplib/test/Makefile index df087e406c35a04c94319f974ef481fdece96de1..7db71a8ed660157aca857610d515205cc6066cf6 100644 --- a/libs/ziplib/test/Makefile +++ b/libs/ziplib/test/Makefile @@ -1,5 +1,7 @@ +OCAMLOPT=ocamlopt + all: ../zip.cmxa minizip.ml - ocamlopt -g -g -I .. -I ../../extc -o minizip -cclib ../../extc/extc_stubs.o -cclib -lz unix.cmxa ../zip.cmxa minizip.ml + $(OCAMLOPT) -g -g -I .. -I ../../extc -o minizip -cclib ../../extc/extc_stubs.o -cclib -lz unix.cmxa ../zip.cmxa minizip.ml clean: rm -rf minizip $(wildcard *.cmx) $(wildcard *.obj) $(wildcard *.o) $(wildcard *.cmi) diff --git a/libs/ziplib/zip.ml b/libs/ziplib/zip.ml index b2e30b99632fca978694d698196a853cce73daba..27f286e120e1794a68875d35e97c657b9824d97d 100644 --- a/libs/ziplib/zip.ml +++ b/libs/ziplib/zip.ml @@ -74,8 +74,6 @@ type out_file = mutable of_entries: entry list; of_comment: string } -exception Error of string * string * string - (* Return the position of the last occurrence of s1 in s2, or -1 if not found. *) @@ -134,8 +132,8 @@ let read_ecd filename ic = let newlen = min (toread + len) 256 in (* Search for magic number *) let ofs = strrstr "PK\005\006" buf 0 newlen in - if ofs < 0 || newlen < 22 || - (let comment_len = + if ofs < 0 || newlen < 22 || + (let comment_len = Char.code buf.[ofs + 20] lor (Char.code buf.[ofs + 21] lsl 8) in newpos + ofs + 22 + comment_len <> filelen) then find_ecd newpos newlen @@ -307,7 +305,7 @@ let read_entry ifile e = res with End_of_file -> raise (Error(ifile.if_filename, e.filename, "truncated data")) - + (* Write the contents of an entry into an out channel *) let copy_entry_to_channel ifile e oc = @@ -346,7 +344,7 @@ let copy_entry_to_channel ifile e oc = raise (Error(ifile.if_filename, e.filename, "CRC mismatch")) with End_of_file -> raise (Error(ifile.if_filename, e.filename, "truncated data")) - + (* Write the contents of an entry to a file *) let copy_entry_to_file ifile e outfilename = @@ -471,7 +469,7 @@ let add_data_descriptor ofile crc compr_size uncompr_size entry = (* Add an entry with the contents of a string *) -let add_entry data ofile ?(extra = "") ?(comment = "") +let add_entry data ofile ?(extra = "") ?(comment = "") ?(level = 6) ?(mtime = Unix.time()) name = let e = add_entry_header ofile extra comment level mtime name in let crc = Zlib.update_crc Int32.zero data 0 (String.length data) in @@ -502,7 +500,7 @@ let add_entry data ofile ?(extra = "") ?(comment = "") (* Add an entry with the contents of an in channel *) -let copy_channel_to_entry ic ofile ?(extra = "") ?(comment = "") +let copy_channel_to_entry ic ofile ?(extra = "") ?(comment = "") ?(level = 6) ?(mtime = Unix.time()) name = let e = add_entry_header ofile extra comment level mtime name in let crc = ref Int32.zero in @@ -529,7 +527,7 @@ let copy_channel_to_entry ic ofile ?(extra = "") ?(comment = "") crc := Zlib.update_crc !crc buf 0 r; in_pos := !in_pos + r; r) - (fun buf n -> + (fun buf n -> output ofile.of_channel buf 0 n; out_pos := !out_pos + n); (!out_pos, !in_pos) @@ -540,11 +538,11 @@ let copy_channel_to_entry ic ofile ?(extra = "") ?(comment = "") (* Add an entry with the contents of a file *) -let copy_file_to_entry infilename ofile ?(extra = "") ?(comment = "") +let copy_file_to_entry infilename ofile ?(extra = "") ?(comment = "") ?(level = 6) ?mtime name = let ic = open_in_bin infilename in let mtime' = - match mtime with + match mtime with Some t -> mtime | None -> try Some((Unix.stat infilename).Unix.st_mtime) diff --git a/main.ml b/main.ml old mode 100755 new mode 100644 index 8c9563325e57b83b58a6a56d497cf70fc18c3d45..9dbafc77dd8f7e615f8d016543567892a87ea20e --- a/main.ml +++ b/main.ml @@ -20,6 +20,31 @@ * DEALINGS IN THE SOFTWARE. *) +(* + Conventions: + - e: expression (typed or untyped) + - c: class + - en: enum + - td: typedef (tdef) + - a: abstract + - an: anon + - tf: tfunc + - cf: class_field + - ef: enum_field + - t: type (t) + - ct: complex_type + - v: local variable (tvar) + - m: module (module_def) + - mt: module_type + - p: pos + + "param" refers to type parameters + "arg" refers to function arguments + leading s_ means function returns string + trailing l means list (but we also use natural plurals such as "metas") + semantic suffixes may be used freely (e.g. e1, e_if, e') +*) + open Printf open Ast open Genswf @@ -44,19 +69,35 @@ type cache = { exception Abort exception Completion of string -let version = 300 + +let version = 3200 +let version_major = version / 1000 +let version_minor = (version mod 1000) / 100 +let version_revision = (version mod 100) +let version_is_stable = version_minor land 1 = 0 let measure_times = ref false let prompt = ref false let start_time = ref (get_time()) let global_cache = ref None +let path_sep = if Sys.os_type = "Unix" then "/" else "\\" + +let get_real_path p = + try + Extc.get_real_path p + with _ -> + p + let executable_path() = Extc.executable_path() let is_debug_run() = try Sys.getenv "HAXEDEBUG" = "1" with _ -> false +let s_version = + Printf.sprintf "%d.%d.%d%s" version_major version_minor version_revision (match Version.version_extra with None -> "" | Some v -> " " ^ v) + let format msg p = if p = Ast.null_pos then msg @@ -81,30 +122,40 @@ let message ctx msg p = ctx.messages <- format msg p :: ctx.messages let deprecated = [ - "Class not found : IntIter","IntIter was renamed to IntIterator"; + "Type not found : IntIter","IntIter was renamed to IntIterator"; "EReg has no field customReplace","EReg.customReplace was renamed to EReg.map"; "#StringTools has no field isEOF","StringTools.isEOF was renamed to StringTools.isEof"; - "Class not found : haxe.BaseCode","haxe.BaseCode was moved to haxe.crypto.BaseCode"; - "Class not found : haxe.Md5","haxe.Md5 was moved to haxe.crypto.Md5"; - "Class not found : haxe.SHA1","haxe.SHA1 was moved to haxe.crypto.SHA1"; - "Class not found : Hash","Hash has been removed, use Map instead"; - "Class not found : IntHash","IntHash has been removed, use Map instead"; - "Class not found : haxe.FastList","haxe.FastList was moved to haxe.ds.GenericStack"; + "Type not found : haxe.BaseCode","haxe.BaseCode was moved to haxe.crypto.BaseCode"; + "Type not found : haxe.Md5","haxe.Md5 was moved to haxe.crypto.Md5"; + "Type not found : haxe.SHA1","haxe.SHA1 was moved to haxe.crypto.SHA1"; + "Type not found : Hash","Hash has been removed, use Map instead"; + "Type not found : IntHash","IntHash has been removed, use Map instead"; + "Type not found : haxe.FastList","haxe.FastList was moved to haxe.ds.GenericStack"; "#Std has no field format","Std.format has been removed, use single quote 'string ${escape}' syntax instead"; - "Class not found : Int32","Int32 has been removed, use Int instead"; "Identifier 'EType' is not part of enum haxe.macro.ExprDef","EType has been removed, use EField instead"; "Identifier 'CType' is not part of enum haxe.macro.Constant","CType has been removed, use CIdent instead"; - "Class not found : haxe.rtti.Infos","Use @:rtti instead of implementing haxe.rtti.Infos"; - "Class not found : haxe.rtti.Generic","Use @:generic instead of implementing haxe.Generic"; - "Class not found : haxe.Int32","haxe.Int32 has been removed, use normal Int instead"; - "Class not found : flash.utils.TypedDictionary","flash.utils.TypedDictionary has been removed, use Map instead"; - "Class not found : haxe.Stack", "haxe.Stack has been renamed to haxe.CallStack"; - "Class not found : neko.zip.Reader", "neko.zip.Reader has been removed, use haxe.zip.Reader instead"; - "Class not found : neko.zip.Reader", "neko.zip.Writer has been removed, use haxe.zip.Writer instead"; - "Class not found : haxe.Public", "Use @:publicFields instead of implementing or extending haxe.Public"; - "#Xml has no field createProlog", "Xml.createProlog was renamed to Xml.createProcessingInstruction"; + "Type not found : haxe.rtti.Infos","Use @:rtti instead of implementing haxe.rtti.Infos"; + "Type not found : haxe.rtti.Generic","Use @:generic instead of implementing haxe.Generic"; + "Type not found : flash.utils.TypedDictionary","flash.utils.TypedDictionary has been removed, use Map instead"; + "Type not found : haxe.Stack", "haxe.Stack has been renamed to haxe.CallStack"; + "Type not found : neko.zip.Reader", "neko.zip.Reader has been removed, use haxe.zip.Reader instead"; + "Type not found : neko.zip.Writer", "neko.zip.Writer has been removed, use haxe.zip.Writer instead"; + "Type not found : haxe.Public", "Use @:publicFields instead of implementing or extending haxe.Public"; + "#Xml has no field createProlog", "Xml.createProlog was renamed to Xml.createProcessingInstruction" ] +let limit_string s offset = + let rest = 80 - offset in + let words = ExtString.String.nsplit s " " in + let rec loop i words = match words with + | word :: words -> + if String.length word + i + 1 > rest then (Printf.sprintf "\n%*s" offset "") :: word :: loop (String.length word) words + else (if i = 0 then "" else " ") :: word :: loop (i + 1 + String.length word) words + | [] -> + [] + in + String.concat "" (loop 0 words) + let error ctx msg p = let msg = try List.assoc msg deprecated with Not_found -> msg in message ctx msg p; @@ -117,16 +168,28 @@ let htmlescape s = s let reserved_flags = [ - "cross";"flash8";"js";"neko";"flash";"php";"cpp";"cs";"java"; + "cross";"js";"neko";"flash";"php";"cpp";"cs";"java";"python"; "as3";"swc";"macro";"sys" ] -let complete_fields fields = +let complete_fields com fields = let b = Buffer.create 0 in + let details = Common.raw_defined com "display-details" in Buffer.add_string b "\n"; - List.iter (fun (n,t,d) -> - Buffer.add_string b (Printf.sprintf "%s%s\n" n (htmlescape t) (htmlescape d)) - ) (List.sort (fun (a,_,_) (b,_,_) -> compare a b) fields); + List.iter (fun (n,t,k,d) -> + let s_kind = match k with + | Some k -> (match k with + | Typer.FKVar -> "var" + | Typer.FKMethod -> "method" + | Typer.FKType -> "type" + | Typer.FKPackage -> "package") + | None -> "" + in + if details then + Buffer.add_string b (Printf.sprintf "%s%s\n" n s_kind (htmlescape t) (htmlescape d)) + else + Buffer.add_string b (Printf.sprintf "%s%s\n" n (htmlescape t) (htmlescape d)) + ) (List.sort (fun (a,_,ak,_) (b,_,bk,_) -> compare (ak,a) (bk,b)) fields); Buffer.add_string b "\n"; raise (Completion (Buffer.contents b)) @@ -147,31 +210,35 @@ let make_path f = | ["hx";path] -> ExtString.String.nsplit path "/" | _ -> cl ) in - let error() = - let msg = - if String.length f == 0 then - "Class name must not be empty" - else match (List.hd (List.rev cl)).[0] with - | 'A'..'Z' -> "Invalid class name" - | _ -> "Class name must start with uppercase character" - in + let error msg = + let msg = "Could not process argument " ^ f ^ "\n" ^ msg in failwith msg in let invalid_char x = for i = 1 to String.length x - 1 do match x.[i] with | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' -> () - | _ -> error() - done; - false + | c -> error ("invalid character: " ^ (String.make 1 c)) + done in let rec loop = function - | [] -> error() - | [x] -> if String.length x = 0 || not (x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')) || invalid_char x then error() else [] , x + | [] -> + error "empty part" + | [x] -> + if String.length x = 0 then + error "empty part" + else if not (x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')) then + error "Class name must start with uppercase character"; + invalid_char x; + [],x | x :: l -> - if String.length x = 0 || x.[0] < 'a' || x.[0] > 'z' || invalid_char x then error() else - let path , name = loop l in - x :: path , name + if String.length x = 0 then + error "empty part" + else if x.[0] < 'a' || x.[0] > 'z' then + error "Package name must start with a lower case character"; + invalid_char x; + let path,name = loop l in + x :: path,name in loop cl @@ -235,18 +302,30 @@ let rec read_type_path com p = loop path p ) (extract()); ) com.swf_libs; - List.iter (fun (path,std,close,all_files,lookup) -> - List.iter (fun (path, name) -> - if path = p then classes := name :: !classes else - let rec loop p1 p2 = - match p1, p2 with - | [], _ -> () - | x :: _, [] -> packages := x :: !packages - | a :: p1, b :: p2 -> if a = b then loop p1 p2 - in - loop path p - ) (all_files()) - ) com.java_libs; + List.iter (fun (path,std,close,all_files,lookup) -> + List.iter (fun (path, name) -> + if path = p then classes := name :: !classes else + let rec loop p1 p2 = + match p1, p2 with + | [], _ -> () + | x :: _, [] -> packages := x :: !packages + | a :: p1, b :: p2 -> if a = b then loop p1 p2 + in + loop path p + ) (all_files()) + ) com.java_libs; + List.iter (fun (path,std,all_files,lookup) -> + List.iter (fun (path, name) -> + if path = p then classes := name :: !classes else + let rec loop p1 p2 = + match p1, p2 with + | [], _ -> () + | x :: _, [] -> packages := x :: !packages + | a :: p1, b :: p2 -> if a = b then loop p1 p2 + in + loop path p + ) (all_files()) + ) com.net_libs; unique !packages, unique !classes let delete_file f = try Sys.remove f with _ -> () @@ -286,7 +365,7 @@ let parse_hxml_data data = ) lines) let parse_hxml file = - let ch = IO.input_channel (try open_in_bin file with _ -> failwith ("File not found " ^ file)) in + let ch = IO.input_channel (try open_in_bin file with _ -> raise Not_found) in let data = IO.read_all ch in IO.close_in ch; parse_hxml_data data @@ -296,7 +375,7 @@ let lookup_classes com spath = | [] -> [] | cp :: l -> let cp = (if cp = "" then "./" else cp) in - let c = normalize_path (Extc.get_real_path (Common.unique_full_path cp)) in + let c = normalize_path (get_real_path (Common.unique_full_path cp)) in let clen = String.length c in if clen < String.length spath && String.sub spath 0 clen = c then begin let path = String.sub spath clen (String.length spath - clen) in @@ -333,7 +412,7 @@ let add_libs com libs = | Some cache -> (try (* if we are compiling, really call haxelib since library path might have changed *) - if not com.display then raise Not_found; + if com.display = DMNone then raise Not_found; Hashtbl.find cache.c_haxelib libs with Not_found -> let lines = call_haxelib() in @@ -423,6 +502,113 @@ let run_command ctx cmd = t(); r +let display_memory ctx = + let verbose = ctx.com.verbose in + let print = print_endline in + let fmt_size sz = + if sz < 1024 then + string_of_int sz ^ " B" + else if sz < 1024*1024 then + string_of_int (sz asr 10) ^ " KB" + else + Printf.sprintf "%.1f MB" ((float_of_int sz) /. (1024.*.1024.)) + in + let size v = + fmt_size (mem_size v) + in + Gc.full_major(); + Gc.compact(); + let mem = Gc.stat() in + print ("Total Allocated Memory " ^ fmt_size (mem.Gc.heap_words * (Sys.word_size asr 8))); + print ("Free Memory " ^ fmt_size (mem.Gc.free_words * (Sys.word_size asr 8))); + (match !global_cache with + | None -> + print "No cache found"; + | Some c -> + print ("Total cache size " ^ size c); + print (" haxelib " ^ size c.c_haxelib); + print (" parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)"); + print (" typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)"); + let rec scan_module_deps m h = + if Hashtbl.mem h m.m_id then + () + else begin + Hashtbl.add h m.m_id m; + PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps + end + in + let all_modules = Hashtbl.fold (fun _ m acc -> PMap.add m.m_id m acc) c.c_modules PMap.empty in + let modules = Hashtbl.fold (fun (path,key) m acc -> + let mdeps = Hashtbl.create 0 in + scan_module_deps m mdeps; + let deps = ref [] in + let out = ref all_modules in + Hashtbl.iter (fun _ md -> + out := PMap.remove md.m_id !out; + if m == md then () else begin + deps := Obj.repr md :: !deps; + List.iter (fun t -> + match t with + | TClassDecl c -> + deps := Obj.repr c :: !deps; + List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_statics; + List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_fields; + | TEnumDecl e -> + deps := Obj.repr e :: !deps; + List.iter (fun n -> deps := Obj.repr (PMap.find n e.e_constrs) :: !deps) e.e_names; + | TTypeDecl t -> deps := Obj.repr t :: !deps; + | TAbstractDecl a -> deps := Obj.repr a :: !deps; + ) md.m_types; + end + ) mdeps; + let chk = Obj.repr Common.memory_marker :: PMap.fold (fun m acc -> Obj.repr m :: acc) !out [] in + let inf = Objsize.objsize m !deps chk in + (m,Objsize.size_with_headers inf, (inf.Objsize.reached,!deps,!out)) :: acc + ) c.c_modules [] in + let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in + List.iter (fun (m,size,(reached,deps,out)) -> + let key = m.m_extra.m_sign in + if key <> !cur_key then begin + print (Printf.sprintf (" --- CONFIG %s ----------------------------") (Digest.to_hex key)); + cur_key := key; + end; + let sign md = + if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")" + in + print (Printf.sprintf " %s : %s" (Ast.s_type_path m.m_path) (fmt_size size)); + (if reached then try + incr mcount; + let lcount = ref 0 in + let leak l = + incr lcount; + incr tcount; + print (Printf.sprintf " LEAK %s" l); + if !lcount >= 3 && !tcount >= 100 && not verbose then begin + print (Printf.sprintf " ..."); + raise Exit; + end; + in + if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common"; + PMap.iter (fun _ md -> + if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (Ast.s_type_path md.m_path ^ sign md); + ) out; + with Exit -> + ()); + if verbose then begin + print (Printf.sprintf " %d total deps" (List.length deps)); + PMap.iter (fun _ md -> + print (Printf.sprintf " dep %s%s" (Ast.s_type_path md.m_path) (sign md)); + ) m.m_extra.m_deps; + end; + flush stdout + ) (List.sort (fun (m1,s1,_) (m2,s2,_) -> + let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in + if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1 + ) modules); + if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !"); + print "Cache dump complete") + + let default_flush ctx = List.iter prerr_endline (List.rev ctx.messages); if ctx.has_error && !prompt then begin @@ -463,8 +649,8 @@ let rec process_params create pl = loop [] l | "--cwd" :: dir :: l -> (* we need to change it immediately since it will affect hxml loading *) - (try Unix.chdir dir with _ -> ()); - loop (dir :: "--cwd" :: acc) l + (try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory")); + loop acc l | "--connect" :: hp :: l -> (match !global_cache with | None -> @@ -474,19 +660,21 @@ let rec process_params create pl = (* already connected : skip *) loop acc l) | "--run" :: cl :: args -> - let acc = (cl ^ ".main()") :: "--macro" :: acc in + let acc = cl :: "-main" :: "--interp" :: acc in let ctx = create (!each_params @ (List.rev acc)) in ctx.com.sys_args <- args; init ctx; ctx.flush() | arg :: l -> match List.rev (ExtString.String.nsplit arg ".") with - | "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) -> loop acc (parse_hxml arg @ l) + | "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) -> + let acc, l = (try acc, parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in + loop acc l | _ -> loop (arg :: acc) l in (* put --display in front if it was last parameter *) let pl = (match List.rev pl with - | file :: "--display" :: pl -> "--display" :: file :: List.rev pl + | file :: "--display" :: pl when file <> "memory" -> "--display" :: file :: List.rev pl | "use_rtti_doc" :: "-D" :: file :: "--display" :: pl -> "--display" :: file :: List.rev pl | _ -> pl ) in @@ -494,6 +682,7 @@ let rec process_params create pl = and wait_loop boot_com host port = let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in + (try Unix.setsockopt sock Unix.SO_REUSEADDR true with _ -> ()); (try Unix.bind sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't wait on " ^ host ^ ":" ^ string_of_int port)); Unix.listen sock 10; Sys.catch_break false; @@ -529,7 +718,10 @@ and wait_loop boot_com host port = Hashtbl.replace cache.c_modules (m.m_path,m.m_extra.m_sign) m; in let check_module_path com m p = - m.m_extra.m_file = Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p) + if m.m_extra.m_file <> Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p) then begin + if verbose then print_endline ("Module path " ^ s_type_path m.m_path ^ " has been changed"); + raise Not_found; + end in let compilation_step = ref 0 in let compilation_mark = ref 0 in @@ -551,14 +743,36 @@ and wait_loop boot_com host port = else try if m.m_extra.m_mark <= start_mark then begin (match m.m_extra.m_kind with - | MFake -> () (* don't get classpath *) - | MCode -> if not (check_module_path com2 m p) then raise Not_found; - | MMacro when ctx.Typecore.in_macro -> if not (check_module_path com2 m p) then raise Not_found; + | MFake | MSub -> () (* don't get classpath *) + | MExtern -> + (* if we have a file then this will override our extern type *) + let has_file = (try ignore(Typeload.resolve_module_file com2 m.m_path (ref[]) p); true with Not_found -> false) in + if has_file then begin + if verbose then print_endline ("A file is masking the library file " ^ s_type_path m.m_path); + raise Not_found; + end; + let rec loop = function + | [] -> + if verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path); + raise Not_found (* no extern registration *) + | load :: l -> + match load m.m_path p with + | None -> loop l + | Some (file,_) -> + if Common.unique_full_path file <> m.m_extra.m_file then begin + if verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); + raise Not_found; + end + in + loop com2.load_extern_type + | MCode -> check_module_path com2 m p + | MMacro when ctx.Typecore.in_macro -> check_module_path com2 m p | MMacro -> let _, mctx = Typer.get_macro_context ctx p in - if not (check_module_path mctx.Typecore.com m p) then raise Not_found; + check_module_path mctx.Typecore.com m p ); if file_time m.m_extra.m_file <> m.m_extra.m_time then begin + if verbose then print_endline ("File " ^ m.m_extra.m_file ^ (if m.m_extra.m_time = -1. then " not cached (macro-in-macro)" else " has been modified")); if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file; raise Not_found; end; @@ -595,7 +809,7 @@ and wait_loop boot_com host port = a.a_meta <- List.filter (fun (m,_,_) -> m <> Ast.Meta.ValueUsed) a.a_meta | _ -> () ) m.m_types; - Typeload.add_module ctx m p; + if m.m_extra.m_kind <> MSub then Typeload.add_module ctx m p; PMap.iter (Hashtbl.add com2.resources) m.m_extra.m_binded_res; PMap.iter (fun _ m2 -> add_modules m0 m2) m.m_extra.m_deps); List.iter (Typer.call_init_macro ctx) m.m_extra.m_macro_calls @@ -642,7 +856,7 @@ and wait_loop boot_com host port = end; in let rec cache_context com = - if not com.display then begin + if com.display = DMNone then begin List.iter cache_module com.modules; if verbose then print_endline ("Cached " ^ string_of_int (List.length com.modules) ^ " modules"); end; @@ -660,7 +874,7 @@ and wait_loop boot_com host port = ); ctx.setup <- (fun() -> Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p); - if ctx.com.display then begin + if ctx.com.display <> DMNone then begin let file = (!Parser.resume_display).Ast.pfile in let fkey = file ^ "!" ^ get_signature ctx.com in (* force parsing again : if the completion point have been changed *) @@ -677,7 +891,7 @@ and wait_loop boot_com host port = Unix.clear_nonblock sin; if verbose then print_endline ("Processing Arguments [" ^ String.concat "," data ^ "]"); (try - Common.display_default := false; + Common.display_default := DMNone; Parser.resume_display := Ast.null_pos; Typeload.return_partial_type := false; measure_times := false; @@ -712,7 +926,7 @@ and wait_loop boot_com host port = Unix.close sin; (* prevent too much fragmentation by doing some compactions every X run *) incr run_count; - if !run_count mod 1 = 50 then begin + if !run_count mod 10 = 0 then begin let t0 = get_time() in Gc.compact(); if verbose then begin @@ -764,8 +978,8 @@ and do_connect host port args = and init ctx = let usage = Printf.sprintf - "Haxe Compiler %d.%d.%d - (C)2005-2013 Haxe Foundation\n Usage : haxe%s -main [-swf|-js|-neko|-php|-cpp|-as3] [options]\n Options :" - (version / 100) ((version mod 100)/10) (version mod 10) (if Sys.os_type = "Win32" then ".exe" else "") + "Haxe Compiler %s - (C)2005-2015 Haxe Foundation\n Usage : haxe%s -main [-swf|-js|-neko|-php|-cpp|-as3] [options]\n Options :" + s_version (if Sys.os_type = "Win32" then ".exe" else "") in let com = ctx.com in let classes = ref [([],"Std")] in @@ -776,21 +990,22 @@ try let config_macros = ref [] in let cp_libs = ref [] in let added_libs = Hashtbl.create 0 in - let gen_as3 = ref false in let no_output = ref false in let did_something = ref false in let force_typing = ref false in let pre_compilation = ref [] in let interp = ref false in - Common.define_value com Define.HaxeVer (string_of_float (float_of_int version /. 100.)); - Common.raw_define com (if ((version / 10) land 1 == 0) then "haxe_release" else "haxe_svn"); + let swf_version = ref false in + let evals = ref [] in + Common.define_value com Define.HaxeVer (float_repres (float_of_int version /. 1000.)); + Common.define_value com Define.HxcppApiLevel "321"; Common.raw_define com "haxe3"; Common.define_value com Define.Dce "std"; com.warning <- (fun msg p -> message ctx ("Warning : " ^ msg) p); com.error <- error ctx; if !global_cache <> None then com.run_command <- run_command ctx; Parser.display_error := (fun e p -> com.error (Parser.error_msg e) p); - Parser.use_doc := !Common.display_default || (!global_cache <> None); + Parser.use_doc := !Common.display_default <> DMNone || (!global_cache <> None); (try let p = Sys.getenv "HAXE_STD_PATH" in let rec loop = function @@ -802,21 +1017,21 @@ try | l -> l in - let parts = "" :: Str.split_delim (Str.regexp "[;:]") p in - com.class_path <- List.map normalize_path (loop parts) + let parts = Str.split_delim (Str.regexp "[;:]") p in + com.class_path <- "" :: List.map normalize_path (loop parts) with Not_found -> if Sys.os_type = "Unix" then - com.class_path <- ["/usr/lib/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/extraLibs/";"/usr/local/lib/haxe/extraLibs/";"";"/"] + com.class_path <- ["/usr/lib/haxe/std/";"/usr/share/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/extraLibs/";"/usr/local/lib/haxe/extraLibs/";""] else - let base_path = normalize_path (Extc.get_real_path (try executable_path() with _ -> "./")) in + let base_path = normalize_path (get_real_path (try executable_path() with _ -> "./")) in com.class_path <- [base_path ^ "std/";base_path ^ "extraLibs/";""]); com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path; let set_platform pf file = if com.platform <> Cross then failwith "Multiple targets"; Common.init_platform com pf; com.file <- file; - if (pf = Flash8 || pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc; + if (pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc; in let define f = Arg.Unit (fun () -> Common.define com f) in let process_ref = ref (fun args -> ()) in @@ -829,6 +1044,7 @@ try | [] -> () | args -> (!process_ref) args in + let arg_delays = ref [] in let basic_args_spec = [ ("-cp",Arg.String (fun path -> process_libs(); @@ -838,7 +1054,6 @@ try ("-swf",Arg.String (set_platform Flash)," : compile code to Flash SWF file"); ("-as3",Arg.String (fun dir -> set_platform Flash dir; - gen_as3 := true; Common.define com Define.As3; Common.define com Define.NoInline; )," : generate AS3 code into target directory"); @@ -850,13 +1065,17 @@ try ("-cpp",Arg.String (fun dir -> set_platform Cpp dir; )," : generate C++ code into target directory"); - ("-cs",Arg.String (fun dir -> + ("-cs",Arg.String (fun dir -> + cp_libs := "hxcs" :: !cp_libs; set_platform Cs dir; )," : generate C# code into target directory"); ("-java",Arg.String (fun dir -> cp_libs := "hxjava" :: !cp_libs; set_platform Java dir; )," : generate Java code into target directory"); + ("-python",Arg.String (fun dir -> + set_platform Python dir; + )," : generate Python code as target file"); ("-xml",Arg.String (fun file -> Parser.use_doc := true; xml_out := Some file @@ -872,10 +1091,12 @@ try Common.raw_define com l; )," : use a haxelib library"); ("-D",Arg.String (fun var -> - if var = fst (Define.infos Define.UseRttiDoc) then Parser.use_doc := true; - if var = fst (Define.infos Define.NoOpt) then com.foptimize <- false; - if List.mem var reserved_flags then raise (Arg.Bad (var ^ " is a reserved compiler flag and cannot be defined from command line")); - Common.raw_define com var + begin match var with + | "no_copt" | "no-copt" -> com.foptimize <- false; + | "use_rtti_doc" | "use-rtti-doc" -> Parser.use_doc := true; + | _ -> if List.mem var reserved_flags then raise (Arg.Bad (var ^ " is a reserved compiler flag and cannot be defined from command line")); + end; + Common.raw_define com var; )," : define a conditional compilation flag"); ("-v",Arg.Unit (fun () -> com.verbose <- true @@ -893,8 +1114,9 @@ try Common.define_value com Define.Dce mode ),"[std|full|no] : set the dead code elimination mode"); ("-swf-version",Arg.Float (fun v -> - com.flash_version <- v; - )," : change the SWF version (6 to 10)"); + if not !swf_version || com.flash_version < v then com.flash_version <- v; + swf_version := true; + )," : change the SWF version"); ("-swf-header",Arg.String (fun h -> try swf_header := Some (match ExtString.String.nsplit h ":" with @@ -915,8 +1137,25 @@ try Genswf.add_swf_lib com file true )," : use the SWF library for type checking"); ("-java-lib",Arg.String (fun file -> - Genjava.add_java_lib com file false + let std = file = "lib/hxjava-std.jar" in + arg_delays := (fun () -> Genjava.add_java_lib com file std) :: !arg_delays; )," : add an external JAR or class directory library"); + ("-net-lib",Arg.String (fun file -> + let file, is_std = match ExtString.String.nsplit file "@" with + | [file] -> + file,false + | [file;"std"] -> + file,true + | _ -> raise Exit + in + arg_delays := (fun () -> Gencs.add_net_lib com file is_std) :: !arg_delays; + ),"[@std] : add an external .NET DLL file"); + ("-net-std",Arg.String (fun file -> + Gencs.add_net_std com file + )," : add a root std .NET DLL search path"); + ("-c-arg",Arg.String (fun arg -> + com.c_args <- arg :: com.c_args + )," : pass option to the native Java/C# compiler"); ("-x", Arg.String (fun file -> let neko_file = file ^ ".n" in set_platform Neko neko_file; @@ -957,23 +1196,66 @@ try List.iter (fun (_,_,extract) -> Hashtbl.iter (fun n _ -> classes := n :: !classes) (extract()) ) com.swf_libs; + List.iter (fun (_,std,_,all_files,_) -> + if not std then + List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) (all_files()) + ) com.java_libs; + List.iter (fun (_,std,all_files,_) -> + if not std then + List.iter (fun path -> classes := path :: !classes) (all_files()) + ) com.net_libs; ) :: !pre_compilation; xml_out := Some "hx" ),": generate hx headers for all input classes"); ("--next", Arg.Unit (fun() -> assert false), ": separate several haxe compilations"); + ("--each", Arg.Unit (fun() -> assert false), ": append preceding parameters to all haxe compilations separated by --next"); ("--display", Arg.String (fun file_pos -> match file_pos with | "classes" -> - pre_compilation := (fun() -> raise (Parser.TypePath (["."],None))) :: !pre_compilation; + pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true))) :: !pre_compilation; | "keywords" -> - complete_fields (Hashtbl.fold (fun k _ acc -> (k,"","") :: acc) Lexer.keywords []) + complete_fields com (Hashtbl.fold (fun k _ acc -> (k,"",None,"") :: acc) Lexer.keywords []) + | "memory" -> + did_something := true; + (try display_memory ctx with e -> prerr_endline (Printexc.get_backtrace ())); | _ -> let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in let file = unquote file in + let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in + let activate_special_display_mode () = + Common.define com Define.NoCOpt; + Parser.use_parser_resume := false + in + let mode = match smode with + | "position" -> + activate_special_display_mode(); + DMPosition + | "usage" -> + activate_special_display_mode(); + DMUsage + | "type" -> + activate_special_display_mode(); + DMType + | "toplevel" -> + activate_special_display_mode(); + DMToplevel + | "" -> + Parser.use_parser_resume := true; + DMDefault + | _ -> + let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in + match smode with + | "resolve" -> + activate_special_display_mode(); + DMResolve arg + | _ -> + Parser.use_parser_resume := true; + DMDefault + in let pos = try int_of_string pos with _ -> failwith ("Invalid format : " ^ pos) in - com.display <- true; - Common.display_default := true; - Common.define com Define.Display; + com.display <- mode; + Common.display_default := mode; + Common.define_value com Define.Display (if smode <> "" then smode else "1"); Parser.use_doc := true; Parser.resume_display := { Ast.pfile = Common.unique_full_path file; @@ -993,9 +1275,9 @@ try com.php_front <- Some f; )," : select the name for the php front file"); ("--php-lib",Arg.String (fun f -> - if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib"); - com.php_lib <- Some f; - )," : select the name for the php lib folder"); + if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib"); + com.php_lib <- Some f; + )," : select the name for the php lib folder"); ("--php-prefix", Arg.String (fun f -> if com.php_prefix <> None then raise (Arg.Bad "Multiple --php-prefix"); com.php_prefix <- Some f; @@ -1015,6 +1297,10 @@ try force_typing := true; config_macros := e :: !config_macros )," : call the given macro before typing anything else"); + ("--eval", Arg.String (fun s -> + force_typing := true; + evals := s :: !evals; + ), " : evaluates argument as Haxe module code"); ("--wait", Arg.String (fun hp -> let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in wait_loop com host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) @@ -1023,27 +1309,30 @@ try assert false ),"<[host:]port> : connect on the given port and run commands there)"); ("--cwd", Arg.String (fun dir -> - (try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory")) + assert false ),"
: set current working directory"); ("-version",Arg.Unit (fun() -> - message ctx (Printf.sprintf "%d.%d.%d" (version / 100) ((version mod 100)/10) (version mod 10)) Ast.null_pos; + message ctx s_version Ast.null_pos; did_something := true; ),": print version and exit"); ("--help-defines", Arg.Unit (fun() -> + let m = ref 0 in let rec loop i = let d = Obj.magic i in if d <> Define.Last then begin let t, doc = Define.infos d in - let str = String.concat "-" (ExtString.String.nsplit t "_") ^ " : " ^ doc in - str :: loop (i + 1) + if String.length t > !m then m := String.length t; + ((String.concat "-" (ExtString.String.nsplit t "_")),doc) :: (loop (i + 1)) end else [] in - let all = List.sort String.compare (loop 0) in + let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in + let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" !m n (limit_string doc (!m + 3))) all in List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all; did_something := true ),": print help for all compiler specific defines"); ("--help-metas", Arg.Unit (fun() -> + let m = ref 0 in let rec loop i = let d = Obj.magic i in if d <> Meta.Last then begin @@ -1067,41 +1356,51 @@ try | [p] -> " (" ^ platform_name p ^ " only)" | pl -> " (for " ^ String.concat "," (List.map platform_name pl) ^ ")" ) in - let str = "@" ^ t ^ params ^ " : " ^ doc ^ pfs in - str :: loop (i + 1) + let str = "@" ^ t in + if String.length str > !m then m := String.length str; + (str,params ^ doc ^ pfs) :: loop (i + 1) end else loop (i + 1) end else [] in - let all = List.sort String.compare (loop 0) in + let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in + let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" !m n (limit_string doc (!m + 3))) all in List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all; did_something := true ),": print help for all compiler metadatas"); ] in let args_callback cl = classes := make_path cl :: !classes in + let all_args_spec = basic_args_spec @ adv_args_spec in let process args = let current = ref 0 in - Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) (basic_args_spec @ adv_args_spec) args_callback usage + (try + Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) all_args_spec args_callback usage; + List.iter (fun fn -> fn()) !arg_delays + with (Arg.Bad msg) as exc -> + let r = Str.regexp "unknown option `\\([-A-Za-z]+\\)'" in + try + ignore(Str.search_forward r msg 0); + let s = Str.matched_group 1 msg in + let sl = List.map (fun (s,_,_) -> s) all_args_spec in + let msg = Typecore.string_error_raise s sl (Printf.sprintf "Invalid command: %s" s) in + raise (Arg.Bad msg) + with Not_found -> + raise exc); + arg_delays := [] in process_ref := process; process ctx.com.args; process_libs(); - (try ignore(Common.find_file com "mt/Include.hx"); Common.raw_define com "mt"; with Not_found -> ()); - if com.display then begin - let mode = Common.defined_value_safe com Define.DisplayMode in - if mode = "usage" then begin - com.display <- false; - Common.display_default := false; - end; + if com.display <> DMNone then begin com.warning <- message ctx; com.error <- error ctx; com.main_class <- None; - let real = Extc.get_real_path (!Parser.resume_display).Ast.pfile in + let real = get_real_path (!Parser.resume_display).Ast.pfile in classes := lookup_classes com real; if !classes = [] then begin - if not (Sys.file_exists real) then failwith "Display file does not exists"; - (match List.rev (ExtString.String.nsplit real "\\") with + if not (Sys.file_exists real) then failwith "Display file does not exist"; + (match List.rev (ExtString.String.nsplit real path_sep) with | file :: _ when file.[0] >= 'a' && file.[1] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter") | _ -> ()); failwith "Display file was not found in class path"; @@ -1117,28 +1416,18 @@ try (* no platform selected *) set_platform Cross ""; "?" - | Flash8 | Flash -> - if com.flash_version >= 9. then begin - let rec loop = function - | [] -> () - | (v,_) :: _ when v > com.flash_version -> () - | (v,def) :: l -> - Common.raw_define com ("flash" ^ def); - loop l - in - loop Common.flash_versions; - Common.raw_define com "flash"; - com.defines <- PMap.remove "flash8" com.defines; - com.package_rules <- PMap.remove "flash" com.package_rules; - add_std "flash"; - end else begin - com.package_rules <- PMap.add "flash" (Directory "flash8") com.package_rules; - com.package_rules <- PMap.add "flash8" Forbidden com.package_rules; - Common.raw_define com "flash"; - Common.raw_define com ("flash" ^ string_of_int (int_of_float com.flash_version)); - com.platform <- Flash8; - add_std "flash8"; - end; + | Flash -> + let rec loop = function + | [] -> () + | (v,_) :: _ when v > com.flash_version -> () + | (v,def) :: l -> + Common.raw_define com ("flash" ^ def); + loop l + in + loop Common.flash_versions; + Common.raw_define com "flash"; + com.package_rules <- PMap.remove "flash" com.package_rules; + add_std "flash"; "swf" | Neko -> add_std "neko"; @@ -1153,27 +1442,45 @@ try add_std "cpp"; "cpp" | Cs -> + let old_flush = ctx.flush in + ctx.flush <- (fun () -> + com.net_libs <- []; + old_flush() + ); Gencs.before_generate com; add_std "cs"; "cs" | Java -> - let old_flush = ctx.flush in - ctx.flush <- (fun () -> - List.iter (fun (_,_,close,_,_) -> close()) com.java_libs; - old_flush() - ); + let old_flush = ctx.flush in + ctx.flush <- (fun () -> + List.iter (fun (_,_,close,_,_) -> close()) com.java_libs; + com.java_libs <- []; + old_flush() + ); Genjava.before_generate com; add_std "java"; "java" + | Python -> + add_std "python"; + "python" ) 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 && 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; + begin match com.display with + | DMNone | DMToplevel -> + () + | _ -> + 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 *) - (* check file extension. In case of wrong commandline, we don't want - to accidentaly delete a source file. *) - if not !no_output && file_extension com.file = ext then delete_file com.file; List.iter (fun f -> f()) (List.rev (!pre_compilation)); if !classes = [([],"Std")] && not !force_typing then begin - if !cmds = [] && not !did_something then Arg.usage basic_args_spec usage; + let help_spec = basic_args_spec @ [ + ("-help", Arg.Unit (fun () -> ()),": show extended help information"); + ("--help", Arg.Unit (fun () -> ()),": show extended help information"); + ("--help-defines", Arg.Unit (fun () -> ()),": print help for all compiler specific defines"); + ("--help-metas", Arg.Unit (fun () -> ()),": print help for all compiler metadatas"); + ("", Arg.Unit (fun () -> ()),": compile the module specified by dot-path"); + ] in + if !cmds = [] && not !did_something then Arg.usage help_spec usage; end else begin ctx.setup(); Common.log com ("Classpath : " ^ (String.concat ";" com.class_path)); @@ -1182,59 +1489,46 @@ try Typecore.type_expr_ref := (fun ctx e with_type -> Typer.type_expr ctx e with_type); let tctx = Typer.create com in List.iter (Typer.call_init_macro tctx) (List.rev !config_macros); + List.iter (Typer.eval tctx) !evals; List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath Ast.null_pos)) (List.rev !classes); Typer.finalize tctx; t(); if ctx.has_error then raise Abort; - if com.display then begin - if ctx.has_next then raise Abort; - failwith "No completion point was found"; + begin match com.display with + | DMNone | DMUsage | DMPosition | DMType | DMResolve _ -> + () + | _ -> + if ctx.has_next then raise Abort; + failwith "No completion point was found"; end; let t = Common.timer "filters" in let main, types, modules = Typer.generate tctx in com.main <- main; com.types <- types; com.modules <- modules; - let filters = [ - Codegen.Abstract.handle_abstract_casts tctx; - if com.foptimize then (fun e -> Optimizer.reduce_expression tctx (Optimizer.inline_constructors tctx e)) else Optimizer.sanitize tctx; - Codegen.check_local_vars_init; - Codegen.captured_vars com; - Codegen.rename_local_vars com; - ] in - List.iter (Codegen.post_process filters) com.types; - Codegen.post_process_end(); - List.iter (fun f -> f()) (List.rev com.filters); - List.iter (Codegen.save_class_state tctx) com.types; - if Common.defined_value_safe com Define.DisplayMode = "usage" then - Codegen.detect_usage com; - let dce_mode = (try Common.defined_value com Define.Dce with _ -> "no") in - if not (!gen_as3 || dce_mode = "no" || Common.defined com Define.DocGen) then Dce.run com main (dce_mode = "full" && not !interp); - let type_filters = [ - Codegen.check_private_path; - Codegen.remove_generic_base; - Codegen.apply_native_paths; - Codegen.add_rtti; - Codegen.remove_extern_fields; - (match ctx.com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> Codegen.add_field_inits); - Codegen.add_meta_field; - Codegen.check_remove_metadata; - Codegen.check_void_field; - ] in - let type_filters = if ctx.com.platform = Java then Codegen.promote_abstract_parameters :: type_filters else type_filters in - List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types; + Filters.run com tctx main; if ctx.has_error then raise Abort; + (* check file extension. In case of wrong commandline, we don't want + to accidentaly delete a source file. *) + if not !no_output && file_extension com.file = ext then delete_file com.file; (match !xml_out with | None -> () | Some "hx" -> Genxml.generate_hx com | Some file -> Common.log com ("Generating xml : " ^ file); + Common.mkdir_from_path file; Genxml.generate com file); if com.platform = Flash || com.platform = Cpp then List.iter (Codegen.fix_overrides com) com.types; if Common.defined com Define.Dump then Codegen.dump_types com; if Common.defined com Define.DumpDependencies then Codegen.dump_dependencies com; t(); + if not !no_output then begin match com.platform with + | Neko when !interp -> () + | Cpp when Common.defined com Define.Cppia -> () + | Cpp | Cs | Java | Php -> Common.mkdir_from_path (com.file ^ "/.") + | _ -> Common.mkdir_from_path com.file + end; (match com.platform with | _ when !no_output -> if !interp then begin @@ -1246,10 +1540,10 @@ try end; | Cross -> () - | Flash8 | Flash when !gen_as3 -> + | Flash when Common.defined com Define.As3 -> Common.log com ("Generating AS3 in : " ^ com.file); Genas3.generate com; - | Flash8 | Flash -> + | Flash -> Common.log com ("Generating swf : " ^ com.file); Genswf.generate com !swf_header; | Neko -> @@ -1270,16 +1564,26 @@ try | Java -> Common.log com ("Generating Java in : " ^ com.file); Genjava.generate com; + | Python -> + Common.log com ("Generating python in : " ^ com.file); + Genpy.generate com; ); end; Sys.catch_break false; - if not !no_output then List.iter (fun c -> - let r = run_command ctx c in - if r <> 0 then failwith ("Command failed with error " ^ string_of_int r) - ) (List.rev !cmds) + List.iter (fun f -> f()) (List.rev com.final_filters); + if not !no_output then begin + List.iter (fun c -> + let r = run_command ctx c in + if r <> 0 then failwith ("Command failed with error " ^ string_of_int r) + ) (List.rev !cmds) + end with - | Abort | Typecore.Fatal_error -> + | Abort -> () + | Ast.Error (m,p) -> + error ctx m p + | Typecore.Fatal_error (m,p) -> + error ctx m p | Common.Abort (m,p) -> error ctx m p | Lexer.Error (m,p) -> @@ -1287,7 +1591,7 @@ with | Parser.Error (m,p) -> error ctx (Parser.error_msg m) p | Typecore.Forbid_package ((pack,m,p),pl,pf) -> - if !Common.display_default && ctx.has_next then begin + if !Common.display_default <> DMNone && ctx.has_next then begin ctx.has_error <- false; ctx.messages <- []; end else begin @@ -1300,6 +1604,8 @@ with message ctx msg p; List.iter (message ctx "Called from") l; error ctx "Aborted" Ast.null_pos; + | Codegen.Generic_Exception(m,p) -> + error ctx m p | Arg.Bad msg -> error ctx ("Error: " ^ msg) Ast.null_pos | Failure msg when not (is_debug_run()) -> @@ -1308,21 +1614,21 @@ with message ctx msg Ast.null_pos | Typer.DisplayFields fields -> let ctx = print_context() in - let fields = List.map (fun (name,t,doc) -> name, s_type ctx t, (match doc with None -> "" | Some d -> d)) fields in + let fields = List.map (fun (name,t,kind,doc) -> name, s_type ctx t, kind, (match doc with None -> "" | Some d -> d)) fields in let fields = if !measure_times then begin close_times(); let tot = ref 0. in Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers; - let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), "") :: fields in + let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), None, "") :: fields in if !tot > 0. then Hashtbl.fold (fun _ t acc -> - ("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), "") :: acc + ("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), None, "") :: acc ) Common.htimers fields else fields end else fields in - complete_fields fields + complete_fields com fields | Typecore.DisplayTypes tl -> let ctx = print_context() in let b = Buffer.create 0 in @@ -1335,38 +1641,52 @@ with | Typecore.DisplayPosition pl -> let b = Buffer.create 0 in let error_printer file line = sprintf "%s:%d:" (Common.unique_full_path file) line in + Buffer.add_string b "\n"; List.iter (fun p -> let epos = Lexer.get_error_pos error_printer p in - Buffer.add_string b "\n"; + Buffer.add_string b ""; Buffer.add_string b epos; - Buffer.add_string b "\n\n"; + Buffer.add_string b "\n"; ) pl; + Buffer.add_string b ""; raise (Completion (Buffer.contents b)) - | Typer.DisplayMetadata m -> + | Typer.DisplayToplevel il -> let b = Buffer.create 0 in - List.iter (fun (m,el,p) -> - Buffer.add_string b ("" else begin - Buffer.add_string b ">\n"; - List.iter (fun e -> Buffer.add_string b ((htmlescape (Genxml.sexpr e)) ^ "\n")) el; - Buffer.add_string b "\n"; - end - ) m; + Buffer.add_string b "\n"; + let ctx = print_context() in + let s_type t = htmlescape (s_type ctx t) in + List.iter (fun id -> match id with + | Typer.ITLocal v -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type v.v_type) v.v_name); + | Typer.ITMember(c,cf) -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type cf.cf_type) cf.cf_name); + | Typer.ITStatic(c,cf) -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type cf.cf_type) cf.cf_name); + | Typer.ITEnum(en,ef) -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type ef.ef_type) ef.ef_name); + | Typer.ITGlobal(mt,s,t) -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type_path (t_infos mt).mt_path) (s_type t) s); + | Typer.ITType(mt) -> Buffer.add_string b (Printf.sprintf "%s\n" (s_type_path (t_infos mt).mt_path) (snd (t_infos mt).mt_path)); + | Typer.ITPackage s -> Buffer.add_string b (Printf.sprintf "%s\n" s) + ) il; + Buffer.add_string b ""; raise (Completion (Buffer.contents b)) - | Parser.TypePath (p,c) -> + | Parser.TypePath (p,c,is_import) -> (match c with | None -> let packs, classes = read_type_path com p in if packs = [] && classes = [] then error ctx ("No classes found in " ^ String.concat "." p) Ast.null_pos else - complete_fields (List.map (fun f -> f,"","") (packs @ classes)) + complete_fields com ( + let convert k f = (f,"",Some k,"") in + (List.map (convert Typer.FKPackage) packs) @ (List.map (convert Typer.FKType) classes) + ) | Some (c,cur_package) -> try + let sl_pack,s_module = match List.rev p with + | s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s + | _ -> p,c + in let ctx = Typer.create com in let rec lookup p = try - Typeload.load_module ctx (p,c) Ast.null_pos + Typeload.load_module ctx (p,s_module) Ast.null_pos with e -> if cur_package then match List.rev p with @@ -1375,12 +1695,39 @@ with else raise e in - let m = lookup p in - complete_fields (List.map (fun t -> snd (t_path t),"","") (List.filter (fun t -> not (t_infos t).mt_private) m.m_types)) + let m = lookup sl_pack in + let statics = ref None in + let public_types = List.filter (fun t -> + let tinfos = t_infos t in + let is_module_type = snd tinfos.mt_path = c in + if is_import && is_module_type then begin match t with + | TClassDecl c -> + ignore(c.cl_build()); + statics := Some c.cl_ordered_statics + | _ -> () + end; + not tinfos.mt_private + ) m.m_types in + let types = if c <> s_module then [] else List.map (fun t -> snd (t_path t),"",Some Typer.FKType,"") public_types in + let ctx = print_context() in + let make_field_doc cf = + cf.cf_name, + s_type ctx cf.cf_type, + Some (match cf.cf_kind with Method _ -> Typer.FKMethod | Var _ -> Typer.FKVar), + (match cf.cf_doc with Some s -> s | None -> "") + in + let types = match !statics with + | None -> types + | Some cfl -> types @ (List.map make_field_doc (List.filter (fun cf -> cf.cf_public) cfl)) + in + complete_fields com types with Completion c -> raise (Completion c) | _ -> error ctx ("Could not load module " ^ (Ast.s_type_path (p,c))) Ast.null_pos) + | Interp.Sys_exit i -> + ctx.flush(); + exit i | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || !global_cache <> None with _ -> true) && not (is_debug_run()) -> error ctx (Printexc.to_string e) Ast.null_pos diff --git a/matcher.ml b/matcher.ml index 011de78db7406092f762f0fe674c60c2fdc55044..49397060eb86b4fc3c2196b93ffccd049499bb58 100644 --- a/matcher.ml +++ b/matcher.ml @@ -1,1307 +1,1454 @@ -(* - * Copyright (C)2005-2013 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. - *) - -open Ast -open Common -open Type -open Typecore - -type con_def = - | CEnum of tenum * tenum_field - | CConst of tconstant - | CType of module_type - | CArray of int - | CFields of int * (string * tclass_field) list - | CExpr of texpr - -and con = { - c_def : con_def; - c_type : t; - c_pos : pos; -} - -type pvar = tvar * pos - -type pat_def = - | PAny - | PVar of pvar - | PCon of con * pat list - | POr of pat * pat - | PBind of pvar * pat - | PTuple of pat array - -and pat = { - p_def : pat_def; - p_type : t; - p_pos : pos; -} - -type st_def = - | SVar of tvar - | SField of st * string - | SEnum of st * string * int - | SArray of st * int - | STuple of st * int * int - -and st = { - st_def : st_def; - st_type : t; - st_pos : pos; -} - -type out = { - o_expr : texpr; - o_guard : texpr option; - o_pos : pos; - o_id : int; -} - -type pat_vec = pat array * out -type pat_matrix = pat_vec list - -type pattern_ctx = { - mutable pc_locals : (string, pvar) PMap.t; - mutable pc_sub_vars : (string, pvar) PMap.t option; - mutable pc_reify : bool; -} - -type dt = - | Out of out * dt option - | Switch of st * (con * dt) list - | Bind of (pvar * st) list * dt - | Goto of int - -type matcher = { - ctx : typer; - stl : st list; - need_val : bool; - v_lookup : (string,tvar) Hashtbl.t; - mutable outcomes : (pat list,out) PMap.t; - mutable out_type : Type.t; - mutable toplevel_or : bool; - mutable used_paths : (int,bool) Hashtbl.t; - mutable eval_stack : (pvar * st) list list; -} - -exception Not_exhaustive of pat * st -exception Unrecognized_pattern of Ast.expr - -let arity con = match con.c_def with - | CEnum (_,{ef_type = TFun(args,_)}) -> List.length args - | CEnum _ -> 0 - | CConst _ -> 0 - | CType mt -> 0 - | CArray i -> i - | CFields (i,_) -> i - | CExpr _ -> 0 - -let mk_st def t p = { - st_def = def; - st_type = t; - st_pos = p; -} - -let mk_out mctx id e eg pl p = - let out = { - o_expr = e; - o_guard = eg; - o_pos = p; - o_id = id; - } in - mctx.outcomes <- PMap.add pl out mctx.outcomes; - out - -let clone_out mctx out pl p = - let out = {out with o_pos = p; } in - out - -let mk_pat pdef t p = { - p_def = pdef; - p_type = t; - p_pos = p; -} - -let mk_con cdef t p = { - c_def = cdef; - c_type = t; - c_pos = p; -} - -let mk_con_pat cdef pl t p = { - p_def = PCon(mk_con cdef t p,pl); - p_type = t; - p_pos = p; -} - -let mk_any t p = { - p_def = PAny; - p_type = t; - p_pos = p; -} - -let any = mk_any t_dynamic Ast.null_pos - -let fake_tuple_type = TInst(mk_class null_module ([],"-Tuple") null_pos, []) - -let mk_subs st con = - let map = match follow st.st_type with - | TInst(c,pl) -> apply_params c.cl_types pl - | TEnum(en,pl) -> apply_params en.e_types pl - | _ -> fun t -> t - in - match con.c_def with - | CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,s)) (map cf.cf_type) st.st_pos) fl - | CEnum (en,({ef_type = TFun _} as ef)) -> - let pl = match follow con.c_type with TEnum(_,pl) | TAbstract({a_this = TEnum(_)},pl)-> pl | TAbstract({a_path = [],"EnumValue"},[]) -> [] | _ -> [] in - begin match apply_params en.e_types pl (monomorphs ef.ef_params ef.ef_type) with - | TFun(args,r) -> - ExtList.List.mapi (fun i (_,_,t) -> - mk_st (SEnum(st,ef.ef_name,i)) t st.st_pos - ) args - | _ -> - assert false - end - | CArray 0 -> [] - | CArray i -> - let t = match follow con.c_type with TInst({cl_path=[],"Array"},[t]) -> t | _ -> assert false in - ExtList.List.init i (fun i -> mk_st (SArray(st,i)) t st.st_pos) - | CEnum _ | CConst _ | CType _ | CExpr _ -> - [] - -let get_tuple_types t = match t with - | TFun(tl,tr) when tr == fake_tuple_type -> Some tl - | _ -> None - -(* Printing *) - -let s_type = s_type (print_context()) - -let rec s_expr_small e = match e.eexpr with - | TLocal v -> v.v_name - | TField (e,s) -> s_expr_small e ^ "." ^ field_name s - | TBlock [] -> "{}" - | _ -> s_expr (s_type) e - -let s_con con = match con.c_def with - | CEnum(_,ef) -> ef.ef_name - | CConst TNull -> "_" - | CConst c -> s_const c - | CType mt -> s_type_path (t_path mt) - | CArray i -> "[" ^(string_of_int i) ^ "]" - | CFields (_,fl) -> String.concat "," (List.map (fun (s,_) -> s) fl) - | CExpr e -> s_expr s_type e - -let rec s_pat pat = match pat.p_def with - | PVar (v,_) -> v.v_name - | PCon (c,[]) -> s_con c - | PCon (c,pl) -> s_con c ^ "(" ^ (String.concat "," (List.map s_pat pl)) ^ ")" - | POr (pat1,pat2) -> s_pat pat1 ^ " | " ^ s_pat pat2 - | PAny -> "_" - | PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat - | PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")" - -let st_args l r v = - (if l > 0 then (String.concat "," (ExtList.List.make l "_")) ^ "," else "") - ^ v ^ - (if r > 0 then "," ^ (String.concat "," (ExtList.List.make r "_")) else "") - -let rec s_st st = (match st.st_def with - | SVar v -> v.v_name - | SEnum (st,n,i) -> s_st st ^ "." ^ n ^ "." ^ (string_of_int i) - | SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]" - | STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")" - | SField (st,n) -> s_st st ^ "." ^ n) - (* ^ ":" ^ (s_type st.st_type) *) - -let rec s_pat_vec pl = - String.concat " " (Array.to_list (Array.map s_pat pl)) - -let s_out out = "" - (* ^ s_expr_small out.o_expr *) - -let rec s_pat_matrix pmat = - String.concat "\n" (List.map (fun (pl,out) -> (s_pat_vec pl) ^ "->" ^ (s_out out)) pmat) - -let rec s_dt tabs tree = tabs ^ match tree with - | Out(out,None)-> - s_out out; - | Out(out,Some dt) -> - "if (" ^ (s_expr_small (match out.o_guard with Some e -> e | None -> assert false)) ^ ") " ^ (s_out out) ^ " else " ^ s_dt tabs dt - | Switch (st, cl) -> - "switch(" ^ (s_st st) ^ ") { \n" ^ tabs - ^ (String.concat ("\n" ^ tabs) (List.map (fun (c,dt) -> - "case " ^ (s_con c) ^ ":\n" ^ (s_dt (tabs ^ "\t") dt) - ) cl)) - ^ "\n" ^ (if String.length tabs = 0 then "" else (String.sub tabs 0 (String.length tabs - 1))) ^ "}" - | Bind (bl, dt) -> "bind " ^ (String.concat "," (List.map (fun ((v,_),st) -> v.v_name ^ "(" ^ (string_of_int v.v_id) ^ ") =" ^ (s_st st)) bl)) ^ "\n" ^ (s_dt tabs dt) - | Goto i -> - "goto " ^ (string_of_int i) - -(* Pattern parsing *) - -let unify_enum_field en pl ef t = - let t2 = match follow ef.ef_type with - | TFun(_,r) -> r - | t2 -> t2 - in - let t2 = (apply_params en.e_types pl (monomorphs ef.ef_params t2)) in - Type.unify t2 t - -let unify ctx a b p = - try unify_raise ctx a b p with Error (Unify l,p) -> error (error_msg (Unify l)) p - -let rec is_value_type = function - | TMono r -> - (match !r with None -> false | Some t -> is_value_type t) - | TType (t,tl) -> - is_value_type (apply_params t.t_types tl t.t_type) - | TInst({cl_path=[],"String"},[]) -> - true - | TAbstract _ -> - true - | _ -> - false - -let to_pattern ctx e t = - let perror p = error "Unrecognized pattern" p in - let verror n p = error ("Variable " ^ n ^ " must appear exactly once in each sub-pattern") p in - let mk_var tctx s t p = - let v = match tctx.pc_sub_vars with - | Some vmap -> fst (try PMap.find s vmap with Not_found -> verror s p) - | None -> alloc_var s t - in - unify ctx t v.v_type p; - if PMap.mem s tctx.pc_locals then verror s p; - tctx.pc_locals <- PMap.add s (v,p) tctx.pc_locals; - v - in - let rec loop pctx e t = - let p = pos e in - match fst e with - | EConst(Ident "null") -> - error "null-patterns are not allowed" p - | ECheckType(e, CTPath({tpackage=["haxe";"macro"]; tname="Expr"})) -> - let old = pctx.pc_reify in - pctx.pc_reify <- true; - let e = loop pctx e t in - pctx.pc_reify <- old; - e - | EParenthesis e -> - loop pctx e t - | ECast(e1,None) -> - loop pctx e1 t - | EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as c) -> - let e = Codegen.type_constant ctx.com c p in - unify ctx e.etype t p; - let c = match e.eexpr with TConst c -> c | _ -> assert false in - mk_con_pat (CConst c) [] t p - | EField _ -> - let e = type_expr ctx e (WithType t) in - let e = match Optimizer.make_constant_expression ctx ~concat_strings:true e with Some e -> e | None -> e in - (match e.eexpr with - | TConst c -> mk_con_pat (CConst c) [] t p - | TTypeExpr mt -> mk_con_pat (CType mt) [] t p - | TField(_, FStatic(_,cf)) when is_value_type cf.cf_type -> - mk_con_pat (CExpr e) [] cf.cf_type p - | TField(_, FEnum(en,ef)) -> - begin try - unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_types) ef t - with Unify_error l -> - error (error_msg (Unify l)) p - end; - mk_con_pat (CEnum(en,ef)) [] t p - | _ -> error "Constant expression expected" p) - | ECall(ec,el) -> - let ec = type_expr ctx ec (WithType t) in - (match follow ec.etype with - | TEnum(en,pl) - | TFun(_,TEnum(en,pl)) -> - let ef = match ec.eexpr with - | TField (_,FEnum (_,f)) -> f - | _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p - in - let monos = List.map (fun _ -> mk_mono()) ef.ef_params in - let tl,r = match apply_params en.e_types pl (apply_params ef.ef_params monos ef.ef_type) with - | TFun(args,r) -> - unify ctx r t p; - List.map (fun (n,_,t) -> t) args,r - | _ -> error "Arguments expected" p - in - let rec loop2 i el tl = match el,tl with - | (EConst(Ident "_"),pany) :: [], t :: tl -> - let pat = mk_pat PAny t_dynamic pany in - (ExtList.List.make ((List.length tl) + 1) pat) - | e :: el, t :: tl -> - let pat = loop pctx e t in - pat :: loop2 (i + 1) el tl - | e :: _, [] -> - error "Too many arguments" (pos e); - | [],_ :: _ -> - error "Not enough arguments" p; - | [],[] -> - [] - in - let el = loop2 0 el tl in - List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ef.ef_params; - mk_con_pat (CEnum(en,ef)) el r p - | _ -> perror p) - | EConst(Ident "_") -> - begin match get_tuple_types t with - | Some tl -> - let pl = List.map (fun (_,_,t) -> mk_any t p) tl in - { - p_def = PTuple (Array.of_list pl); - p_pos = p; - p_type = t_dynamic; - } - | None -> - mk_any t p - end - | EConst(Ident s) -> - begin try - let ec = match follow t with - | TEnum(en,pl) -> - let ef = try - PMap.find s en.e_constrs - with Not_found when not (is_lower_ident s) -> - error (string_error s en.e_names ("Expected constructor for enum " ^ (s_type_path en.e_path))) p - in - (match ef.ef_type with - | TFun (args,_) -> - let msg = Printf.sprintf "Enum constructor %s.%s requires parameters %s" - (s_type_path en.e_path) - ef.ef_name - (String.concat ", " (List.map (fun (n,_,t) -> n ^ ":" ^ (s_type t)) args)) - in - error msg p - | _ -> ()); - let et = mk (TTypeExpr (TEnumDecl en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics en) }) p in - mk (TField (et,FEnum (en,ef))) (apply_params en.e_types pl ef.ef_type) p - | _ -> - let old = ctx.untyped in - ctx.untyped <- true; - let e = try type_expr ctx e (WithType t) with _ -> ctx.untyped <- old; raise Not_found in - ctx.untyped <- old; - e - in - let ec = match Optimizer.make_constant_expression ctx ~concat_strings:true ec with Some e -> e | None -> ec in - (match ec.eexpr with - | TField (_,FEnum (en,ef)) -> - begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end; - begin try - unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_types) ef t; - with Unify_error l -> - error (error_msg (Unify l)) p - end; - mk_con_pat (CEnum(en,ef)) [] t p - | TConst c -> - begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end; - unify ctx ec.etype t p; - mk_con_pat (CConst c) [] t p - | TTypeExpr mt -> - let tcl = Typeload.load_instance ctx {tname="Class";tpackage=[];tsub=None;tparams=[]} p true in - let t2 = match tcl with TAbstract(a,_) -> TAbstract(a,[mk_mono()]) | _ -> assert false in - mk_con_pat (CType mt) [] t2 p - | _ -> - raise Not_found); - with Not_found -> - if not (is_lower_ident s) && s.[0] <> '`' then error "Capture variables must be lower-case" p; - begin match get_tuple_types t with - | Some _ -> - error "Cannot bind tuple" p - | None -> - let v = mk_var pctx s t p in - mk_pat (PVar (v,p)) v.v_type p - end - end - | (EObjectDecl fl) -> - let is_matchable cf = match cf.cf_kind with Method _ | Var {v_read = AccCall} -> false | _ -> true in - let is_valid_field_name fields n p = - try - let cf = PMap.find n fields in - if not (is_matchable cf) then error ("Cannot match against method or property with getter " ^ n) p; - with Not_found -> - error (unify_error_msg (print_context()) (has_extra_field t n)) p - in - begin match follow t with - | TAnon {a_fields = fields} -> - List.iter (fun (n,(_,p)) -> is_valid_field_name fields n p) fl; - let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) -> - if not (is_matchable cf) then - sl,pl,i - else - let pat = - try - if pctx.pc_reify && cf.cf_name = "pos" then raise Not_found; - loop pctx (List.assoc n fl) cf.cf_type - with Not_found -> - (mk_any cf.cf_type p) - in - (n,cf) :: sl,pat :: pl,i + 1 - ) fields ([],[],0) in - mk_con_pat (CFields(i,sl)) pl t p - | TInst(c,tl) -> - List.iter (fun (n,(_,p)) -> is_valid_field_name c.cl_fields n p) fl; - let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) -> - if not (is_matchable cf) then - sl,pl,i - else - let t = apply_params c.cl_types tl (monomorphs cf.cf_params cf.cf_type) in - let pat = try loop pctx (List.assoc n fl) t with Not_found -> (mk_any t p) in - (n,cf) :: sl,pat :: pl,i + 1 - ) c.cl_fields ([],[],0) in - mk_con_pat (CFields(i,sl)) pl t p - | _ -> - error ((s_type t) ^ " should be { }") p - end - | EArrayDecl [] -> - mk_con_pat (CArray 0) [] t p - | EArrayDecl el -> - begin match follow t with - | TInst({cl_path=[],"Array"},[t2]) -> - let pl = ExtList.List.mapi (fun i e -> - loop pctx e t2 - ) el in - mk_con_pat (CArray (List.length el)) pl t p - | TFun(tl,tr) when tr == fake_tuple_type -> - let pl = try - List.map2 (fun e (_,_,t) -> loop pctx e t) el tl - with Invalid_argument _ -> - error ("Invalid number of arguments: expected " ^ (string_of_int (List.length tl)) ^ ", found " ^ (string_of_int (List.length el))) p - in - { - p_def = PTuple (Array.of_list pl); - p_pos = p; - p_type = t_dynamic; - } - | _ -> - error ((s_type t) ^ " should be Array") p - end - | EBinop(OpAssign,(EConst(Ident s),p2),e1) -> - let v = mk_var pctx s t p in - let pat1 = loop pctx e1 t in - mk_pat (PBind((v,p),pat1)) t p2 - | EBinop(OpOr,(EBinop(OpOr,e1,e2),p2),e3) -> - loop pctx (EBinop(OpOr,e1,(EBinop(OpOr,e2,e3),p2)),p) t - | EBinop(OpOr,e1,e2) -> - let old = pctx.pc_locals in - let rec dup t = match t with - | TMono r -> (match !r with - | None -> mk_mono() - | Some t -> Type.map dup t) - | _ -> Type.map dup t - in - let t2 = dup t in - let pat1 = loop pctx e1 t in - begin match pat1.p_def with - | PAny | PVar _ -> - ctx.com.warning "This pattern is unused" (pos e2); - pat1 - | _ -> - let pctx2 = { - pc_sub_vars = Some pctx.pc_locals; - pc_locals = old; - pc_reify = pctx.pc_reify; - } in - let pat2 = loop pctx2 e2 t2 in - PMap.iter (fun s (_,p) -> if not (PMap.mem s pctx2.pc_locals) then verror s p) pctx.pc_locals; - mk_pat (POr(pat1,pat2)) pat2.p_type (punion pat1.p_pos pat2.p_pos); - end - | _ -> - raise (Unrecognized_pattern e) - in - let pctx = { - pc_locals = PMap.empty; - pc_sub_vars = None; - pc_reify = false; - } in - loop pctx e t, pctx.pc_locals - -let get_pattern_locals ctx e t = - try - let _,locals = to_pattern ctx e t in - PMap.foldi (fun n (v,_) acc -> PMap.add n v acc) locals PMap.empty - with Unrecognized_pattern _ -> - PMap.empty - -(* Match compilation *) - -let unify_con con1 con2 = match con1.c_def,con2.c_def with - | CExpr e1, CExpr e2 -> - e1 == e2 - | CConst c1,CConst c2 -> - c1 = c2 - | CEnum(e1,ef1),CEnum(e2,ef2) -> - e1 == e2 && ef1.ef_name = ef2.ef_name - | CFields (i1,fl1),CFields (i2,fl2) -> - (try - List.iter (fun (s,_) -> if not (List.mem_assoc s fl1) then raise Not_found) fl2; - true - with Not_found -> - false) - | CType mt1,CType mt2 -> - t_path mt1 = t_path mt2 - | CArray a1, CArray a2 -> - a1 == a2 - | _ -> - false - -let array_tl arr = Array.sub arr 1 (Array.length arr - 1) - -let spec mctx con pmat = - let a = arity con in - let r = DynArray.create () in - let add pv out = - DynArray.add r (pv,out) - in - let rec loop2 pv out = match pv.(0).p_def with - | PCon(c2,pl) when unify_con c2 con -> - add (Array.append (Array.of_list pl) (array_tl pv)) out - | PCon(c2,pl) -> - () - | PAny | PVar _-> - add (Array.append (Array.make a (mk_any (pv.(0).p_type) (pv.(0).p_pos))) (array_tl pv)) out - | POr(pat1,pat2) -> - let tl = array_tl pv in - let out2 = clone_out mctx out [pat2] pat2.p_pos in - loop2 (Array.append [|pat1|] tl) out; - loop2 (Array.append [|pat2|] tl) out2; - | PBind(_,pat) -> - loop2 (Array.append [|pat|] (array_tl pv)) out - | PTuple tl -> - loop2 tl out - in - let rec loop pmat = match pmat with - | (pv,out) :: pl -> - loop2 pv out; - loop pl - | [] -> - () - in - loop pmat; - DynArray.to_list r - -let default mctx pmat = - let r = DynArray.create () in - let add pv out = - DynArray.add r (pv,out) - in - let rec loop2 pv out = match pv.(0).p_def with - | PCon _ -> - () - | PAny | PVar _-> - add (array_tl pv) out - | POr(pat1,pat2) -> - let tl = array_tl pv in - let out2 = clone_out mctx out [pat2] pat2.p_pos in - loop2 (Array.append [|pat1|] tl) out; - loop2 (Array.append [|pat2|] tl) out2; - | PBind(_,pat) -> - loop2 (Array.append [|pat|] (array_tl pv)) out - | PTuple tl -> - loop2 tl out - in - let rec loop pmat = match pmat with - | (pv,out) :: pl -> - loop2 pv out; - loop pl; - | [] -> - () - in - loop pmat; - DynArray.to_list r - -let pick_column pmat = - let rec loop i pv = if Array.length pv = 0 then -1 else match pv.(0).p_def with - | PVar _ | PAny -> - loop (i + 1) (array_tl pv) - | PTuple pl -> - loop i pl - | _ -> - i - in - loop 0 (fst (List.hd pmat)) - -let swap_pmat_columns i pmat = - List.map (fun (pv,out) -> - let pv = match pv with [|{p_def = PTuple pt}|] -> pt | _ -> pv in - let tmp = pv.(i) in - Array.set pv i pv.(0); - Array.set pv 0 tmp; - pv,out - ) pmat - -let swap_columns i (row : 'a list) : 'a list = - match row with - | rh :: rt -> - let rec loop count acc col = match col with - | [] -> acc - | ch :: cl when i = count -> - ch :: (List.rev acc) @ [rh] @ cl - | ch :: cl -> - loop (count + 1) (ch :: acc) cl - in - loop 1 [] rt - | _ -> - [] - -let column_sigma mctx st pmat = - let acc = ref [] in - let bindings = ref [] in - let unguarded = Hashtbl.create 0 in - let add c g = - if not (List.exists (fun c2 -> unify_con c2 c) !acc) then acc := c :: !acc; - if not g then Hashtbl.replace unguarded c.c_def true; - in - let bind_st out st v = - if not (List.exists (fun ((v2,p),_) -> v2.v_id == (fst v).v_id) !bindings) then bindings := (v,st) :: !bindings - in - let rec loop pmat = match pmat with - | (pv,out) :: pr -> - let rec loop2 out = function - | PCon (c,_) -> - add c (out.o_guard <> None); - | POr(pat1,pat2) -> - let out2 = clone_out mctx out [pat2] pat2.p_pos in - loop2 out pat1.p_def; - loop2 out2 pat2.p_def; - | PVar v -> - bind_st out st v; - | PBind(v,pat) -> - bind_st out st v; - loop2 out pat.p_def - | PAny -> - () - | PTuple tl -> - loop2 out tl.(0).p_def - in - loop2 out pv.(0).p_def; - loop pr - | [] -> - () - in - loop pmat; - List.rev_map (fun con -> con,not (Hashtbl.mem unguarded con.c_def)) !acc,!bindings - -let all_ctors mctx st = - let h = ref PMap.empty in - let inf = match follow st.st_type with - | TAbstract({a_path = [],"Bool"},_) -> - h := PMap.add (CConst(TBool true)) Ast.null_pos !h; - h := PMap.add (CConst(TBool false)) Ast.null_pos !h; - false - | TInst({cl_path=[],"String"},_) - | TInst({cl_path=[],"Array"},_) - | TAbstract _ -> - true - | TEnum(en,pl) -> - PMap.iter (fun _ ef -> - let tc = monomorphs mctx.ctx.type_params st.st_type in - try unify_enum_field en pl ef tc; - h := PMap.add (CEnum(en,ef)) ef.ef_pos !h - with Unify_error _ -> - () - ) en.e_constrs; - false - | TInst ({cl_kind = KTypeParameter _},_) -> - error "Unapplied type parameter" st.st_pos - | TAnon a -> - (match !(a.a_status) with - | Statics c -> - true - | _ -> - false) - | TInst(_,_) -> - false - | _ -> - true - in - h,inf - -let rec collapse_pattern pl = match pl with - | pat :: [] -> - pat - | pat :: pl -> - let pat2 = collapse_pattern pl in - { - p_def = POr(pat,pat2); - p_pos = punion pat.p_pos pat2.p_pos; - p_type = pat.p_type - } - | [] -> - assert false - -let bind_remaining out pv stl = - let rec loop stl pv = - if Array.length pv = 0 then - [] - else - match stl,pv.(0).p_def with - | st :: stl,PAny -> - loop stl (array_tl pv) - | st :: stl,PVar v -> - (v,st) :: loop stl (array_tl pv) - | stl,PTuple pl -> - loop stl pl - | _ :: _,_-> - loop stl (array_tl pv) - | [],_ -> - [] - in - loop stl pv - -let rec compile mctx stl pmat = match pmat with - | [] -> - (match stl with - | st :: stl -> - let all,inf = all_ctors mctx st in - let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in - begin match pl,inf with - | _,true - | [],_ -> - raise (Not_exhaustive(any,st)) - | _ -> - raise (Not_exhaustive(collapse_pattern pl,st)) - end - | _ -> - assert false) - | ([|{p_def = PTuple pt}|],out) :: pl -> - compile mctx stl ((pt,out) :: pl) - | (pv,out) :: pl -> - let i = pick_column pmat in - if i = -1 then begin - Hashtbl.replace mctx.used_paths out.o_id true; - let bl = bind_remaining out pv stl in - let dt = if out.o_guard = None || match pl with [] -> true | _ -> false then - Out(out,None) - else - Out(out,Some (compile mctx stl pl)) - in - if bl = [] then dt else Bind(bl,dt) - end else if i > 0 then begin - let pmat = swap_pmat_columns i pmat in - let stls = swap_columns i stl in - compile mctx stls pmat - end else begin - let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in - let sigma,bl = column_sigma mctx st_head pmat in - let all,inf = all_ctors mctx st_head in - let cases = List.map (fun (c,g) -> - if not g then all := PMap.remove c.c_def !all; - let spec = spec mctx c pmat in - let hsubs = mk_subs st_head c in - let subs = hsubs @ st_tail in - let dt = compile mctx subs spec in - c,dt - ) sigma in - let def = default mctx pmat in - let dt = match def,cases with - | _,[{c_def = CFields _},dt] -> - dt - | _ when not inf && PMap.is_empty !all -> - Switch(st_head,cases) - | [],_ when inf && not mctx.need_val -> - Switch(st_head,cases) - | [],_ when inf -> - raise (Not_exhaustive(any,st_head)) - | [],_ -> - let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in - raise (Not_exhaustive(collapse_pattern pl,st_head)) - | def,[] -> - compile mctx st_tail def - | def,_ -> - let cdef = mk_con (CConst TNull) t_dynamic st_head.st_pos in - let cases = cases @ [cdef,compile mctx st_tail def] in - Switch(st_head,cases) - in - if bl = [] then dt else Bind(bl,dt) - end - -(* Conversion to typed AST *) - -let mk_const ctx p = function - | TString s -> mk (TConst (TString s)) ctx.com.basic.tstring p - | TInt i -> mk (TConst (TInt i)) ctx.com.basic.tint p - | TFloat f -> mk (TConst (TFloat f)) ctx.com.basic.tfloat p - | TBool b -> mk (TConst (TBool b)) ctx.com.basic.tbool p - | TNull -> mk (TConst TNull) (ctx.com.basic.tnull (mk_mono())) p - | _ -> error "Unsupported constant" p - -let rec st_to_unique_name ctx st = match st.st_def with - | SField(st,f) -> st_to_unique_name ctx st ^ "_f" ^ f - | SArray(st,i) -> st_to_unique_name ctx st ^ "_a" ^ (string_of_int i) - | SEnum(st,n,i) -> st_to_unique_name ctx st ^ "_e" ^ n ^ "_" ^ (string_of_int i) - | SVar v -> v.v_name - | STuple (st,_,_) -> st_to_unique_name ctx st - -let rec st_to_texpr mctx st = match st.st_def with - | SVar v -> mk (TLocal v) v.v_type st.st_pos - | SField (sts,f) -> - let e = st_to_texpr mctx sts in - let fa = try quick_field e.etype f with Not_found -> FDynamic f in - mk (TField(e,fa)) st.st_type st.st_pos - | SArray (sts,i) -> mk (TArray(st_to_texpr mctx sts,mk_const mctx.ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos - | STuple (st,_,_) -> st_to_texpr mctx st - | SEnum _ -> - let n = st_to_unique_name mctx st in - let v = try Hashtbl.find mctx.v_lookup n with Not_found -> - let v = alloc_var n st.st_type in - Hashtbl.add mctx.v_lookup n v; - v - in - mctx.ctx.locals <- PMap.add n v mctx.ctx.locals; - mk (TLocal v) v.v_type st.st_pos - -let rec st_eq st1 st2 = match st1.st_def,st2.st_def with - | STuple (st1,i1,_), STuple(st2,i2,_) -> i1 = i2 && st_eq st1 st2 - | SEnum(st1,_,i1), SEnum(st2,_,i2) -> i1 = i2 && st_eq st1 st2 - | SField(st1,f1),SField(st2,f2) -> f1 = f2 && st_eq st1 st2 - | SArray(st1,i1),SArray(st2,i2) -> i1 = i1 && st_eq st1 st2 - | SVar _, SVar _ -> true - | _ -> false - -let is_compatible out1 out2 = - out1.o_id = out2.o_id - && out1.o_guard = None - -let replace_locals mctx out e = - let replace v = - let rec loop vl = match vl with - | vl :: vll -> (try snd (List.find (fun ((v2,_),st) -> v2 == v) vl) with Not_found -> loop vll) - | [] -> raise Not_found - in - loop mctx.eval_stack - in - let rec loop e = match e.eexpr with - | TLocal v -> - (try - let st = replace v in - unify mctx.ctx e.etype st.st_type e.epos; - st_to_texpr mctx st - with Not_found -> - e) - | _ -> - Type.map_expr loop e - in - let e = loop e in - (* if not (Common.defined mctx.ctx.com Define.NoUnusedVarWarnings) then - Hashtbl.iter (fun _ (v,p) -> if (String.length v.v_name) > 0 && v.v_name.[0] <> '_' then mctx.ctx.com.warning "This variable is unused" p) all_subterms; *) - e - -let rec to_typed_ast mctx dt = - match dt with - | Goto _ -> - error "Not implemented yet" Ast.null_pos - | Out(out,dt) -> - replace_locals mctx out begin match out.o_guard,dt with - | Some eg,None -> - mk (TIf(eg,out.o_expr,None)) t_dynamic out.o_expr.epos - | Some eg,Some dt -> - let eelse = to_typed_ast mctx dt in - mk (TIf(eg,out.o_expr,Some eelse)) eelse.etype (punion out.o_expr.epos eelse.epos) - | _,None -> - out.o_expr - | _ -> assert false - end - | Bind (bl, dt) -> - List.iter (fun ((v,_),st) -> - let e = st_to_texpr mctx st in - begin match e.eexpr with - | TLocal v2 -> v2.v_name <- v.v_name - | _ -> () - end; - ) bl; - mctx.eval_stack <- bl :: mctx.eval_stack; - let e = to_typed_ast mctx dt in - mctx.eval_stack <- List.tl mctx.eval_stack; - e - | Switch(st,cases) -> - match follow st.st_type with - | TEnum(en,pl) | TAbstract({a_this = TEnum(en,_)},pl) -> to_enum_switch mctx en pl st cases - | TInst({cl_path = [],"Array"},[t]) -> to_array_switch mctx t st cases - | t -> to_value_switch mctx t st cases - -and group_cases mctx cases to_case = - let def = ref None in - let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with - | CConst TNull -> - let e = to_typed_ast mctx dt in - def := Some e; - (group,cases,dto) - | _ -> match dto with - | None -> ([to_case con],cases,Some dt) - | Some dt2 -> match dt,dt2 with - | Out(out1,_),Out(out2,_) when is_compatible out1 out2 -> - ((to_case con) :: group,cases,dto) - | _ -> - let e = to_typed_ast mctx dt2 in - ([to_case con],(List.rev group,e) :: cases, Some dt) - ) ([],[],None) cases in - let cases = List.rev (match group,dto with - | [],None -> - cases - | group,Some dt -> - let e = to_typed_ast mctx dt in - (List.rev group,e) :: cases - | _ -> - assert false - ) in - cases,def - -and to_enum_switch mctx en pl st cases = - let eval = st_to_texpr mctx st in - let to_case con = match con.c_def with - | CEnum(en,ef) -> en,ef - | _ -> - error ("Unexpected") con.c_pos - in - let type_case group dt p = - let group = List.rev group in - let en,ef = List.hd group in - let save = save_locals mctx.ctx in - let etf = follow (monomorphs en.e_types (monomorphs ef.ef_params ef.ef_type)) in - (* TODO: this is horrible !!! *) - let capture_vars = match dt with - | Out(out,None) -> - let vl = PMap.foldi (fun k v acc -> (k,v) :: acc) (List.fold_left (fun acc vl -> List.fold_left (fun acc (v,st) -> if PMap.mem v acc then acc else PMap.add v st acc) acc vl) PMap.empty mctx.eval_stack) [] in - Some vl - | _ -> - None - in - let vl = match etf with - | TFun(args,r) -> - let vl = ExtList.List.mapi (fun i (_,_,t) -> - let st = mk_st (SEnum(st,ef.ef_name,i)) t st.st_pos in - let mk_e () = Some (match (st_to_texpr mctx st).eexpr with TLocal v -> v | _ -> assert false) in - begin match capture_vars with - | Some cvl -> - let rec check st2 = st_eq st st2 || match st2.st_def with - | SEnum(st,_,_) | SArray(st,_) | STuple(st,_,_) | SField(st,_) -> check st - | SVar _ -> false - in - let rec loop cvl = match cvl with - | [] -> None - | (_,st2) :: cvl -> - if check st2 then mk_e() else loop cvl - in - loop cvl - | _ -> - mk_e() - end - ) args in - if List.exists (fun e -> e <> None) vl then (Some vl) else None - | _ -> None - in - let e = to_typed_ast mctx dt in - save(); - (List.map (fun (_,ef) -> ef.ef_index) group),vl,e - in - let def = ref None in - let group,cases,dto = List.fold_left (fun (group,cases,dto) (con,dt) -> match con.c_def with - | CConst TNull -> - let e = to_typed_ast mctx dt in - def := Some e; - (group,cases,dto) - | _ -> match dto with - | None -> ([to_case con],cases,Some dt) - | Some dt2 -> match dt,dt2 with - | Out(out1,_),Out(out2,_) when is_compatible out1 out2 -> - ((to_case con) :: group,cases,dto) - | _ -> - let g = type_case group dt2 con.c_pos in - ([to_case con],g :: cases, Some dt) - ) ([],[],None) cases in - let cases = List.rev (match group,dto with - | [],None -> - cases - | group,Some dt -> - let g = type_case group dt eval.epos in - g :: cases - | _ -> - assert false - ) in - mk (TMatch(eval,(en,pl),cases,!def)) mctx.out_type eval.epos - -and to_value_switch mctx t st cases = - let eval = st_to_texpr mctx st in - let to_case con = match con.c_def with - | CConst c -> - mk_const mctx.ctx con.c_pos c - | CType mt -> - Typer.type_module_type mctx.ctx mt None con.c_pos - | CExpr e -> - e - | _ -> - error ("Unexpected " ^ (s_con con)) con.c_pos - in - let cases,def = group_cases mctx cases to_case in - mk (TSwitch(eval,cases,!def)) mctx.out_type eval.epos - -and to_array_switch mctx t st cases = - let to_case con = match con.c_def with - | CArray i -> - mk_const mctx.ctx con.c_pos (TInt (Int32.of_int i)) - | _ -> - error ("Unexpected " ^ (s_con con)) con.c_pos - in - let cases,def = group_cases mctx cases to_case in - let eval = st_to_texpr mctx st in - let eval = mk (TField(eval,quick_field eval.etype "length")) mctx.ctx.com.basic.tint st.st_pos in - mk (TSwitch(eval,cases,!def)) mctx.out_type eval.epos - -(* Main *) - -let rec collapse_case el = match el with - | e :: [] -> - e - | e :: el -> - let e2 = collapse_case el in - EBinop(OpOr,e,e2),punion (pos e) (pos e2) - | [] -> - assert false - -let match_expr ctx e cases def with_type p = - let need_val,with_type,tmono = match with_type with - | NoValue -> false,NoValue,None - | WithType t | WithTypeResume t when (match follow t with TMono _ -> true | _ -> false) -> - (* we don't want to unify with each case individually, but instead at the end after unify_min *) - true,Value,Some with_type - | t -> true,t,None - in - (* turn default into case _ *) - let cases = match cases,def with - | [],None -> [] - | cases,Some def -> - let p = match def with - | None -> p - | Some (_,p) -> p - in - cases @ [[(EConst(Ident "_")),p],None,def] - | _ -> cases - in - (* type subject(s) *) - let evals = match fst e with - | EArrayDecl el | EParenthesis(EArrayDecl el,_) -> - List.map (fun e -> type_expr ctx e Value) el - | _ -> - let e = type_expr ctx e Value in - begin match follow e.etype with - | TEnum(en,_) when PMap.is_empty en.e_constrs || Meta.has Meta.FakeEnum en.e_meta -> - raise Exit - | _ -> - () - end; - [e] - in - let var_inits = ref [] in - let a = List.length evals in - (* turn subjects to subterms and handle variable initialization where necessary *) - let stl = ExtList.List.mapi (fun i e -> - let rec loop e = match e.eexpr with - | TField (ef,s) when (match s with FEnum _ -> false | _ -> true) -> - mk_st (SField(loop ef,field_name s)) e.etype e.epos - | TParenthesis e -> - loop e - | TLocal v -> - mk_st (SVar v) e.etype e.epos - | _ -> - let v = gen_local ctx e.etype in - var_inits := (v, Some e) :: !var_inits; - mk_st (SVar v) e.etype e.epos - in - let st = loop e in - if a = 1 then st else mk_st (STuple(st,i,a)) st.st_type st.st_pos - ) evals in - let tl = List.map (fun st -> st.st_type) stl in - (* create matcher context *) - let mctx = { - ctx = ctx; - stl = stl; - need_val = need_val; - v_lookup = Hashtbl.create 0; - outcomes = PMap.empty; - out_type = mk_mono(); - toplevel_or = false; - used_paths = Hashtbl.create 0; - eval_stack = []; - } in - (* flatten cases *) - let cases = List.map (fun (el,eg,e) -> - List.iter (fun e -> match fst e with EBinop(OpOr,_,_) -> mctx.toplevel_or <- true; | _ -> ()) el; - collapse_case el,eg,e - ) cases in - let add_pattern_locals (pat,locals) = - PMap.iter (fun n (v,p) -> ctx.locals <- PMap.add n v ctx.locals) locals; - pat - in - (* evaluate patterns *) - let pl = ExtList.List.mapi (fun i (ep,eg,e) -> - let save = save_locals ctx in - (* type case patterns *) - let pl,restore,with_type = try (match tl with - | [t] -> - (* context type parameters are turned into monomorphs until the pattern has been typed *) - let monos = List.map (fun _ -> mk_mono()) ctx.type_params in - let t = apply_params ctx.type_params monos t in - let pl = [add_pattern_locals (to_pattern ctx ep t)] in - let restore = match with_type with - | Value | NoValue -> [] - | WithType _ | WithTypeResume _ -> - PMap.fold (fun v acc -> - (* apply context monomorphs to locals and replace them back after typing the case body *) - let t = v.v_type in - v.v_type <- apply_params ctx.type_params monos v.v_type; - (fun () -> v.v_type <- t) :: acc - ) ctx.locals [] - in - (* turn any still unknown types back into type parameters *) - List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ctx.type_params; - pl,restore,(match with_type with - | WithType t -> WithType (apply_params ctx.type_params monos t) - | WithTypeResume t -> WithTypeResume (apply_params ctx.type_params monos t) - | _ -> with_type); - | tl -> - let t = monomorphs ctx.type_params (tfun tl fake_tuple_type) in - [add_pattern_locals (to_pattern ctx ep t)],[],with_type) - with Unrecognized_pattern (e,p) -> - error "Case expression must be a constant value or a pattern, not an arbitrary expression" p - in - (* type case body *) - let e = match e with - | None -> mk (TBlock []) ctx.com.basic.tvoid (pos ep) - | Some e -> - let e = type_expr ctx e with_type in - match with_type with - | WithType t -> - unify ctx e.etype t e.epos; - Codegen.Abstract.check_cast ctx t e e.epos; - | WithTypeResume t -> - (try unify_raise ctx e.etype t e.epos with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p))); - Codegen.Abstract.check_cast ctx t e e.epos - | _ -> e - in - (* type case guard *) - let eg = match eg with - | None -> None - | Some e -> - let eg = type_expr ctx e (WithType ctx.com.basic.tbool) in - unify ctx eg.etype ctx.com.basic.tbool eg.epos; - Some eg - in - List.iter (fun f -> f()) restore; - save(); - let out = mk_out mctx i e eg pl (pos ep) in - Array.of_list pl,out - ) cases in - let check_unused () = - let unused p = - display_error ctx "This pattern is unused" p; - let old_error = ctx.on_error in - ctx.on_error <- (fun ctx s p -> ctx.on_error <- old_error; raise Exit); - let check_expr e p = - try begin match fst e with - | EConst(Ident ("null" | "true" | "false")) -> () - | EConst(Ident _) -> - ignore (type_expr ctx e Value); - display_error ctx "Case expression must be a constant value or a pattern, not an arbitrary expression" (pos e) - | _ -> () - end with Exit -> () - in - let rec loop prev cl = match cl with - | (_,Some _,_) :: cl -> loop prev cl - | ((e,p2),_,_) :: cl -> - if p2.pmin >= p.pmin then check_expr prev p else loop (e,p2) cl - | [] -> - check_expr prev p - in - (match cases with (e,_,_) :: cl -> loop e cl | [] -> assert false); - ctx.on_error <- old_error; - in - PMap.iter (fun _ out -> if not (Hashtbl.mem mctx.used_paths out.o_id) then begin - if out.o_pos == p then display_error ctx "The default pattern is unused" p - else unused out.o_pos; - if mctx.toplevel_or then begin match evals with - | [{etype = t}] when (match follow t with TAbstract({a_path=[],"Int"},[]) -> true | _ -> false) -> - display_error ctx "Note: Int | Int is an or-pattern now" p; - | _ -> () - end; - end) mctx.outcomes; - in - begin try - (* compile decision tree *) - let dt = compile mctx stl pl in - (* check for unused patterns *) - check_unused(); - (* determine type of switch statement *) - let t = if not need_val then - mk_mono() - else match with_type with - | WithType t | WithTypeResume t -> t - | _ -> try Typer.unify_min_raise ctx (List.rev_map (fun (_,out) -> out.o_expr) (List.rev pl)) with Error (Unify l,p) -> error (error_msg (Unify l)) p - in - (* unify with expected type if necessary *) - begin match tmono with - | None -> () - | Some (WithType t2) -> unify ctx t2 t p - | Some (WithTypeResume t2) -> (try unify_raise ctx t2 t p with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p))) - | _ -> assert false - end; - (* generate typed AST from decision tree *) - let e = to_typed_ast mctx dt in - let e = { e with epos = p; etype = t} in - if !var_inits = [] then - e - else begin - mk (TBlock [ - mk (TVars (List.rev !var_inits)) t_dynamic e.epos; - e; - ]) t e.epos - end - with Not_exhaustive(pat,st) -> - let rec s_st_r top pre st v = match st.st_def with - | SVar v1 -> - if not pre then v else begin try - let e = match List.assoc v1 !var_inits with Some e -> e | None -> assert false in - (Type.s_expr_pretty "" (Type.s_type (print_context())) e) ^ v - with Not_found -> - v1.v_name ^ v - end - | STuple(st,i,a) -> - let r = a - i - 1 in - Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v)) - | SArray(st,i) -> - s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v)) - | SField(st,f) -> - s_st_r false true st (Printf.sprintf ".%s%s" f (if top then " = " ^ v else v)) - | SEnum(st,n,i) -> - let ef = match follow st.st_type with - | TEnum(en,_) -> PMap.find n en.e_constrs - | _ -> raise Not_found - in - let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in - s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v)) - in - error ("Unmatched patterns: " ^ (s_st_r true false st (s_pat pat))) st.st_pos - end; -;; -match_expr_ref := match_expr; +(* + * Copyright (C)2005-2013 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. + *) + +open Ast +open Common +open Type +open Typecore + +type pvar = tvar * pos + +type con_def = + | CEnum of tenum * tenum_field + | CConst of tconstant + | CAny + | CType of module_type + | CArray of int + | CFields of int * (string * tclass_field) list + | CExpr of texpr + +and con = { + c_def : con_def; + c_type : t; + c_pos : pos; +} + +and st_def = + | SVar of tvar + | SField of st * tclass_field + | SEnum of st * tenum_field * int + | SArray of st * int + | STuple of st * int * int + +and st = { + st_def : st_def; + st_type : t; + st_pos : pos; +} + +and dt = + | Switch of st * (con * dt) list + | Bind of ((tvar * pos) * st) list * dt + | Goto of int + | Expr of int + | Guard of int * dt * dt option + +(* Pattern *) + +type pat_def = + | PAny + | PVar of pvar + | PCon of con * pat list + | POr of pat * pat + | PBind of pvar * pat + | PTuple of pat array + +and pat = { + p_def : pat_def; + p_type : t; + p_pos : pos; +} + +type out = { + mutable o_pos : pos; + o_id : int; + o_catch_all : bool; + mutable o_num_paths : int; +} + +type pat_vec = pat array * out +type pat_matrix = pat_vec list + +(* Context *) + +type pattern_ctx = { + mutable pc_locals : (string, pvar) PMap.t; + mutable pc_sub_vars : (string, pvar) PMap.t option; + mutable pc_reify : bool; + mutable pc_is_complex : bool; +} + +type matcher = { + ctx : typer; + need_val : bool; + dt_lut : dt DynArray.t; + dt_cache : (dt,int) Hashtbl.t; + mutable dt_count : int; + mutable outcomes : out list; + mutable toplevel_or : bool; + mutable has_extractor : bool; + mutable expr_map : (int,texpr * texpr option) PMap.t; + mutable is_exhaustive : bool; +} + +type type_finiteness = + | Infinite (* type has inifite constructors (e.g. Int, String) *) + | CompileTimeFinite (* type is considered finite only at compile-time but has inifite possible run-time values (enum abstracts) *) + | RunTimeFinite (* type is truly finite (Bool, enums) *) + +exception Not_exhaustive of pat * st +exception Unrecognized_pattern of Ast.expr + +let arity con = match con.c_def with + | CEnum (_,{ef_type = TFun(args,_)}) -> List.length args + | CEnum _ -> 0 + | CConst _ -> 0 + | CType mt -> 0 + | CArray i -> i + | CFields (i,_) -> i + | CExpr _ -> 0 + | CAny -> 0 + +let mk_st def t p = { + st_def = def; + st_type = t; + st_pos = p; +} + +let mk_out mctx id e eg is_catch_all p = + let out = { + o_pos = p; + o_id = id; + o_catch_all = is_catch_all; + o_num_paths = 0; + } in + mctx.outcomes <- out :: mctx.outcomes; + mctx.expr_map <- PMap.add id (e,eg) mctx.expr_map; + out + +let clone_out mctx out p = + let out = {out with o_pos = p; } in + mctx.outcomes <- out :: mctx.outcomes; + out + +let get_guard mctx id = + snd (PMap.find id mctx.expr_map) + +let get_expr mctx id = + fst (PMap.find id mctx.expr_map) + +let mk_pat pdef t p = { + p_def = pdef; + p_type = t; + p_pos = p; +} + +let mk_con cdef t p = { + c_def = cdef; + c_type = t; + c_pos = p; +} + +let mk_con_pat cdef pl t p = mk_pat (PCon(mk_con cdef t p,pl)) t p + +let mk_any t p = mk_pat PAny t p + +let any = mk_any t_dynamic Ast.null_pos + +let fake_tuple_type = TInst(mk_class null_module ([],"-Tuple") null_pos, []) + +let mk_type_pat ctx mt t p = + let rec loop = function + | TClassDecl _ -> "Class" + | TEnumDecl _ -> "Enum" + | TAbstractDecl a when Meta.has Meta.RuntimeValue a.a_meta -> "Class" + | TTypeDecl t -> + begin match follow (monomorphs t.t_params t.t_type) with + | TInst(c,_) -> loop (TClassDecl c) + | TEnum(en,_) -> loop (TEnumDecl en) + | TAbstract(a,_) -> loop (TAbstractDecl a) + | _ -> error "Cannot use this type as a value" p + end + | _ -> error "Cannot use this type as a value" p + in + let tcl = Typeload.load_instance ctx {tname=loop mt;tpackage=[];tsub=None;tparams=[]} p true in + let t2 = match tcl with TAbstract(a,_) -> TAbstract(a,[mk_mono()]) | _ -> assert false in + unify ctx t t2 p; + mk_con_pat (CType mt) [] t2 p + +let mk_subs st con = + let map = match follow st.st_type with + | TInst(c,pl) -> apply_params c.cl_params pl + | TEnum(en,pl) -> apply_params en.e_params pl + | TAbstract(a,pl) -> apply_params a.a_params pl + | _ -> fun t -> t + in + match con.c_def with + | CFields (_,fl) -> List.map (fun (s,cf) -> mk_st (SField(st,cf)) (map cf.cf_type) st.st_pos) fl + | CEnum (en,({ef_type = TFun _} as ef)) -> + let rec loop t = match follow t with + | TEnum(_,pl) -> pl + | TAbstract({a_path = [],"EnumValue"},[]) -> [] + | TAbstract(a,pl) -> loop (Abstract.get_underlying_type a pl) + | _ -> [] + in + let pl = loop con.c_type in + begin match apply_params en.e_params pl (monomorphs ef.ef_params ef.ef_type) with + | TFun(args,r) -> + ExtList.List.mapi (fun i (_,_,t) -> + mk_st (SEnum(st,ef,i)) t st.st_pos + ) args + | _ -> + assert false + end + | CArray 0 -> [] + | CArray i -> + let t = match follow con.c_type with TInst({cl_path=[],"Array"},[t]) -> t | TDynamic _ as t -> t | _ -> assert false in + ExtList.List.init i (fun i -> mk_st (SArray(st,i)) t st.st_pos) + | CEnum _ | CConst _ | CType _ | CExpr _ | CAny -> + [] + +let get_tuple_params t = match t with + | TFun(tl,tr) when tr == fake_tuple_type -> Some tl + | _ -> None + +(* Printing *) + +let s_type = s_type (print_context()) + +let rec s_con con = match con.c_def with + | CEnum(_,ef) -> ef.ef_name + | CAny -> "_" + | CConst c -> s_const c + | CType mt -> s_type_path (t_path mt) + | CArray i -> "[" ^(string_of_int i) ^ "]" + | CFields (_,fl) -> String.concat "," (List.map (fun (s,_) -> s) fl) + | CExpr e -> s_expr s_type e + +let rec s_pat pat = match pat.p_def with + | PVar (v,_) -> v.v_name + | PCon (c,[]) -> s_con c + | PCon (c,pl) -> s_con c ^ "(" ^ (String.concat "," (List.map s_pat pl)) ^ ")" + | POr (pat1,pat2) -> s_pat pat1 ^ " | " ^ s_pat pat2 + | PAny -> "_" + | PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat + | PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")" + +let rec s_pat_vec pl = + String.concat " " (Array.to_list (Array.map s_pat pl)) + +let rec s_pat_matrix pmat = + String.concat "\n" (List.map (fun (pl,out) -> (s_pat_vec pl) ^ "->" ^ "") pmat) + +let st_args l r v = + (if l > 0 then (String.concat "," (ExtList.List.make l "_")) ^ "," else "") + ^ v ^ + (if r > 0 then "," ^ (String.concat "," (ExtList.List.make r "_")) else "") + +let rec s_st st = + (match st.st_def with + | SVar v -> v.v_name + | SEnum (st,ef,i) -> s_st st ^ "." ^ ef.ef_name ^ "." ^ (string_of_int i) + | SArray (st,i) -> s_st st ^ "[" ^ (string_of_int i) ^ "]" + | STuple (st,i,a) -> "(" ^ (st_args i (a - i - 1) (s_st st)) ^ ")" + | SField (st,cf) -> s_st st ^ "." ^ cf.cf_name) + +(* Pattern parsing *) + +let unify_enum_field en pl ef t = + let t2 = match follow ef.ef_type with + | TFun(_,r) -> r + | t2 -> t2 + in + let t2 = (apply_params en.e_params pl (monomorphs ef.ef_params t2)) in + Type.unify t2 t + +let unify ctx a b p = + try unify_raise ctx a b p with Error (Unify l,p) -> error (error_msg (Unify l)) p + +let rec is_value_type = function + | TMono r -> + (match !r with None -> false | Some t -> is_value_type t) + | TType (t,tl) -> + is_value_type (apply_params t.t_params tl t.t_type) + | TInst({cl_path=[],"String"},[]) -> + true + | TAbstract _ -> + true + | _ -> + false + +(* Determines if a type allows null-matching. This is similar to is_nullable, but it infers Null on monomorphs *) +let rec matches_null ctx t = match t with + | TMono r -> + (match !r with None -> r := Some (ctx.t.tnull (mk_mono())); true | Some t -> matches_null ctx t) + | TType ({ t_path = ([],"Null") },[_]) -> + true + | TLazy f -> + matches_null ctx (!f()) + | TType (t,tl) -> + matches_null ctx (apply_params t.t_params tl t.t_type) + | TFun _ -> + false + | TAbstract (a,_) -> not (Meta.has Meta.NotNull a.a_meta) + | _ -> + true + +let to_pattern ctx e t = + let perror p = error "Unrecognized pattern" p in + let verror n p = error ("Variable " ^ n ^ " must appear exactly once in each sub-pattern") p in + let mk_var tctx s t p = + let v = match tctx.pc_sub_vars with + | Some vmap -> fst (try PMap.find s vmap with Not_found -> verror s p) + | None -> alloc_var s t + in + unify ctx t v.v_type p; + if PMap.mem s tctx.pc_locals then verror s p; + tctx.pc_locals <- PMap.add s (v,p) tctx.pc_locals; + v + in + let check_texpr_pattern e t p = + let ec = match Optimizer.make_constant_expression ctx ~concat_strings:true e with Some e -> e | None -> e in + match ec.eexpr with + | TField (_,FEnum (en,ef)) -> + begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end; + begin try + unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t; + with Unify_error l -> + error (error_msg (Unify l)) p + end; + mk_con_pat (CEnum(en,ef)) [] t p + | TConst c | TCast({eexpr = TConst c},None) -> + begin try unify_raise ctx ec.etype t ec.epos with Error (Unify _,_) -> raise Not_found end; + unify ctx ec.etype t p; + mk_con_pat (CConst c) [] t p + | TTypeExpr mt -> + mk_type_pat ctx mt t p + | _ -> + raise Not_found + in + let rec loop pctx e t = + let p = pos e in + match fst e with + | ECheckType(e, CTPath({tpackage=["haxe";"macro"]; tname="Expr"})) -> + let old = pctx.pc_reify in + pctx.pc_reify <- true; + let e = loop pctx e t in + pctx.pc_reify <- old; + e + | EParenthesis e -> + loop pctx e t + | ECast(e1,None) -> + loop pctx e1 t + | EConst(Ident "null") -> + if not (matches_null ctx t) then error ("Null-patterns are only allowed on nullable types (found " ^ (s_type t) ^ ")") p; + mk_con_pat (CConst TNull) [] t p + | EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as c) -> + let e = Codegen.type_constant ctx.com c p in + unify ctx e.etype t p; + let c = match e.eexpr with TConst c -> c | _ -> assert false in + mk_con_pat (CConst c) [] t p + | EMeta((Meta.Macro,[],_),(ECall (e1,args),_)) -> + let path, field, args = Codegen.get_macro_path ctx e1 args p in + begin match ctx.g.do_macro ctx MExpr path field args p with + | Some e -> loop pctx e t + | None -> error "Macro failure" p + end + | EField _ -> + let e = type_expr ctx e (WithType t) in + let e = match Optimizer.make_constant_expression ctx ~concat_strings:true e with Some e -> e | None -> e in + (match e.eexpr with + | TConst c | TCast({eexpr = TConst c},None) -> + mk_con_pat (CConst c) [] t p + | TTypeExpr mt -> + mk_type_pat ctx mt t p + | TField(_, FStatic(_,cf)) when is_value_type cf.cf_type -> + ignore (follow cf.cf_type); + begin match cf.cf_expr with + | Some e -> + (try check_texpr_pattern e t p with Not_found -> mk_con_pat (CExpr e) [] cf.cf_type p) + | None -> + mk_con_pat (CExpr e) [] cf.cf_type p + end + | TField(_, FEnum(en,ef)) -> + begin try + unify_enum_field en (List.map (fun _ -> mk_mono()) en.e_params) ef t + with Unify_error l -> + error (error_msg (Unify l)) p + end; + mk_con_pat (CEnum(en,ef)) [] t p + | _ -> error "Constant expression expected" p) + | ECall(ec,el) -> + let ec = type_expr ctx ec (WithType t) in + (match follow ec.etype with + | TEnum(en,pl) + | TFun(_,TEnum(en,pl)) -> + let ef = match ec.eexpr with + | TField (_,FEnum (_,f)) -> f + | _ -> error ("Expected constructor for enum " ^ (s_type_path en.e_path)) p + in + let monos = List.map (fun _ -> mk_mono()) ef.ef_params in + let tl,r = match apply_params en.e_params pl (apply_params ef.ef_params monos ef.ef_type) with + | TFun(args,r) -> + unify ctx r t p; + List.map (fun (n,_,t) -> t) args,r + | _ -> error "No arguments expected" p + in + let rec loop2 i el tl = match el,tl with + | (EConst(Ident "_"),pany) :: [], t :: tl -> + let pat = mk_pat PAny t_dynamic pany in + (ExtList.List.make ((List.length tl) + 1) pat) + | e :: el, t :: tl -> + let pat = loop pctx e t in + pat :: loop2 (i + 1) el tl + | e :: _, [] -> + error "Too many arguments" (pos e); + | [],_ :: _ -> + error "Not enough arguments" p; + | [],[] -> + [] + in + let el = loop2 0 el tl in + List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ef.ef_params; + pctx.pc_is_complex <- true; + mk_con_pat (CEnum(en,ef)) el r p + | _ -> perror p) + | EConst(Ident "_") -> + begin match get_tuple_params t with + | Some tl -> + let pl = List.map (fun (_,_,t) -> mk_any t p) tl in + mk_pat (PTuple (Array.of_list pl)) t_dynamic p + | None -> + mk_any t p + end + | EConst(Ident s) -> + begin try + let ec = match follow t with + | TEnum(en,pl) -> + let ef = try + PMap.find s en.e_constrs + with Not_found when not (is_lower_ident s) -> + error (string_error s en.e_names ("Expected constructor for enum " ^ (s_type_path en.e_path))) p + in + (match ef.ef_type with + | TFun (args,_) -> + let msg = Printf.sprintf "Enum constructor %s.%s requires parameters %s" + (s_type_path en.e_path) + ef.ef_name + (String.concat ", " (List.map (fun (n,_,t) -> n ^ ":" ^ (s_type t)) args)) + in + error msg p + | _ -> ()); + let et = mk (TTypeExpr (TEnumDecl en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics en) }) p in + mk (TField (et,FEnum (en,ef))) (apply_params en.e_params pl ef.ef_type) p + | TAbstract({a_impl = Some c} as a,_) when Meta.has Meta.Enum a.a_meta -> + let cf = PMap.find s c.cl_statics in + Type.unify (follow cf.cf_type) t; + let e = begin match cf.cf_expr with + | Some ({eexpr = TConst c | TCast({eexpr = TConst c},None)} as e) -> e + | _ -> raise Not_found + end in + e + | _ -> + let old = ctx.untyped in + ctx.untyped <- true; + let e = try type_expr ctx e (WithType t) with _ -> ctx.untyped <- old; raise Not_found in + ctx.untyped <- old; + e + in + check_texpr_pattern ec t p + with Not_found -> + begin match get_tuple_params t with + | Some tl -> + let s = String.concat "," (List.map (fun (_,_,t) -> s_type t) tl) in + error ("Pattern should be tuple [" ^ s ^ "]") p + | None -> + if not (is_lower_ident s) && s.[0] <> '`' then error "Capture variables must be lower-case" p; + let v = mk_var pctx s t p in + mk_pat (PVar (v,p)) v.v_type p + end + end + | (EObjectDecl fl) -> + let is_matchable cf = match cf.cf_kind with Method _ -> false | _ -> true in + let is_valid_field_name fields co n p = + try + let cf = PMap.find n fields in + begin match co with + | Some c when not (Typer.can_access ctx c cf false) -> error ("Cannot match against private field " ^ n) p + | _ -> () + end + with Not_found -> + error ((s_type t) ^ " has no field " ^ n ^ " that can be matched against") p; + in + pctx.pc_is_complex <- true; + let loop_fields fields = + let sl,pl,i = PMap.foldi (fun n cf (sl,pl,i) -> + if not (is_matchable cf) then + sl,pl,i + else + let pat = try + if pctx.pc_reify && cf.cf_name = "pos" then raise Not_found; + loop pctx (List.assoc cf.cf_name fl) cf.cf_type + with Not_found -> + (mk_any cf.cf_type p) + in + (n,cf) :: sl,pat :: pl,i + 1 + ) fields ([],[],0) in + mk_con_pat (CFields(i,sl)) pl t p + in + let fields = match follow t with + | TAnon {a_fields = fields} -> + fields + | TInst(c,tl) -> + let fields = ref PMap.empty in + let rec loop c tl = + begin match c.cl_super with + | Some (csup,tlsup) -> loop csup (List.map (apply_params c.cl_params tl) tlsup) + | None -> () + end; + PMap.iter (fun n cf -> fields := PMap.add n {cf with cf_type = apply_params c.cl_params tl (monomorphs cf.cf_params cf.cf_type)} !fields) c.cl_fields + in + loop c tl; + !fields + | TAbstract({a_impl = Some c} as a,tl) -> + let fields = List.fold_left (fun acc cf -> + if Meta.has Meta.Impl cf.cf_meta then + PMap.add cf.cf_name cf acc + else acc + ) PMap.empty c.cl_ordered_statics in + PMap.map (fun cf -> {cf with cf_type = apply_params a.a_params tl (monomorphs cf.cf_params cf.cf_type)}) fields + | _ -> + error ((s_type t) ^ " cannot be matched against a structure") p + in + List.iter (fun (n,(_,p)) -> is_valid_field_name fields None n p) fl; + loop_fields fields + | EArrayDecl [] -> + mk_con_pat (CArray 0) [] t p + | EArrayDecl el -> + pctx.pc_is_complex <- true; + begin match follow t with + | TInst({cl_path=[],"Array"},[t2]) | (TDynamic _ as t2) -> + let pl = ExtList.List.mapi (fun i e -> + loop pctx e t2 + ) el in + mk_con_pat (CArray (List.length el)) pl t p + | TFun(tl,tr) when tr == fake_tuple_type -> + let pl = try + List.map2 (fun e (_,_,t) -> loop pctx e t) el tl + with Invalid_argument _ -> + error ("Invalid number of arguments: expected " ^ (string_of_int (List.length tl)) ^ ", found " ^ (string_of_int (List.length el))) p + in + mk_pat (PTuple (Array.of_list pl)) t p + | _ -> + error ((s_type t) ^ " should be Array") p + end + | EBinop(OpAssign,(EConst(Ident s),p2),e1) -> + let v = mk_var pctx s t p in + let pat1 = loop pctx e1 t in + mk_pat (PBind((v,p),pat1)) t p2 + | EBinop(OpOr,(EBinop(OpOr,e1,e2),p2),e3) -> + loop pctx (EBinop(OpOr,e1,(EBinop(OpOr,e2,e3),p2)),p) t + | EBinop(OpOr,e1,e2) -> + let old = pctx.pc_locals in + let pat1 = loop pctx e1 t in + begin match pat1.p_def with + | PAny | PVar _ -> + display_error ctx "This pattern is unused" (pos e2); + pat1 + | _ -> + let pctx2 = { + pc_sub_vars = Some pctx.pc_locals; + pc_locals = old; + pc_reify = pctx.pc_reify; + pc_is_complex = pctx.pc_is_complex; + } in + let pat2 = loop pctx2 e2 t in + pctx.pc_is_complex <- pctx2.pc_is_complex; + PMap.iter (fun s (_,p) -> if not (PMap.mem s pctx2.pc_locals) then verror s p) pctx.pc_locals; + mk_pat (POr(pat1,pat2)) pat2.p_type (punion pat1.p_pos pat2.p_pos); + end + | _ -> + raise (Unrecognized_pattern e) + in + let pctx = { + pc_locals = PMap.empty; + pc_sub_vars = None; + pc_reify = false; + pc_is_complex = false; + } in + let x = loop pctx e t in + x, pctx.pc_locals, pctx.pc_is_complex + +let get_pattern_locals ctx e t = + try + let _,locals,_ = to_pattern ctx e t in + PMap.foldi (fun n v acc -> PMap.add n v acc) locals PMap.empty + with Unrecognized_pattern _ -> + PMap.empty + +(* Match compilation *) + +let expr_eq e1 e2 = e1 == e2 || match e1.eexpr,e2.eexpr with + | TConst ct1,TConst ct2 -> + ct1 = ct2 + | TField(_,FStatic(c1,cf1)),TField(_,FStatic(c2,cf2)) -> + c1 == c2 && cf1.cf_name = cf2.cf_name + | _ -> + false + +let unify_con con1 con2 = match con1.c_def,con2.c_def with + | CExpr e1, CExpr e2 -> + expr_eq e1 e2 + | CConst c1,CConst c2 -> + c1 = c2 + | CEnum(e1,ef1),CEnum(e2,ef2) -> + e1 == e2 && ef1.ef_name = ef2.ef_name + | CFields (i1,fl1),CFields (i2,fl2) -> + (try + List.iter (fun (s,_) -> if not (List.mem_assoc s fl1) then raise Not_found) fl2; + true + with Not_found -> + false) + | CType mt1,CType mt2 -> + t_path mt1 = t_path mt2 + | CArray a1, CArray a2 -> + a1 == a2 + | CAny, CAny -> + true + | _ -> + false + +let array_tl arr = Array.sub arr 1 (Array.length arr - 1) + +let spec mctx con pmat = + let a = arity con in + let r = DynArray.create () in + let add pv out = + DynArray.add r (pv,out) + in + let rec loop2 pv out = match pv.(0).p_def with + | PCon(c2,pl) when unify_con c2 con -> + add (Array.append (Array.of_list pl) (array_tl pv)) out + | PCon(c2,pl) -> + () + | PAny | PVar _-> + add (Array.append (Array.make a (mk_any (pv.(0).p_type) (pv.(0).p_pos))) (array_tl pv)) out + | PBind(_,pat) -> + loop2 (Array.append [|pat|] (array_tl pv)) out + | PTuple tl -> + loop2 tl out + | POr _ -> + assert false + in + let rec loop pmat = match pmat with + | (pv,out) :: pl -> + loop2 pv out; + loop pl + | [] -> + () + in + loop pmat; + DynArray.to_list r + +let default mctx pmat = + let r = DynArray.create () in + let add pv out = + DynArray.add r (pv,out) + in + let rec loop2 pv out = match pv.(0).p_def with + | PCon _ -> + () + | PAny | PVar _-> + add (array_tl pv) out + | PBind(_,pat) -> + loop2 (Array.append [|pat|] (array_tl pv)) out + | PTuple tl -> + loop2 tl out + | POr _ -> + assert false + in + let rec loop pmat = match pmat with + | (pv,out) :: pl -> + loop2 pv out; + loop pl; + | [] -> + () + in + loop pmat; + DynArray.to_list r + +let pick_column pmat = + let rec loop i pv = if Array.length pv = 0 then -1 else match pv.(0).p_def with + | PVar _ | PAny -> + loop (i + 1) (array_tl pv) + | PTuple pl -> + loop i pl + | _ -> + i + in + loop 0 (fst (List.hd pmat)) + +let swap_pmat_columns i pmat = + List.map (fun (pv,out) -> + let pv = match pv with [|{p_def = PTuple pt}|] -> pt | _ -> pv in + let tmp = pv.(i) in + Array.set pv i pv.(0); + Array.set pv 0 tmp; + pv,out + ) pmat + +let swap_columns i (row : 'a list) : 'a list = + match row with + | rh :: rt -> + let rec loop count acc col = match col with + | [] -> acc + | ch :: cl when i = count -> + ch :: (List.rev acc) @ [rh] @ cl + | ch :: cl -> + loop (count + 1) (ch :: acc) cl + in + loop 1 [] rt + | _ -> + [] + +let expand_or mctx (pmat : pat_matrix) = + let rec loop pat = match pat.p_def with + | POr(pat1,pat2) -> + let pat1 = loop pat1 in + let pat2 = loop pat2 in + pat1 @ pat2 + | PBind(v,pat1) -> + let pat1 = loop pat1 in + List.map (fun pat1 -> + {pat with p_def = PBind(v,pat1)} + ) pat1 + | PTuple(pl) -> + let pat1 = loop pl.(0) in + List.map (fun pat1 -> + let a1 = Array.copy pl in + a1.(0) <- pat1; + {pat with p_def = PTuple a1} + ) pat1 + | _ -> + [pat] + in + let rec loop2 pmat = match pmat with + | (pv,out) :: pmat -> + let pat = loop pv.(0) in + let pat' = ExtList.List.mapi (fun i pat -> + (* TODO: This should really be active, but currently causes problems with or-patterns in + tuples (issue #2610). We will disable this for the 3.1.0 release, which means issue + #2508 is open again. *) + (* let out = if i = 0 then out else clone_out mctx out pat.p_pos in *) + let a1 = Array.copy pv in + a1.(0) <- pat; + a1,out + ) pat in + pat' @ (loop2 pmat) + | [] -> + [] + in + loop2 pmat + +let column_sigma mctx st pmat = + let acc = ref [] in + let bindings = ref [] in + let unguarded = Hashtbl.create 0 in + let add c g = + if not (List.exists (fun c2 -> unify_con c2 c) !acc) then acc := c :: !acc; + if not g then Hashtbl.replace unguarded c.c_def true; + in + let bind_st out st v = + if not (List.exists (fun ((v2,p),_) -> v2.v_id == (fst v).v_id) !bindings) then bindings := (v,st) :: !bindings + in + let rec loop pmat = match pmat with + | (pv,out) :: pr -> + let rec loop2 out = function + | PCon (c,_) -> + add c ((get_guard mctx out.o_id) <> None); + | PVar v -> + bind_st out st v; + | PBind(v,pat) -> + bind_st out st v; + loop2 out pat.p_def + | PAny -> + () + | PTuple tl -> + loop2 out tl.(0).p_def + | POr _ -> + assert false + in + loop2 out pv.(0).p_def; + loop pr + | [] -> + () + in + loop pmat; + List.rev_map (fun con -> con,not (Hashtbl.mem unguarded con.c_def)) !acc,!bindings + +let rec all_ctors mctx t = + let h = ref PMap.empty in + if is_explicit_null t then h := PMap.add (CConst TNull) Ast.null_pos !h; + match follow t with + | TAbstract({a_path = [],"Bool"},_) -> + h := PMap.add (CConst(TBool true)) Ast.null_pos !h; + h := PMap.add (CConst(TBool false)) Ast.null_pos !h; + h,RunTimeFinite + | TAbstract({a_impl = Some c} as a,pl) when Meta.has Meta.Enum a.a_meta -> + List.iter (fun cf -> + ignore(follow cf.cf_type); + if Meta.has Meta.Impl cf.cf_meta then match cf.cf_expr with + | Some {eexpr = TConst c | TCast ({eexpr = TConst c},None)} -> h := PMap.add (CConst c) cf.cf_pos !h + | _ -> () + ) c.cl_ordered_statics; + h,CompileTimeFinite + | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> all_ctors mctx (Abstract.get_underlying_type a pl) + | TInst({cl_path=[],"String"},_) + | TInst({cl_path=[],"Array"},_) -> + h,Infinite + | TEnum(en,pl) -> + PMap.iter (fun _ ef -> + let tc = monomorphs mctx.ctx.type_params t in + try unify_enum_field en pl ef tc; + h := PMap.add (CEnum(en,ef)) ef.ef_pos !h + with Unify_error _ -> + () + ) en.e_constrs; + h,RunTimeFinite + | TAnon a -> + h,CompileTimeFinite + | TInst(_,_) -> + h,CompileTimeFinite + | _ -> + h,Infinite + +let rec collapse_pattern pl = match pl with + | pat :: [] -> + pat + | pat :: pl -> + let pat2 = collapse_pattern pl in + mk_pat (POr(pat,pat2)) pat.p_type (punion pat.p_pos pat2.p_pos) + | [] -> + assert false + +let bind_remaining out pv stl = + let rec loop stl pv = + if Array.length pv = 0 then + [] + else + match stl,pv.(0).p_def with + | st :: stl,PAny -> + loop stl (array_tl pv) + | st :: stl,PVar v -> + (v,st) :: loop stl (array_tl pv) + | stl,PTuple pl -> + loop stl pl + | _ :: _,_-> + loop stl (array_tl pv) + | [],_ -> + [] + in + loop stl pv + +let get_cache mctx dt = + match dt with Goto _ -> dt | _ -> + try + Goto (Hashtbl.find mctx.dt_cache dt) + with Not_found -> + Hashtbl.replace mctx.dt_cache dt mctx.dt_count; + mctx.dt_count <- mctx.dt_count + 1; + DynArray.add mctx.dt_lut dt; + dt + +let rec compile mctx stl pmat toplevel = + let guard id dt1 dt2 = get_cache mctx (Guard(id,dt1,dt2)) in + let expr id = get_cache mctx (Expr id) in + let bind bl dt = get_cache mctx (Bind(bl,dt)) in + let switch st cl = get_cache mctx (Switch(st,cl)) in + get_cache mctx (match pmat with + | [] -> + (match stl with + | st :: stl -> + let all,inf = all_ctors mctx st.st_type in + let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in + begin match pl,inf with + | _,Infinite + | [],_ -> + raise (Not_exhaustive(any,st)) + | _ -> + raise (Not_exhaustive(collapse_pattern pl,st)) + end + | _ -> + (* This can happen in cases a value is required and all default cases are guarded (issue #3150). + Not a particularly elegant solution, may want to revisit this later. *) + raise Exit) + | ([|{p_def = PTuple pt}|],out) :: pl -> + compile mctx stl ((pt,out) :: pl) toplevel + | (pv,out) :: pl -> + let i = pick_column pmat in + if i = -1 then begin + out.o_num_paths <- out.o_num_paths + 1; + let bl = bind_remaining out pv stl in + let dt = match (get_guard mctx out.o_id) with + | None -> + expr out.o_id + | Some _ -> + let dt = match pl,mctx.need_val with + | [],false -> + None + | _ -> + Some (compile mctx stl pl false) + in + guard out.o_id (expr out.o_id) dt + in + (if bl = [] then dt else bind bl dt) + end else if i > 0 then begin + let pmat = swap_pmat_columns i pmat in + let stls = swap_columns i stl in + compile mctx stls pmat toplevel + end else begin + let st_head,st_tail = match stl with st :: stl -> st,stl | _ -> assert false in + let pmat = expand_or mctx pmat in + let sigma,bl = column_sigma mctx st_head pmat in + let all,inf = all_ctors mctx pv.(0).p_type in + let cases = List.map (fun (c,g) -> + if not g then all := PMap.remove c.c_def !all; + let spec = spec mctx c pmat in + let hsubs = mk_subs st_head c in + let subs = hsubs @ st_tail in + let dt = compile mctx subs spec false in + c,dt + ) sigma in + let def = default mctx pmat in + let dt = match def,cases with + | _ when inf = RunTimeFinite && PMap.is_empty !all -> + switch st_head cases + | [],_ when inf = CompileTimeFinite && PMap.is_empty !all -> + switch st_head cases + | [],_ when inf = Infinite && not mctx.need_val && toplevel -> + (* ignore exhaustiveness, but mark context so we do not generate @:exhaustive metadata *) + mctx.is_exhaustive <- false; + switch st_head cases + | [],_ when inf = Infinite -> + raise (Not_exhaustive(any,st_head)) + | [],_ -> + let pl = PMap.foldi (fun cd p acc -> (mk_con_pat cd [] t_dynamic p) :: acc) !all [] in + (* toplevel null can be omitted because the French dig runtime errors (issue #3054) *) + if toplevel && (match pl with + | [{p_def = PCon ({c_def = (CConst TNull)},_)}] -> true + | _ -> false) then + switch st_head cases + else + raise (Not_exhaustive(collapse_pattern pl,st_head)) + | def,[] -> + compile mctx st_tail def false + | def,_ -> + let cdef = mk_con CAny t_dynamic st_head.st_pos in + let def = try + compile mctx st_tail def false + with Exit -> + raise (Not_exhaustive(any,st_head)) + in + let cases = cases @ [cdef,def] in + switch st_head cases + in + if bl = [] then dt else bind bl dt + end) + +let rec collapse_case el = match el with + | e :: [] -> + e + | e :: el -> + let e2 = collapse_case el in + EBinop(OpOr,e,e2),punion (pos e) (pos e2) + | [] -> + assert false + +let mk_const ctx p = function + | TString s -> mk (TConst (TString s)) ctx.com.basic.tstring p + | TInt i -> mk (TConst (TInt i)) ctx.com.basic.tint p + | TFloat f -> mk (TConst (TFloat f)) ctx.com.basic.tfloat p + | TBool b -> mk (TConst (TBool b)) ctx.com.basic.tbool p + | TNull -> mk (TConst TNull) (ctx.com.basic.tnull (mk_mono())) p + | _ -> error "Unsupported constant" p + +let rec convert_st ctx st = match st.st_def with + | SVar v -> mk (TLocal v) v.v_type st.st_pos + | SField (sts,cf) -> + let e = convert_st ctx sts in + Typer.acc_get ctx (Typer.type_field ctx e cf.cf_name st.st_pos Typer.MGet) st.st_pos + | SArray (sts,i) -> mk (TArray(convert_st ctx sts,mk_const ctx st.st_pos (TInt (Int32.of_int i)))) st.st_type st.st_pos + | STuple (st,_,_) -> convert_st ctx st + | SEnum (sts,ef,i) -> mk (TEnumParameter(convert_st ctx sts, ef, i)) st.st_type st.st_pos + +let convert_con ctx con = match con.c_def with + | CConst c -> mk_const ctx con.c_pos c + | CType mt -> mk (TTypeExpr mt) t_dynamic con.c_pos + | CExpr e -> e + | CEnum(e,ef) -> mk_const ctx con.c_pos (TInt (Int32.of_int ef.ef_index)) + | CArray i -> mk_const ctx con.c_pos (TInt (Int32.of_int i)) + | CAny | CFields _ -> assert false + +let convert_switch mctx st cases loop = + let ctx = mctx.ctx in + let e_st = convert_st ctx st in + let p = e_st.epos in + let mk_index_call () = + let ttype = match follow (Typeload.load_instance ctx { tpackage = ["std"]; tname="Type"; tparams=[]; tsub = None} p true) with TInst(c,_) -> c | t -> assert false in + let cf = PMap.find "enumIndex" ttype.cl_statics in + let ec = (!type_module_type_ref) ctx (TClassDecl ttype) None p in + let ef = mk (TField(ec, FStatic(ttype,cf))) (tfun [e_st.etype] ctx.t.tint) p in + let e = make_call ctx ef [e_st] ctx.t.tint p in + e + in + let wrap_exhaustive e = + if mctx.is_exhaustive then + mk (TMeta((Meta.Exhaustive,[],e.epos),e)) e.etype e.epos + else + e + in + let e = match follow st.st_type with + | TEnum(_) -> + wrap_exhaustive (mk_index_call()) + | TAbstract(a,pl) when (match Abstract.get_underlying_type a pl with TEnum(_) -> true | _ -> false) -> + wrap_exhaustive (mk_index_call()) + | TInst({cl_path = [],"Array"},_) as t -> + mk (TField (e_st,quick_field t "length")) ctx.t.tint p + | TAbstract(a,_) when Meta.has Meta.Enum a.a_meta -> + wrap_exhaustive (e_st) + | TAbstract({a_path = [],"Bool"},_) -> + wrap_exhaustive (e_st) + | _ -> + let rec loop cases = match cases with + | [] -> e_st + | (con,_) :: cases -> + begin match con.c_def with + | CEnum _ -> mk_index_call() + | CArray _ -> mk (TField (e_st,FDynamic "length")) ctx.t.tint p + | _ -> loop cases + end + in + loop cases + in + let null = ref None in + let def = ref None in + let cases = List.filter (fun (con,dt) -> + match con.c_def with + | CConst TNull -> + null := Some (loop dt); + false + | CAny -> + def := Some (loop dt); + false + | _ -> + true + ) cases in + let dt = match cases with + | [{c_def = CFields _},dt] -> loop dt + | _ -> DTSwitch(e, List.map (fun (c,dt) -> convert_con ctx c, loop dt) cases, !def) + in + match !null with + | None when is_explicit_null st.st_type && (!def <> None || not mctx.need_val) -> + let econd = mk (TBinop(OpNotEq,e_st,mk (TConst TNull) st.st_type p)) ctx.t.tbool p in + DTGuard(econd,dt,!def) + | None -> + dt + | Some dt_null -> + let t = match ctx.t.tnull ctx.t.tint with + | TType(t,_) ->TType(t,[st.st_type]) + | t -> t + in + let e_null = mk (TConst TNull) t p in + let econd = mk (TBinop(OpEq,e_st, e_null)) ctx.t.tbool p in + DTGuard(econd,dt_null,Some dt) + +(* Decision tree compilation *) + +let transform_extractors eval cases p = + let efail = (EThrow(EConst(Ident "false"),p)),p in + let cfail = [(EConst (Ident "_"),p)],None,Some efail in + let has_extractor = ref false in + let rec loop cases = match cases with + | (epat,eg,e) :: cases -> + let ex = ref [] in + let exc = ref 0 in + let rec find_ex in_or e = match fst e with + | EBinop(OpArrow,_,_) when in_or -> + error "Extractors in or patterns are not allowed" (pos e) + | EBinop(OpArrow, e1, e2) -> + let ec = EConst (Ident ("__ex" ^ string_of_int (!exc))),snd e in + let rec map_left e = match fst e with + | EConst(Ident "_") -> ec + | _ -> Ast.map_expr map_left e + in + let ecall = map_left e1 in + ex := (ecall,e2) :: !ex; + incr exc; + has_extractor := true; + ec + | EBinop(OpOr,e1,e2) -> + let e1 = find_ex true e1 in + let e2 = find_ex true e2 in + (EBinop(OpOr,e1,e2)),(pos e) + | _ -> + Ast.map_expr (find_ex in_or) e + in + let p = match e with None -> p | Some e -> pos e in + let epat = match epat with + | [epat] -> [find_ex false epat] + | _ -> List.map (find_ex true) epat + in + let cases = loop cases in + if !exc = 0 then + (epat,eg,e) :: cases + else begin + let esubjects = EArrayDecl (List.map fst !ex),p in + let case1 = [EArrayDecl (List.map snd !ex),p],eg,e in + let cases2 = match cases with + | [] -> [case1] + | [[EConst (Ident "_"),_],_,e] -> case1 :: [[(EConst (Ident "_"),p)],None,e] + | _ -> + case1 :: [[(EConst (Ident "_"),p)],None,Some (ESwitch(eval,cases,None),p)] + in + let eswitch = (ESwitch(esubjects,cases2,None)),p in + let case = epat,None,Some eswitch in + begin match epat with + | [EConst(Ident _),_] -> + [case;cfail] + | _ -> + case :: cases + end + end + | [] -> + [] + in + let cases = loop cases in + cases,!has_extractor + +let extractor_depth = ref 0 + +let match_expr ctx e cases def with_type p = + let need_val,with_type,tmono = match with_type with + | NoValue -> false,NoValue,None + | WithType t | WithTypeResume t when (match follow t with TMono _ -> true | _ -> false) -> + (* we don't want to unify with each case individually, but instead at the end after unify_min *) + true,Value,Some with_type + | t -> true,t,None + in + (* turn default into case _ *) + let cases = match cases,def with + | [],None -> [] + | cases,Some def -> + let p = match def with + | None -> p + | Some (_,p) -> p + in + cases @ [[(EConst(Ident "_")),p],None,def] + | _ -> cases + in + let cases,has_extractor = transform_extractors e cases p in + (* type subject(s) *) + let array_match = ref false in + let evals = match fst e with + | EArrayDecl el | EParenthesis(EArrayDecl el,_) when (match el with [(EFor _ | EWhile _),_] -> false | _ -> true) -> + array_match := true; + List.map (fun e -> type_expr ctx e Value) el + | _ -> + let e = type_expr ctx e Value in + begin match follow e.etype with + (* TODO: get rid of the XmlType check *) + | TEnum(en,_) when (match en.e_path with (["neko" | "php" | "flash" | "cpp"],"XmlType") -> true | _ -> Meta.has Meta.FakeEnum en.e_meta) -> + raise Exit + | TAbstract({a_path=[],("Int" | "Float" | "Bool")},_) | TInst({cl_path = [],"String"},_) when (Common.defined ctx.com Common.Define.NoPatternMatching) -> + raise Exit; + | _ -> + () + end; + [e] + in + let var_inits = ref [] in + let save = save_locals ctx in + let a = List.length evals in + (* turn subjects to subterms and handle variable initialization where necessary *) + let stl = ExtList.List.mapi (fun i e -> + let rec loop e = match e.eexpr with + | TParenthesis e | TMeta(_,e) -> + loop e + | TLocal v -> + mk_st (SVar v) e.etype e.epos + | _ -> + let v = gen_local ctx e.etype in + var_inits := (v, Some e) :: !var_inits; + ctx.locals <- PMap.add v.v_name v ctx.locals; + mk_st (SVar v) e.etype e.epos + in + let st = loop e in + if a = 1 then st else mk_st (STuple(st,i,a)) st.st_type st.st_pos + ) evals in + let tl = List.map (fun st -> st.st_type) stl in + (* create matcher context *) + let mctx = { + ctx = ctx; + need_val = need_val; + outcomes = []; + toplevel_or = false; + dt_lut = DynArray.create (); + dt_cache = Hashtbl.create 0; + dt_count = 0; + has_extractor = has_extractor; + expr_map = PMap.empty; + is_exhaustive = true; + } in + (* flatten cases *) + let cases = List.map (fun (el,eg,e) -> + List.iter (fun e -> match fst e with EBinop(OpOr,_,_) -> mctx.toplevel_or <- true; | _ -> ()) el; + match el with + | [] -> + let p = match e with None -> p | Some e -> pos e in + error "case without a pattern is not allowed" p + | _ -> + collapse_case el,eg,e + ) cases in + let is_complex = ref false in + if mctx.has_extractor then incr extractor_depth; + let add_pattern_locals (pat,locals,complex) = + PMap.iter (fun n (v,p) -> ctx.locals <- PMap.add n v ctx.locals) locals; + if complex then is_complex := true; + pat + in + (* evaluate patterns *) + let pl = ExtList.List.mapi (fun i (ep,eg,e) -> + let save = save_locals ctx in + (* type case patterns *) + let pl,restore,with_type = + try + (* context type parameters are turned into monomorphs until the pattern has been typed *) + let monos = List.map (fun _ -> mk_mono()) ctx.type_params in + let t = match tl with [t] when not !array_match -> t | tl -> tfun tl fake_tuple_type in + let t = apply_params ctx.type_params monos t in + let pl = [add_pattern_locals (to_pattern ctx ep t)] in + let old_ret = ctx.ret in + ctx.ret <- apply_params ctx.type_params monos ctx.ret; + let restore = PMap.fold (fun v acc -> + (* apply context monomorphs to locals and replace them back after typing the case body *) + let t = v.v_type in + v.v_type <- apply_params ctx.type_params monos v.v_type; + (fun () -> v.v_type <- t) :: acc + ) ctx.locals [fun() -> ctx.ret <- old_ret] in + (* turn any still unknown types back to type parameters *) + List.iter2 (fun m (_,t) -> match follow m with TMono _ -> Type.unify m t | _ -> ()) monos ctx.type_params; + pl,restore,(match with_type with + | WithType t -> WithType (apply_params ctx.type_params monos t) + | WithTypeResume t -> WithTypeResume (apply_params ctx.type_params monos t) + | _ -> with_type); + with Unrecognized_pattern (e,p) -> + error "Case expression must be a constant value or a pattern, not an arbitrary expression" p + in + let is_catch_all = match pl with + | [{p_def = PAny | PVar _}] -> true + | _ -> false + in + (* type case body *) + let e = match e with + | None -> + mk (TBlock []) ctx.com.basic.tvoid (pos ep) + | Some e -> + type_expr ctx e with_type + in + let e = match with_type with + | WithType t -> + Codegen.AbstractCast.cast_or_unify ctx t e e.epos; + | WithTypeResume t -> + (try Codegen.AbstractCast.cast_or_unify_raise ctx t e e.epos with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p))); + | _ -> e + in + (* type case guard *) + let eg = match eg with + | None -> None + | Some e -> + let eg = type_expr ctx e (WithType ctx.com.basic.tbool) in + unify ctx eg.etype ctx.com.basic.tbool eg.epos; + Some eg + in + List.iter (fun f -> f()) restore; + save(); + let out = mk_out mctx i e eg is_catch_all (pos ep) in + Array.of_list pl,out + ) cases in + let check_unused () = + let unused p = + display_error ctx "This pattern is unused" p; + let old_error = ctx.on_error in + ctx.on_error <- (fun ctx s p -> ctx.on_error <- old_error; raise Exit); + let check_expr e p = + try begin match fst e with + | EConst(Ident ("null" | "true" | "false")) -> () + | EConst(Ident _) -> + ignore (type_expr ctx e Value); + display_error ctx "Case expression must be a constant value or a pattern, not an arbitrary expression" (pos e) + | _ -> () + end with Exit -> () + in + let rec loop prev cl = match cl with + | (_,Some _,_) :: cl -> loop prev cl + | ((e,p2),_,_) :: cl -> + if p2.pmin >= p.pmin then check_expr prev p else loop (e,p2) cl + | [] -> + check_expr prev p + in + (match cases with (e,_,_) :: cl -> loop e cl | [] -> assert false); + ctx.on_error <- old_error; + in + let had_catch_all = ref false in + List.iter (fun out -> + if out.o_catch_all && not !had_catch_all then + had_catch_all := true + else if out.o_num_paths = 0 then begin + unused out.o_pos; + if mctx.toplevel_or then begin match evals with + | [{etype = t}] when (match follow t with TAbstract({a_path=[],"Int"},[]) -> true | _ -> false) -> + display_error ctx "Note: Int | Int is an or-pattern now" p; + | _ -> () + end; + end + ) (List.rev mctx.outcomes); + in + let dt = try + (* compile decision tree *) + compile mctx stl pl true + with Not_exhaustive(pat,st) -> + let rec s_st_r top pre st v = match st.st_def with + | SVar v1 -> + if not pre then v else begin try + let e = match List.assoc v1 !var_inits with Some e -> e | None -> assert false in + (Type.s_expr_pretty "" (Type.s_type (print_context())) e) ^ v + with Not_found -> + v1.v_name ^ v + end + | STuple(st,i,a) -> + let r = a - i - 1 in + Printf.sprintf "[%s]" (st_args i r (s_st_r top false st v)) + | SArray(st,i) -> + s_st_r false true st (Printf.sprintf "[%i]%s" i (if top then " = " ^ v else v)) + | SField({st_def = SVar v1},cf) when v1.v_name.[0] = '`' -> + cf.cf_name ^ (if top then " = " ^ v else v) + | SField(st,cf) -> + s_st_r false true st (Printf.sprintf ".%s%s" cf.cf_name (if top then " = " ^ v else v)) + | SEnum(st,ef,i) -> + let len = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> 0 in + s_st_r false false st (Printf.sprintf "%s(%s)" ef.ef_name (st_args i (len - 1 - i) v)) + in + let pat = match follow st.st_type with + | TAbstract({a_impl = Some cl} as a,_) when Meta.has Meta.Enum a.a_meta -> + let rec s_pat pat = match pat.p_def with + | PCon ({c_def = CConst c},[]) when c <> TNull -> + let cf = List.find (fun cf -> + match cf.cf_expr with + | Some ({eexpr = TConst c2 | TCast({eexpr = TConst c2},None)}) -> c = c2 + | _ -> false + ) cl.cl_ordered_statics in + cf.cf_name + | PVar (v,_) -> v.v_name + | PCon (c,[]) -> s_con c + | PCon (c,pl) -> s_con c ^ "(" ^ (String.concat "," (List.map s_pat pl)) ^ ")" + | POr (pat1,pat2) -> s_pat pat1 ^ " | " ^ s_pat pat2 + | PAny -> "_" + | PBind((v,_),pat) -> v.v_name ^ "=" ^ s_pat pat + | PTuple pl -> "(" ^ (String.concat " " (Array.to_list (Array.map s_pat pl))) ^ ")" + in + s_pat pat + | _ -> + s_pat pat + in + let msg = "Unmatched patterns: " ^ (s_st_r true false st pat) in + if !extractor_depth > 0 then begin + display_error ctx msg st.st_pos; + error "Note: Patterns with extractors may require a default pattern" st.st_pos; + end else + error msg st.st_pos + in + save(); + (* check for unused patterns *) + if !extractor_depth = 0 then check_unused(); + if mctx.has_extractor then decr extractor_depth; + (* determine type of switch statement *) + let t = if not need_val then + mk_mono() + else match with_type with + | WithType t | WithTypeResume t -> t + | _ -> try Typer.unify_min_raise ctx (List.rev_map (fun (_,out) -> get_expr mctx out.o_id) (List.rev pl)) with Error (Unify l,p) -> error (error_msg (Unify l)) p + in + (* unify with expected type if necessary *) + begin match tmono with + | None -> () + | Some (WithType t2) -> unify ctx t2 t p + | Some (WithTypeResume t2) -> (try unify_raise ctx t2 t p with Error (Unify l,p) -> raise (Typer.WithTypeError (l,p))) + | _ -> assert false + end; + (* count usage *) + let usage = Array.make (DynArray.length mctx.dt_lut) 0 in + (* we always want to keep the first part *) + let first = (match dt with Goto i -> i | _ -> Hashtbl.find mctx.dt_cache dt) in + Array.set usage first 2; + let rec loop dt = match dt with + | Goto i -> Array.set usage i ((Array.get usage i) + 1) + | Switch(st,cl) -> List.iter (fun (_,dt) -> loop dt) cl + | Bind(bl,dt) -> loop dt + | Expr e -> () + | Guard(e,dt1,dt2) -> + loop dt1; + match dt2 with None -> () | Some dt -> (loop dt) + in + DynArray.iter loop mctx.dt_lut; + (* filter parts that will be inlined and keep a map to them*) + let map = Array.make (DynArray.length mctx.dt_lut) 0 in + let lut = DynArray.create() in + let rec loop i c = + if c < DynArray.length mctx.dt_lut then begin + let i' = if usage.(c) > 1 then begin + DynArray.add lut (DynArray.get mctx.dt_lut c); + i + 1 + end else i in + Array.set map c i; + loop i' (c + 1) + end + in + loop 0 0; + (* reindex *) + let rec loop dt = match dt with + | Goto i -> if usage.(i) > 1 then DTGoto (map.(i)) else loop (DynArray.get mctx.dt_lut i) + | Switch(st,cl) -> convert_switch mctx st cl loop + | Bind(bl,dt) -> DTBind(List.map (fun (v,st) -> v,convert_st ctx st) bl,loop dt) + | Expr id -> DTExpr (get_expr mctx id) + | Guard(id,dt1,dt2) -> DTGuard((match get_guard mctx id with Some e -> e | None -> assert false),loop dt1, match dt2 with None -> None | Some dt -> Some (loop dt)) + in + let lut = DynArray.map loop lut in + { + dt_first = map.(first); + dt_dt_lookup = DynArray.to_array lut; + dt_type = t; + dt_var_init = List.rev !var_inits; + dt_is_complex = !is_complex; + } +;; +match_expr_ref := match_expr; get_pattern_locals_ref := get_pattern_locals \ No newline at end of file diff --git a/optimizer.ml b/optimizer.ml index c498ae562bec422e84fd02f1107ba4e2097bad50..5cdd33362e6f59874cea6c23fe17ca7b536597b0 100644 --- a/optimizer.ml +++ b/optimizer.ml @@ -28,25 +28,46 @@ open Typecore (* ---------------------------------------------------------------------- *) (* API OPTIMIZATIONS *) +(* tells if an expression causes side effects. This does not account for potential null accesses (fields/arrays/ops) *) let has_side_effect e = let rec loop e = match e.eexpr with - | TConst _ | TLocal _ | TField (_,FEnum _) | TTypeExpr _ | TFunction _ -> () - | TMatch _ | TNew _ | TCall _ | TField _ | TArray _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit + | TConst _ | TLocal _ | TTypeExpr _ | TFunction _ -> () + | TCall ({ eexpr = TField(_,FStatic({ cl_path = ([],"Std") },{ cf_name = "string" })) },args) -> Type.iter loop e + | TNew _ | TCall _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit | TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit - | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TWhile _ | TFor _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TVars _ | TBlock _ | TObjectDecl _ -> Type.iter loop e + | TArray _ | TEnumParameter _ | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _ | TFor _ + | TField _ | TIf _ | TTry _ | TSwitch _ | TArrayDecl _ | TBlock _ | TObjectDecl _ | TVar _ -> Type.iter loop e in try loop e; false with Exit -> true +let mk_untyped_call name p params = + { + eexpr = TCall({ eexpr = TLocal(alloc_unbound_var name t_dynamic); etype = t_dynamic; epos = p }, params); + etype = t_dynamic; + epos = p; + } + let api_inline ctx c field params p = match c.cl_path, field, params with - | ([],"Type"),"enumIndex",[{ eexpr = TField (_,FEnum (en,f)) }] -> - Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p) + | ([],"Type"),"enumIndex",[{ eexpr = TField (_,FEnum (en,f)) }] -> (match ctx.com.platform with + | Cs when en.e_extern && not (Meta.has Meta.HxGen en.e_meta) -> + (* We don't want to optimize enums from external sources; as they might change unexpectedly *) + (* and since native C# enums don't have the concept of index - they have rather a value, *) + (* which can't be mapped to a native API - this kind of substitution is dangerous *) + None + | _ -> + Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)) | ([],"Type"),"enumIndex",[{ eexpr = TCall({ eexpr = TField (_,FEnum (en,f)) },pl) }] when List.for_all (fun e -> not (has_side_effect e)) pl -> - Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p) + (match ctx.com.platform with + | Cs when en.e_extern && not (Meta.has Meta.HxGen en.e_meta) -> + (* see comment above *) + None + | _ -> + Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)) | ([],"Std"),"int",[{ eexpr = TConst (TInt _) } as e] -> Some { e with epos = p } | ([],"String"),"fromCharCode",[{ eexpr = TConst (TInt i) }] when i > 0l && i < 128l -> @@ -61,6 +82,77 @@ let api_inline ctx c field params p = Some { eexpr = TConst (TString (if b then "true" else "false")); epos = p; etype = ctx.t.tstring } | _ -> None) + | ([],"Std"),"string",[{ eexpr = TIf (_,{ eexpr = TConst (TString _)},Some { eexpr = TConst (TString _) }) } as e] -> + Some e + | ([],"Std"),"string",[{ eexpr = TLocal _ | TField({ eexpr = TLocal _ },_) } as v] when ctx.com.platform = Js || ctx.com.platform = Flash -> + let pos = v.epos in + let stringv() = + let to_str = mk (TBinop (Ast.OpAdd, mk (TConst (TString "")) ctx.t.tstring pos, v)) ctx.t.tstring pos in + if ctx.com.platform = Js || is_nullable v.etype then + let chk_null = mk (TBinop (Ast.OpEq, v, mk (TConst TNull) t_dynamic pos)) ctx.t.tbool pos in + mk (TIf (chk_null, mk (TConst (TString "null")) ctx.t.tstring pos, Some to_str)) ctx.t.tstring pos + else + to_str + in + (match follow v.etype with + | TInst ({ cl_path = [],"String" }, []) -> + Some (stringv()) + | TAbstract ({ a_path = [],"Float" }, []) -> + Some (stringv()) + | TAbstract ({ a_path = [],"Int" }, []) -> + Some (stringv()) + | TAbstract ({ a_path = [],"UInt" }, []) -> + Some (stringv()) + | TAbstract ({ a_path = [],"Bool" }, []) -> + Some (stringv()) + | _ -> + None) + | ([],"Std"),"is",[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js -> + let mk_local ctx n t pos = + mk (TLocal (try + PMap.find n ctx.locals + with _ -> + let v = add_local ctx n t in + v.v_meta <- [Meta.Unbound,[],p]; + v + )) t pos in + + let tstring = ctx.com.basic.tstring in + let tbool = ctx.com.basic.tbool in + let tint = ctx.com.basic.tint in + + let is_trivial e = + match e.eexpr with + | TConst _ | TLocal _ -> true + | _ -> false + in + + let typeof t = + let tof = mk_local ctx "__typeof__" (tfun [o.etype] tstring) p in + let tof = mk (TCall (tof, [o])) tstring p in + mk (TBinop (Ast.OpEq, tof, (mk (TConst (TString t)) tstring p))) tbool p + in + + (match 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") + | TTypeExpr (TAbstractDecl ({ a_path = [],"Float" })) -> Some (typeof "number") + | TTypeExpr (TAbstractDecl ({ a_path = [],"Int" })) when is_trivial o -> + (* generate (o|0) === o check *) + let teq = mk_local ctx "__strict_eq__" (tfun [tint; tint] tbool) p in + let lhs = mk (TBinop (Ast.OpOr, o, mk (TConst (TInt Int32.zero)) tint p)) tint p in + Some (mk (TCall (teq, [lhs; o])) tbool p) + | TTypeExpr (TClassDecl ({ cl_path = [],"Array" })) -> + (* generate (o instanceof Array) && o.__enum__ == null check *) + let iof = mk_local ctx "__instanceof__" (tfun [o.etype;t.etype] tbool) p in + let iof = mk (TCall (iof, [o; t])) tbool p in + let enum = mk (TField (o, FDynamic "__enum__")) (mk_mono()) p in + let null = mk (TConst TNull) (mk_mono()) p in + let not_enum = mk (TBinop (Ast.OpEq, enum, null)) tbool p in + Some (mk (TBinop (Ast.OpBoolAnd, iof, not_enum)) tbool p) + | _ -> + None) | ([],"Std"),"int",[{ eexpr = TConst (TFloat f) }] -> let f = float_of_string f in (match classify_float f with @@ -70,6 +162,37 @@ let api_inline ctx c field params p = None (* out range, keep platform-specific behavior *) | _ -> Some { eexpr = TConst (TInt (Int32.of_float f)); etype = ctx.t.tint; epos = p }) + | (["cs"],"Lib"),("fixed" | "checked" | "unsafe"),[e] -> + Some (mk_untyped_call ("__" ^ field ^ "__") p [e]) + | (["cs"],"Lib"),("lock"),[obj;block] -> + Some (mk_untyped_call ("__lock__") p [obj;mk_block block]) + | (["java"],"Lib"),("lock"),[obj;block] -> + Some (mk_untyped_call ("__lock__") p [obj;mk_block block]) + | (["cs" | "java"],"Lib"),("nativeArray"),[{ eexpr = TArrayDecl args } as edecl; _] + | (["haxe";"ds";"_Vector"],"Vector_Impl_"),("fromArrayCopy"),[{ eexpr = TArrayDecl args } as edecl] -> (try + let platf = match ctx.com.platform with + | Cs -> "cs" + | Java -> "java" + | _ -> raise Exit + in + let mpath = if field = "fromArrayCopy" then + (["haxe";"ds"],"Vector") + else + ([platf],"NativeArray") + in + + let m = ctx.g.do_load_module ctx mpath null_pos in + let main = List.find (function | TClassDecl _ | TAbstractDecl _ -> true | _ -> false) m.m_types in + let t = match follow edecl.etype, main with + | TInst({ cl_path = [],"Array" }, [t]), TClassDecl(cl) -> + TInst(cl,[t]) + | TInst({ cl_path = [],"Array" }, [t]), TAbstractDecl(a) -> + TAbstract(a,[t]) + | _ -> assert false + in + Some ({ (mk_untyped_call "__array__" p args) with etype = t }) + with | Exit -> + None) | _ -> None @@ -82,20 +205,21 @@ type in_local = { mutable i_captured : bool; mutable i_write : bool; mutable i_read : int; + mutable i_force_temp : bool; } let inline_default_config cf t = (* type substitution on both class and function type parameters *) let rec get_params c pl = match c.cl_super with - | None -> c.cl_types, pl + | None -> c.cl_params, pl | Some (csup,spl) -> - let spl = (match apply_params c.cl_types pl (TInst (csup,spl)) with + let spl = (match apply_params c.cl_params pl (TInst (csup,spl)) with | TInst (_,pl) -> pl | _ -> assert false ) in let ct, cpl = get_params csup spl in - c.cl_types @ ct, pl @ cpl + c.cl_params @ ct, pl @ cpl in let tparams = (match follow t with | TInst (c,pl) -> get_params c pl @@ -106,7 +230,7 @@ let inline_default_config cf t = let tparams = fst tparams @ cf.cf_params in tparams <> [], apply_params tparams tmonos -let rec type_inline ctx cf f ethis params tret config p force = +let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=false) force = (* perform some specific optimization before we inline the call since it's not possible to detect at final optimization time *) try let cl = (match follow ethis.etype with @@ -125,28 +249,39 @@ let rec type_inline ctx cf f ethis params tret config p force = try Hashtbl.find locals v.v_id with Not_found -> + let v' = alloc_var v.v_name v.v_type in + if Meta.has Meta.Unbound v.v_meta then v'.v_meta <- [Meta.Unbound,[],p]; let i = { i_var = v; - i_subst = alloc_var v.v_name v.v_type; + i_subst = v'; i_captured = false; i_write = false; + i_force_temp = false; i_read = 0; } in + i.i_subst.v_meta <- v.v_meta; Hashtbl.add locals v.v_id i; Hashtbl.add locals i.i_subst.v_id i; i in + let in_local_fun = ref false in let read_local v = - try + let l = try Hashtbl.find locals v.v_id with Not_found -> + (* make sure to duplicate unbound inline variable to prevent dependency leak when unifying monomorph *) + if has_meta Meta.Unbound v.v_meta then local v else { i_var = v; i_subst = v; i_captured = false; i_write = false; + i_force_temp = false; i_read = 0; } + in + if !in_local_fun then l.i_captured <- true; + l in (* use default values for null/unset arguments *) let rec loop pl al first = @@ -157,7 +292,7 @@ let rec type_inline ctx cf f ethis params tret config p force = if we pass a Null var to an inlined method that needs a T. we need to force a local var to be created on some platforms. *) - if ctx.com.config.pf_static && not (is_nullable v.v_type) && is_null e.etype then (local v).i_write <- true; + if ctx.com.config.pf_static && not (is_nullable v.v_type) && is_null e.etype then (local v).i_force_temp <- true; (* if we cast from Dynamic, create a local var as well to do the cast once and allow DCE to perform properly. @@ -165,19 +300,29 @@ let rec type_inline ctx cf f ethis params tret config p force = if v.v_type != t_dynamic && follow e.etype == t_dynamic then (local v).i_write <- true; (match e.eexpr, opt with | TConst TNull , Some c -> mk (TConst c) v.v_type e.epos - (* we have to check for abstract casts here because we can't do that later. However, we have to skip the check for the - first argument of abstract implementation functions. *) - | _ when not (first && Meta.has Meta.Impl cf.cf_meta && cf.cf_name <> "_new") -> (!check_abstract_cast_ref) ctx (map_type v.v_type) e e.epos + (* + This is really weird and should be reviewed again. The problem is that we cannot insert a TCast here because + the abstract `this` value could be written to, which is not possible if it is wrapped in a cast. + + The original problem here is that we do not generate a temporary variable and thus mute the type of the + `this` variable, which leads to unification errors down the line. See issues #2236 and #3713. + *) + (* | _ when first && (Meta.has Meta.Impl cf.cf_meta) -> {e with etype = v.v_type} *) | _ -> e) :: loop pl al false | [], (v,opt) :: al -> - mk (TConst (match opt with None -> TNull | Some c -> c)) v.v_type p :: loop [] al false + (mk (TConst (match opt with None -> TNull | Some c -> c)) v.v_type p) :: loop [] al false in (* Build the expr/var subst list *) let ethis = (match ethis.eexpr with TConst TSuper -> { ethis with eexpr = TConst TThis } | _ -> ethis) in let vthis = alloc_var "_this" ethis.etype in - let inlined_vars = List.map2 (fun e (v,_) -> local v, e) (ethis :: loop params f.tf_args true) ((vthis,None) :: f.tf_args) in + let inlined_vars = List.map2 (fun e (v,_) -> + let l = local v in + if has_side_effect e then l.i_force_temp <- true; (* force tmp var *) + l, e + ) (ethis :: loop params f.tf_args true) ((vthis,None) :: f.tf_args) in + let inlined_vars = List.rev inlined_vars in (* here, we try to eliminate final returns from the expression tree. However, this is not entirely correct since we don't yet correctly propagate @@ -191,41 +336,36 @@ let rec type_inline ctx cf f ethis params tret config p force = in let has_vars = ref false in let in_loop = ref false in - let in_local_fun = ref false in let cancel_inlining = ref false in let has_return_value = ref false in let ret_val = (match follow f.tf_type with TAbstract ({ a_path = ([],"Void") },[]) -> false | _ -> true) in + let map_pos = if self_calling_closure then (fun e -> e) else (fun e -> { e with epos = p }) in let rec map term e = let po = e.epos in - let e = { e with epos = p } in + let e = map_pos e in match e.eexpr with | TLocal v -> let l = read_local v in - if !in_local_fun then l.i_captured <- true; l.i_read <- l.i_read + (if !in_loop then 2 else 1); (* never inline a function which contain a delayed macro because its bound to its variables and not the calling method *) if v.v_name = "__dollar__delay_call" then cancel_inlining := true; - { e with eexpr = TLocal l.i_subst } + let e = { e with eexpr = TLocal l.i_subst } in + if Meta.has Meta.This v.v_meta then mk (TCast(e,None)) v.v_type e.epos else e | TConst TThis -> let l = read_local vthis in l.i_read <- l.i_read + (if !in_loop then 2 else 1); { e with eexpr = TLocal l.i_subst } - | TVars vl -> + | TVar (v,eo) -> has_vars := true; - let vl = List.map (fun (v,e) -> - (local v).i_subst,opt (map false) e - ) vl in - { e with eexpr = TVars vl } + { e with eexpr = TVar ((local v).i_subst,opt (map false) eo)} | TReturn eo when not !in_local_fun -> if not term then error "Cannot inline a not final return" po; (match eo with | None -> mk (TConst TNull) f.tf_type p - | Some e -> has_return_value := true; - (* we can omit unsafe casts to retain the real type, the cast will be added back later anyway *) - (match e.eexpr with - | TCast(e1,None) -> map term e1 - | _ -> map term e)) + | Some e -> + has_return_value := true; + map term e) | TFor (v,e1,e2) -> let i = local v in let e1 = map false e1 in @@ -241,14 +381,6 @@ let rec type_inline ctx cf f ethis params tret config p force = let eloop = map false eloop in in_loop := old; { e with eexpr = TWhile (cond,eloop,flag) } - | TMatch (v,en,cases,def) -> - let term = term && def <> None in - let cases = List.map (fun (i,vl,e) -> - let vl = opt (List.map (fun v -> opt (fun v -> (local v).i_subst) v)) vl in - i, vl, map term e - ) cases in - let def = opt (map term) def in - { e with eexpr = TMatch (map false v,en,cases,def); etype = if term && ret_val then unify_min ctx ((List.map (fun (_,_,e) -> e) cases) @ (match def with None -> [] | Some e -> [e])) else e.etype } | TSwitch (e1,cases,def) when term -> let term = term && def <> None in let cases = List.map (fun (el,e) -> @@ -266,6 +398,13 @@ let rec type_inline ctx cf f ethis params tret config p force = | TBlock l -> let old = save_locals ctx in let t = ref e.etype in + let has_return e = + let rec loop e = match e.eexpr with + | TReturn _ -> raise Exit + | _ -> Type.iter loop e + in + try loop e; false with Exit -> true + in let rec loop = function | [] when term -> t := mk_mono(); @@ -275,6 +414,8 @@ let rec type_inline ctx cf f ethis params tret config p force = let e = map term e in if term then t := e.etype; [e] + | ({ eexpr = TIf (cond,e1,None) } as e) :: l when term && has_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) }] | e :: l -> let e = map false e in e :: loop l @@ -290,12 +431,29 @@ let rec type_inline ctx cf f ethis params tret config p force = | TParenthesis e1 -> let e1 = map term e1 in mk (TParenthesis e1) e1.etype e.epos - | TUnop ((Increment|Decrement),_,{ eexpr = TLocal v }) -> - (read_local v).i_write <- true; - Type.map_expr (map false) e - | TBinop ((OpAssign | OpAssignOp _),{ eexpr = TLocal v },_) -> - (read_local v).i_write <- true; - Type.map_expr (map false) e; + | TUnop ((Increment|Decrement) as op,flag,({ eexpr = TLocal v } as e1)) -> + let l = read_local v in + l.i_write <- true; + {e with eexpr = TUnop(op,flag,{e1 with eexpr = TLocal l.i_subst})} + | TBinop ((OpAssign | OpAssignOp _) as op,({ eexpr = TLocal v } as e1),e2) -> + let l = read_local v in + l.i_write <- true; + let e2 = map false e2 in + {e with eexpr = TBinop(op,{e1 with eexpr = TLocal l.i_subst},e2)} +(* | TCall({eexpr = TLocal v} as e1,el) -> + let el = List.map (map false) el in + let l = read_local v in + let edef() = {e with eexpr = TCall({e1 with eexpr = TLocal l.i_subst},el)} in + begin try + begin match List.assq l inlined_vars with + | {eexpr = TField(_, (FStatic(_,cf) | FInstance(_,_,cf)))} as e' when cf.cf_kind = Method MethInline -> + make_call ctx e' el e.etype e.epos + | _ -> + edef() + end + with Not_found -> + edef() + end *) | TFunction f -> (match f.tf_args with [] -> () | _ -> has_vars := true); let old = save_locals ctx and old_fun = !in_local_fun in @@ -332,23 +490,23 @@ let rec type_inline ctx cf f ethis params tret config p force = in let is_writable e = match e.eexpr with - | TField _ | TLocal _ | TArray _ -> true + | TField _ | TEnumParameter _ | TLocal _ | TArray _ -> true | _ -> false in let force = ref force in let vars = List.fold_left (fun acc (i,e) -> - let flag = (match e.eexpr with - | TLocal { v_name = "this" } -> true + let flag = not i.i_force_temp && (match e.eexpr with + | TLocal v when Meta.has Meta.This v.v_meta -> true | TLocal _ | TConst _ -> not i.i_write | TFunction _ -> if i.i_write then error "Cannot modify a closure parameter inside inline method" p; true | _ -> not i.i_write && i.i_read <= 1 ) in let flag = flag && (not i.i_captured || is_constant e) in (* force inlining if we modify 'this' *) - if i.i_write && i.i_var.v_name = "this" then force := true; - (* force inlining of 'this' variable if the expression is writable *) - let flag = if not flag && i.i_var.v_name = "this" then begin - if i.i_write && not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p; + if i.i_write && (Meta.has Meta.This i.i_var.v_meta) then force := true; + (* force inlining of 'this' variable if it is written *) + let flag = if not flag && (Meta.has Meta.This i.i_var.v_meta) && i.i_write then begin + if not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p; true end else flag in if flag then begin @@ -364,53 +522,53 @@ let rec type_inline ctx cf f ethis params tret config p force = | _ -> Type.map_expr inline_params e in let e = (if PMap.is_empty subst then e else inline_params e) in - let init = (match vars with [] -> None | l -> Some (mk (TVars (List.rev l)) ctx.t.tvoid p)) in + let init = match vars with [] -> None | l -> Some l in (* If we have local variables and returning a value, then this will result in unoptimized JS code, so let's instead skip inlining. This could be fixed with better post process code cleanup (planed) *) - if !cancel_inlining || (Common.platform ctx.com Js && not !force && (init <> None || !has_vars)) then + if !cancel_inlining || (not (Common.defined ctx.com Define.Analyzer) && Common.platform ctx.com Js && not !force && (init <> None || !has_vars)) then None else let wrap e = (* we can't mute the type of the expression because it is not correct to do so *) - (try - let etype = if has_params then map_type e.etype else e.etype in - (* if the expression is "untyped" and we don't want to unify it accidentally ! *) - (match follow e.etype with - | TMono _ -> - (match follow tret with - | TAbstract ({ a_path = [],"Void" },_) -> e - | _ -> raise (Unify_error [])) - | _ -> try - type_eq EqStrict etype tret; - e - with Unify_error _ when (match ctx.com.platform with Cpp -> true | Flash when Common.defined ctx.com Define.As3 -> true | _ -> false) -> - (* try to detect upcasts: in that case we may use a safe cast *) - Type.unify tret etype; - let ct = match follow tret with - | TInst(c,_) -> Some (TClassDecl c) - | _ -> None - in - mk (TCast (e,ct)) tret e.epos) + let etype = if has_params then map_type e.etype else e.etype in + (* if the expression is "untyped" and we don't want to unify it accidentally ! *) + try (match follow e.etype with + | TMono _ | TInst ({cl_kind = KTypeParameter _ },_) -> + (match follow tret with + | TAbstract ({ a_path = [],"Void" },_) -> e + | _ -> raise (Unify_error [])) + | _ -> + type_eq (if ctx.com.config.pf_static then EqDoNotFollowNull else EqStrict) etype tret; + e) with Unify_error _ -> - mk (TCast (e,None)) tret e.epos) + mk (TCast (e,None)) tret e.epos in let e = (match e.eexpr, init with | _, None when not !has_return_value -> {e with etype = tret} | TBlock [e] , None -> wrap e | _ , None -> wrap e - | TBlock l, Some init -> mk (TBlock (init :: l)) tret e.epos - | _, Some init -> mk (TBlock [init;e]) tret e.epos + | TBlock l, Some vl -> + let el_v = List.map (fun (v,eo) -> mk (TVar (v,eo)) ctx.t.tvoid e.epos) vl in + mk (TBlock (el_v @ l)) tret e.epos + | _, Some vl -> + let el_v = List.map (fun (v,eo) -> mk (TVar (v,eo)) ctx.t.tvoid e.epos) vl in + mk (TBlock (el_v @ [e])) tret e.epos ) in + let inline_meta e meta = match meta with + | Meta.Deprecated,_,_ -> mk (TMeta(meta,e)) e.etype e.epos + | _ -> e + in + let e = List.fold_left inline_meta e cf.cf_meta in (* we need to replace type-parameters that were used in the expression *) if not has_params then Some e else - let mt = map_type cf.cf_type in + let mt = map_type cf.cf_type in let unify_func () = unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p in (match follow ethis.etype with | TAnon a -> (match !(a.a_status) with @@ -441,52 +599,52 @@ let rec type_inline ctx cf f ethis params tret config p force = (* ---------------------------------------------------------------------- *) (* LOOPS *) -let rec optimize_for_loop ctx i e1 e2 p = +let rec optimize_for_loop ctx (i,pi) e1 e2 p = let t_void = ctx.t.tvoid in let t_int = ctx.t.tint in let lblock el = Some (mk (TBlock el) t_void p) in let mk_field e n = TField (e,try quick_field e.etype n with Not_found -> assert false) in - let gen_int_iter pt = + let gen_int_iter pt f_get f_length = let i = add_local ctx i pt in let index = gen_local ctx t_int in let arr, avars = (match e1.eexpr with - | TLocal _ -> e1, [] + | TLocal _ -> e1, None | _ -> let atmp = gen_local ctx e1.etype in - mk (TLocal atmp) e1.etype e1.epos, [atmp,Some e1] + mk (TLocal atmp) e1.etype e1.epos, (Some (atmp,Some e1)) ) in let iexpr = mk (TLocal index) t_int p in let e2 = type_expr ctx e2 NoValue in - let aget = mk (TVars [i,Some (mk (TArray (arr,iexpr)) pt p)]) t_void p in + let aget = mk (TVar (i,Some (f_get arr iexpr pt p))) t_void pi in let incr = mk (TUnop (Increment,Prefix,iexpr)) t_int p in let block = match e2.eexpr with | TBlock el -> mk (TBlock (aget :: incr :: el)) t_void e2.epos | _ -> mk (TBlock [aget;incr;e2]) t_void p in - let ivar = index, Some (mk (TConst (TInt 0l)) t_int p) in - let elength = match follow e1.etype with - | TAbstract({a_impl = Some c},_) -> - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in - let ethis = mk (TTypeExpr (TClassDecl c)) ta e1.epos in - let efield = mk (mk_field ethis "get_length") (tfun [arr.etype] t_int) p in - make_call ctx efield [arr] t_int e1.epos - | _ -> mk (mk_field arr "length") t_int p - in - lblock [ - mk (TVars (ivar :: avars)) t_void p; - mk (TWhile ( + let ivar = Some (mk (TConst (TInt 0l)) t_int p) in + let elength = f_length arr p in + let el = [mk (TWhile ( mk (TBinop (OpLt, iexpr, elength)) ctx.t.tbool p, block, NormalWhile )) t_void p; - ] + ] in + let el = match avars with None -> el | Some (v,eo) -> (mk (TVar (v,eo)) t_void p) :: el in + let el = (mk (TVar (index,ivar)) t_void p) :: el in + lblock el + in + let get_next_array_element arr iexpr pt p = + (mk (TArray (arr,iexpr)) pt p) + in + let get_array_length arr p = + mk (mk_field arr "length") ctx.com.basic.tint p in match e1.eexpr, follow e1.etype with | TNew ({ cl_path = ([],"IntIterator") },[],[i1;i2]) , _ -> let max = (match i1.eexpr , i2.eexpr with - | TConst (TInt a), TConst (TInt b) when Int32.compare b a < 0 -> error "Range operate can't iterate backwards" p + | TConst (TInt a), TConst (TInt b) when Int32.compare b a < 0 -> error "Range operator can't iterate backwards" p | _, TConst _ | _ , TLocal _ -> None | _ -> Some (gen_local ctx t_int) ) in @@ -506,7 +664,7 @@ let rec optimize_for_loop ctx i e1 e2 p = check e2; let etmp = mk (TLocal tmp) t_int p in let incr = mk (TUnop (Increment,Postfix,etmp)) t_int p in - let init = mk (TVars [i,Some incr]) t_void p in + let init = mk (TVar (i,Some incr)) t_void pi in let block = match e2.eexpr with | TBlock el -> mk (TBlock (init :: el)) t_void e2.epos | _ -> mk (TBlock [init;e2]) t_void p @@ -514,14 +672,14 @@ let rec optimize_for_loop ctx i e1 e2 p = (* force locals to be of Int type (to prevent Int/UInt issues) *) - let i2 = match i2.etype with + let i2 = match follow i2.etype with | TAbstract ({ a_path = ([],"Int") }, []) -> i2 | _ -> { i2 with eexpr = TCast(i2, None); etype = t_int } in (match max with | None -> lblock [ - mk (TVars [tmp,Some i1]) t_void p; + mk (TVar (tmp,Some i1)) t_void p; mk (TWhile ( mk (TBinop (OpLt, etmp, i2)) ctx.t.tbool p, block, @@ -530,34 +688,97 @@ let rec optimize_for_loop ctx i e1 e2 p = ] | Some max -> lblock [ - mk (TVars [tmp,Some i1;max,Some i2]) t_void p; + mk (TVar (tmp,Some i1)) t_void p; + mk (TVar (max,Some i2)) t_void p; mk (TWhile ( mk (TBinop (OpLt, etmp, mk (TLocal max) t_int p)) ctx.t.tbool p, block, NormalWhile )) t_void p; ]) + | TArrayDecl el, TInst({ cl_path = [],"Array" },[pt]) when false -> + begin try + let num_expr = ref 0 in + let rec loop e = match fst e with + | EContinue | EBreak -> + raise Exit + | _ -> + incr num_expr; + Ast.map_expr loop e + in + ignore(loop e2); + let v = add_local ctx i pt in + let e2 = type_expr ctx e2 NoValue in + let cost = (List.length el) * !num_expr in + let max_cost = try + int_of_string (Common.defined_value ctx.com Define.LoopUnrollMaxCost) + with Not_found -> + 250 + in + if cost > max_cost then raise Exit; + let eloc = mk (TLocal v) v.v_type p in + let el = List.map (fun e -> + let e_assign = mk (TBinop(OpAssign,eloc,e)) e.etype e.epos in + concat e_assign e2 + ) el in + let ev = mk (TVar(v, None)) ctx.t.tvoid p in + Some (mk (TBlock (ev :: el)) ctx.t.tvoid p) + with Exit -> + gen_int_iter pt get_next_array_element get_array_length + end | _ , TInst({ cl_path = [],"Array" },[pt]) | _ , TInst({ cl_path = ["flash"],"Vector" },[pt]) -> - gen_int_iter pt + gen_int_iter pt get_next_array_element get_array_length | _ , TInst({ cl_array_access = Some pt } as c,pl) when (try match follow (PMap.find "length" c.cl_fields).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_fields) -> - gen_int_iter (apply_params c.cl_types pl pt) - | (TLocal _ | TField _), TAbstract({a_impl = Some c} as a,[pt]) when Meta.has Meta.ArrayAccess a.a_meta && (try match follow (PMap.find "length" c.cl_statics).cf_type with TAbstract ({ a_path = [],"Int" },[]) -> true | _ -> false with Not_found -> false) && not (PMap.mem "iterator" c.cl_statics) -> - gen_int_iter pt + gen_int_iter (apply_params c.cl_params pl pt) get_next_array_element get_array_length + | _, TAbstract({a_impl = Some c} as a,tl) -> + begin try + let cf_length = PMap.find "get_length" c.cl_statics in + let get_length e p = + make_static_call ctx c cf_length (apply_params a.a_params tl) [e] ctx.com.basic.tint p + in + begin match follow cf_length.cf_type with + | TFun(_,tr) -> + begin match follow tr with + | TAbstract({a_path = [],"Int"},_) -> () + | _ -> raise Not_found + end + | _ -> + raise Not_found + end; + begin try + (* first try: do we have an @:arrayAccess getter field? *) + let todo = mk (TConst TNull) ctx.t.tint p in + let cf,_,r,_,_ = (!find_array_access_raise_ref) ctx a tl todo None p in + let get_next e_base e_index t p = + make_static_call ctx c cf (apply_params a.a_params tl) [e_base;e_index] r p + in + gen_int_iter r get_next get_length + with Not_found -> + (* second try: do we have @:arrayAccess on the abstract itself? *) + if not (Meta.has Meta.ArrayAccess a.a_meta) then raise Not_found; + (* let's allow this only for core-type abstracts *) + if not (Meta.has Meta.CoreType a.a_meta) then raise Not_found; + (* in which case we assume that a singular type parameter is the element type *) + let t = match tl with [t] -> t | _ -> raise Not_found in + gen_int_iter t get_next_array_element get_length + end with Not_found -> + None + end | _ , TInst ({ cl_kind = KGenericInstance ({ cl_path = ["haxe";"ds"],"GenericStack" },[t]) } as c,[]) -> let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> assert false) in let i = add_local ctx i t in let cell = gen_local ctx tcell in let cexpr = mk (TLocal cell) tcell p in let e2 = type_expr ctx e2 NoValue in - let evar = mk (TVars [i,Some (mk (mk_field cexpr "elt") t p)]) t_void p in + let evar = mk (TVar (i,Some (mk (mk_field cexpr "elt") t p))) t_void pi in let enext = mk (TBinop (OpAssign,cexpr,mk (mk_field cexpr "next") tcell p)) tcell p in let block = match e2.eexpr with | TBlock el -> mk (TBlock (evar :: enext :: el)) t_void e2.epos | _ -> mk (TBlock [evar;enext;e2]) t_void p in lblock [ - mk (TVars [cell,Some (mk (mk_field e1 "head") tcell p)]) t_void p; + mk (TVar (cell,Some (mk (mk_field e1 "head") tcell p))) t_void p; mk (TWhile ( mk (TBinop (OpNotEq, cexpr, mk (TConst TNull) tcell p)) ctx.t.tbool p, block, @@ -567,6 +788,24 @@ let rec optimize_for_loop ctx i e1 e2 p = | _ -> None +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 _, _, 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 in + let eit = mk (TLocal tmp) e1.etype 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 eblock = (match e2.eexpr with + | TBlock el -> { e2 with eexpr = TBlock (enext :: el) } + | _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p + ) in + mk (TBlock [ + mk (TVar (tmp,Some e1)) ctx.t.tvoid p; + mk (TWhile (ehasnext,eblock,NormalWhile)) ctx.t.tvoid p + ]) ctx.t.tvoid p + + (* ---------------------------------------------------------------------- *) (* SANITIZE *) @@ -600,33 +839,10 @@ let standard_precedence op = let rec need_parent e = match e.eexpr with - | TConst _ | TLocal _ | TArray _ | TField _ | TParenthesis _ | TCall _ | TNew _ | TTypeExpr _ | TObjectDecl _ | TArrayDecl _ -> false + | TConst _ | TLocal _ | TArray _ | TField _ | TEnumParameter _ | TParenthesis _ | TMeta _ | TCall _ | TNew _ | TTypeExpr _ | TObjectDecl _ | TArrayDecl _ -> false | TCast (e,None) -> need_parent e - | TCast _ | TThrow _ | TReturn _ | TTry _ | TMatch _ | TSwitch _ | TFor _ | TIf _ | TWhile _ | TBinop _ | TContinue | TBreak - | TBlock _ | TVars _ | TFunction _ | TUnop _ -> true - -let rec add_final_return e t = - let def_return p = - let c = (match follow t with - | TAbstract ({ a_path = [],"Int" },_) -> TInt 0l - | TAbstract ({ a_path = [],"Float" },_) -> TFloat "0." - | TAbstract ({ a_path = [],"Bool" },_) -> TBool false - | _ -> TNull - ) in - { eexpr = TReturn (Some { eexpr = TConst c; epos = p; etype = t }); etype = t; epos = p } - in - match e.eexpr with - | TBlock el -> - (match List.rev el with - | [] -> e - | elast :: el -> - match add_final_return elast t with - | { eexpr = TBlock el2 } -> { e with eexpr = TBlock ((List.rev el) @ el2) } - | elast -> { e with eexpr = TBlock (List.rev (elast :: el)) }) - | TReturn _ -> - e - | _ -> - { e with eexpr = TBlock [e;def_return e.epos] } + | TCast _ | TThrow _ | TReturn _ | TTry _ | TSwitch _ | TFor _ | TIf _ | TWhile _ | TBinop _ | TContinue | TBreak + | TBlock _ | TVar _ | TFunction _ | TUnop _ -> true let sanitize_expr com e = let parent e = @@ -642,9 +858,8 @@ let sanitize_expr com e = let complex e = (* complex expressions are the one that once generated to source consists in several expressions *) match e.eexpr with - | TVars _ (* needs to be put into blocks *) + | TVar _ (* needs to be put into blocks *) | TFor _ (* a temp var is needed for holding iterator *) - | TMatch _ (* a temp var is needed for holding enum *) | TCall ({ eexpr = TLocal { v_name = "__js__" } },_) (* we never know *) -> block e | _ -> e @@ -659,11 +874,16 @@ let sanitize_expr com e = in match e.eexpr with | TConst TNull -> - if com.config.pf_static && not (is_nullable e.etype) then - (match follow e.etype with - | TMono _ -> () (* in these cases the null will cast to default value *) - | TFun _ -> () (* this is a bit a particular case, maybe flash-specific actually *) - | _ -> com.error ("On static platforms, null can't be used as basic type " ^ s_type (print_context()) e.etype) e.epos); + if com.config.pf_static && not (is_nullable e.etype) then begin + let rec loop t = match follow t with + | TMono _ -> () (* in these cases the null will cast to default value *) + | TFun _ -> () (* this is a bit a particular case, maybe flash-specific actually *) + (* TODO: this should use get_underlying_type, but we do not have access to Codegen here. *) + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> loop (apply_params a.a_params tl a.a_this) + | _ -> com.error ("On static platforms, null can't be used as basic type " ^ s_type (print_context()) e.etype) e.epos + in + loop e.etype + end; e | TBinop (op,e1,e2) -> let swap op1 op2 = @@ -681,14 +901,14 @@ 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 (op,mode,e2) -> + | TUnop (op,mode,e1) -> let rec loop ee = match ee.eexpr with - | TBinop _ | TIf _ -> parent e2 + | TBinop _ | TIf _ | TUnop _ -> parent e1 | TCast (e,None) -> loop e - | _ -> e2 + | _ -> e1 in - { e with eexpr = TUnop (op,mode,loop e2) } + { e with eexpr = TUnop (op,mode,loop e1)} | TIf (e1,e2,eelse) -> let e1 = parent e1 in let e2 = (if (eelse <> None && has_if e2) || (match e2.eexpr with TIf _ -> true | _ -> false) then block e2 else complex e2) in @@ -702,11 +922,6 @@ let sanitize_expr com e = let e2 = complex e2 in { e with eexpr = TFor (v,e1,e2) } | TFunction f -> - let f = (match follow f.tf_type with - | TAbstract ({ a_path = [],"Void" },[]) -> f - | t -> - if com.config.pf_add_final_return then { f with tf_expr = add_final_return f.tf_expr t } else f - ) in let f = (match f.tf_expr.eexpr with | TBlock _ -> f | _ -> { f with tf_expr = block f.tf_expr } @@ -714,6 +929,8 @@ let sanitize_expr com e = { e with eexpr = TFunction f } | TCall (e2,args) -> if need_parent e2 then { e with eexpr = TCall(parent e2,args) } else e + | TEnumParameter (e2,ef,i) -> + if need_parent e2 then { e with eexpr = TEnumParameter(parent e2,ef,i) } else e | TField (e2,f) -> if need_parent e2 then { e with eexpr = TField(parent e2,f) } else e | TArray (e1,e2) -> @@ -727,15 +944,10 @@ let sanitize_expr com e = let cases = List.map (fun (el,e) -> el, complex e) cases in let def = (match def with None -> None | Some e -> Some (complex e)) in { e with eexpr = TSwitch (e1,cases,def) } - | TMatch (e1, en, cases, def) -> - let e1 = parent e1 in - let cases = List.map (fun (el,vars,e) -> el, vars, complex e) cases in - let def = (match def with None -> None | Some e -> Some (complex e)) in - { e with eexpr = TMatch (e1,en,cases,def) } | _ -> e -let reduce_expr ctx e = +let reduce_expr com e = match e.eexpr with | TSwitch (_,cases,_) -> List.iter (fun (cl,_) -> @@ -759,7 +971,7 @@ let reduce_expr ctx e = | _ -> true ) l with - | [] -> { ec with epos = e.epos } + | [] -> ec | l -> { e with eexpr = TBlock (List.rev (ec :: l)) }) | TParenthesis ec -> { ec with epos = e.epos } @@ -768,13 +980,13 @@ let reduce_expr ctx e = | _ -> e -let rec sanitize ctx e = - sanitize_expr ctx.com (reduce_expr ctx (Type.map_expr (sanitize ctx) e)) +let rec sanitize com e = + sanitize_expr com (reduce_expr com (Type.map_expr (sanitize com) e)) (* ---------------------------------------------------------------------- *) (* REDUCE *) -let rec reduce_loop ctx e = +let optimize_binop e op e1 e2 = let is_float t = match follow t with | TAbstract({ a_path = [],"Float" },_) -> true @@ -785,145 +997,160 @@ let rec reduce_loop ctx e = | TAbstract({ a_path = [],("Float"|"Int") },_) -> true | _ -> false in - let e = Type.map_expr (reduce_loop ctx) e in let check_float op f1 f2 = let f = op f1 f2 in - let fstr = string_of_float f in + let fstr = float_repres f in if (match classify_float f with FP_nan | FP_infinite -> false | _ -> float_of_string fstr = f) then { e with eexpr = TConst (TFloat fstr) } else e in - sanitize_expr ctx.com (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) - | TWhile ({ eexpr = TConst (TBool false) },sub,flag) -> - (match flag with - | NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *) - | DoWhile -> e) (* we cant remove while since sub can contain continue/break *) - | TBinop (op,e1,e2) -> - (match e1.eexpr, e2.eexpr with - | TConst (TInt 0l) , _ when op = OpAdd && is_numeric e2.etype -> e2 - | TConst (TInt 1l) , _ when op = OpMult -> e2 - | TConst (TFloat v) , _ when op = OpAdd && float_of_string v = 0. && is_float e2.etype -> e2 - | TConst (TFloat v) , _ when op = OpMult && float_of_string v = 1. && is_float e2.etype -> e2 - | _ , TConst (TInt 0l) when (match op with OpAdd -> is_numeric e1.etype | OpSub | OpShr | OpShl -> true | _ -> false) -> e1 (* bits operations might cause overflow *) - | _ , TConst (TInt 1l) when op = OpMult -> e1 - | _ , TConst (TFloat v) when (match op with OpAdd | OpSub -> float_of_string v = 0. && is_float e1.etype | _ -> false) -> e1 (* bits operations might cause overflow *) - | _ , TConst (TFloat v) when op = OpMult && float_of_string v = 1. && is_float e1.etype -> e1 - | TConst TNull, TConst TNull -> - (match op with - | OpEq -> { e with eexpr = TConst (TBool true) } - | OpNotEq -> { e with eexpr = TConst (TBool false) } - | _ -> e) - | TConst (TInt a), TConst (TInt b) -> - let opt f = try { e with eexpr = TConst (TInt (f a b)) } with Exit -> e in - let check_overflow f = - opt (fun a b -> - let v = f (Int64.of_int32 a) (Int64.of_int32 b) in - let iv = Int64.to_int32 v in - if Int64.compare (Int64.of_int32 iv) v <> 0 then raise Exit; - iv - ) - in - let ebool t = - { e with eexpr = TConst (TBool (t (Int32.compare a b) 0)) } - in - (match op with - | OpAdd -> check_overflow Int64.add - | OpSub -> check_overflow Int64.sub - | OpMult -> check_overflow Int64.mul - | OpDiv -> check_float ( /. ) (Int32.to_float a) (Int32.to_float b) - | OpAnd -> opt Int32.logand - | OpOr -> opt Int32.logor - | OpXor -> opt Int32.logxor - | OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int b)) - | OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int b)) - | OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int b)) - | OpEq -> ebool (=) - | OpNotEq -> ebool (<>) - | OpGt -> ebool (>) - | OpGte -> ebool (>=) - | OpLt -> ebool (<) - | OpLte -> ebool (<=) - | _ -> e) - | TConst ((TFloat _ | TInt _) as ca), TConst ((TFloat _ | TInt _) as cb) -> - let fa = (match ca with - | TFloat a -> float_of_string a - | TInt a -> Int32.to_float a - | _ -> assert false - ) in - let fb = (match cb with - | TFloat b -> float_of_string b - | TInt b -> Int32.to_float b - | _ -> assert false - ) in - let fop op = check_float op fa fb in - let ebool t = - { e with eexpr = TConst (TBool (t (compare fa fb) 0)) } - in - (match op with - | OpAdd -> fop (+.) - | OpDiv -> fop (/.) - | OpSub -> fop (-.) - | OpMult -> fop ( *. ) - | OpEq -> ebool (=) - | OpNotEq -> ebool (<>) - | OpGt -> ebool (>) - | OpGte -> ebool (>=) - | OpLt -> ebool (<) - | OpLte -> ebool (<=) - | _ -> e) - | TConst (TBool a), TConst (TBool b) -> - let ebool f = - { e with eexpr = TConst (TBool (f a b)) } - in - (match op with - | OpEq -> ebool (=) - | OpNotEq -> ebool (<>) - | OpBoolAnd -> ebool (&&) - | OpBoolOr -> ebool (||) - | _ -> e) - | TConst a, TConst b when op = OpEq || op = OpNotEq -> - let ebool b = - { e with eexpr = TConst (TBool (if op = OpEq then b else not b)) } - in - (match a, b with - | TInt a, TFloat b | TFloat b, TInt a -> ebool (Int32.to_float a = float_of_string b) - | _ -> ebool (a = b)) - | TConst (TBool a), _ -> - (match op with - | OpBoolAnd -> if a then e2 else { e with eexpr = TConst (TBool false) } - | OpBoolOr -> if a then { e with eexpr = TConst (TBool true) } else e2 - | _ -> e) - | _ , TConst (TBool a) -> - (match op with - | OpBoolAnd when a -> e1 - | OpBoolOr when not a -> e1 - | _ -> e) - | TField (_,FEnum (e1,f1)), TField (_,FEnum (e2,f2)) when e1 == e2 -> - (match op with - | 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 - | _ -> - error "You cannot directly compare enums with arguments. Use either 'switch' or 'Type.enumEq'" e.epos) + (match e1.eexpr, e2.eexpr with + | TConst (TInt 0l) , _ when op = OpAdd && is_numeric e2.etype -> e2 + | TConst (TInt 1l) , _ when op = OpMult -> e2 + | TConst (TFloat v) , _ when op = OpAdd && float_of_string v = 0. && is_float e2.etype -> e2 + | TConst (TFloat v) , _ when op = OpMult && float_of_string v = 1. && is_float e2.etype -> e2 + | _ , TConst (TInt 0l) when (match op with OpAdd -> is_numeric e1.etype | OpSub | OpShr | OpShl -> true | _ -> false) -> e1 (* bits operations might cause overflow *) + | _ , TConst (TInt 1l) when op = OpMult -> e1 + | _ , TConst (TFloat v) when (match op with OpAdd | OpSub -> float_of_string v = 0. && is_float e1.etype | _ -> false) -> e1 (* bits operations might cause overflow *) + | _ , TConst (TFloat v) when op = OpMult && float_of_string v = 1. && is_float e1.etype -> e1 + | TConst TNull, TConst TNull -> + (match op with + | OpEq -> { e with eexpr = TConst (TBool true) } + | OpNotEq -> { e with eexpr = TConst (TBool false) } + | _ -> e) + | TFunction _, TConst TNull -> + (match op with + | OpEq -> { e with eexpr = TConst (TBool false) } + | OpNotEq -> { e with eexpr = TConst (TBool true) } + | _ -> e) + | TConst TNull, TFunction _ -> + (match op with + | OpEq -> { e with eexpr = TConst (TBool false) } + | OpNotEq -> { e with eexpr = TConst (TBool true) } + | _ -> e) + | TConst (TInt a), TConst (TInt b) -> + let opt f = try { e with eexpr = TConst (TInt (f a b)) } with Exit -> e in + let check_overflow f = + opt (fun a b -> + let v = f (Int64.of_int32 a) (Int64.of_int32 b) in + let iv = Int64.to_int32 v in + if Int64.compare (Int64.of_int32 iv) v <> 0 then raise Exit; + iv + ) + in + let ebool t = + { e with eexpr = TConst (TBool (t (Int32.compare a b) 0)) } + in + (match op with + | OpAdd -> check_overflow Int64.add + | OpSub -> check_overflow Int64.sub + | OpMult -> check_overflow Int64.mul + | OpDiv -> check_float ( /. ) (Int32.to_float a) (Int32.to_float b) + | OpAnd -> opt Int32.logand + | OpOr -> opt Int32.logor + | OpXor -> opt Int32.logxor + | OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int b)) + | OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int b)) + | OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int b)) + | OpEq -> ebool (=) + | OpNotEq -> ebool (<>) + | OpGt -> ebool (>) + | OpGte -> ebool (>=) + | OpLt -> ebool (<) + | OpLte -> ebool (<=) + | _ -> e) + | TConst ((TFloat _ | TInt _) as ca), TConst ((TFloat _ | TInt _) as cb) -> + let fa = (match ca with + | TFloat a -> float_of_string a + | TInt a -> Int32.to_float a + | _ -> assert false + ) in + let fb = (match cb with + | TFloat b -> float_of_string b + | TInt b -> Int32.to_float b + | _ -> assert false + ) in + let fop op = check_float op fa fb in + let ebool t = + { e with eexpr = TConst (TBool (t (compare fa fb) 0)) } + in + (match op with + | OpAdd -> fop (+.) + | OpDiv -> fop (/.) + | OpSub -> fop (-.) + | OpMult -> fop ( *. ) + | OpEq -> ebool (=) + | OpNotEq -> ebool (<>) + | OpGt -> ebool (>) + | OpGte -> ebool (>=) + | OpLt -> ebool (<) + | OpLte -> ebool (<=) + | _ -> e) + | TConst (TBool a), TConst (TBool b) -> + let ebool f = + { e with eexpr = TConst (TBool (f a b)) } + in + (match op with + | OpEq -> ebool (=) + | OpNotEq -> ebool (<>) + | OpBoolAnd -> ebool (&&) + | OpBoolOr -> ebool (||) + | _ -> e) + | TConst a, TConst b when op = OpEq || op = OpNotEq -> + let ebool b = + { e with eexpr = TConst (TBool (if op = OpEq then b else not b)) } + in + (match a, b with + | TInt a, TFloat b | TFloat b, TInt a -> ebool (Int32.to_float a = float_of_string b) + | _ -> ebool (a = b)) + | TConst (TBool a), _ -> + (match op with + | OpBoolAnd -> if a then e2 else { e with eexpr = TConst (TBool false) } + | OpBoolOr -> if a then { e with eexpr = TConst (TBool true) } else e2 + | _ -> e) + | _ , TConst (TBool a) -> + (match op with + | OpBoolAnd when a -> e1 + | OpBoolOr when not a -> e1 + | _ -> e) + | TField (_,FEnum (e1,f1)), TField (_,FEnum (e2,f2)) when e1 == e2 -> + (match op with + | 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 | _ -> - e) - | TUnop (op,flag,esub) -> - (match op, esub.eexpr with - | Not, TConst (TBool f) -> { e with eexpr = TConst (TBool (not f)) } + error "You cannot directly compare enums with arguments. Use either 'switch' or 'Type.enumEq'" e.epos) + | _ -> + e) + +let optimize_unop e op flag esub = + match op, esub.eexpr with + | Not, (TConst (TBool f) | TParenthesis({eexpr = TConst (TBool f)})) -> { e with eexpr = TConst (TBool (not f)) } | Neg, TConst (TInt i) -> { e with eexpr = TConst (TInt (Int32.neg i)) } | NegBits, TConst (TInt i) -> { e with eexpr = TConst (TInt (Int32.lognot i)) } | Neg, TConst (TFloat f) -> let v = 0. -. float_of_string f in - let vstr = string_of_float v in + let vstr = float_repres v in if float_of_string vstr = v then { e with eexpr = TConst (TFloat vstr) } else e | _ -> e - ) + +let rec reduce_loop ctx e = + let e = Type.map_expr (reduce_loop ctx) e in + sanitize_expr ctx.com (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) + | TWhile ({ eexpr = TConst (TBool false) },sub,flag) -> + (match flag with + | NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *) + | DoWhile -> e) (* we cant remove while since sub can contain continue/break *) + | TBinop (op,e1,e2) -> + optimize_binop e op e1 e2 + | TUnop (op,flag,esub) -> + optimize_unop e op flag esub | TCall ({ eexpr = TField ({ eexpr = TTypeExpr (TClassDecl c) },field) },params) -> (match api_inline ctx c (field_name field) params e.epos with | None -> reduce_expr ctx e @@ -932,13 +1159,16 @@ let rec reduce_loop ctx e = let cf = mk_field "" ef.etype e.epos 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 inl = (try type_inline ctx cf func ethis el rt None e.epos false with Error (Custom _,_) -> None) 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) | TCall ({ eexpr = TField (o,FClosure (c,cf)) } as f,el) -> - let fmode = (match c with None -> FAnon cf | Some c -> FInstance (c,cf)) in + let fmode = (match c with None -> FAnon cf | Some (c,tl) -> FInstance (c,tl,cf)) in { e with eexpr = TCall ({ f with eexpr = TField (o,fmode) },el) } + | TSwitch (e1,[[{eexpr = TConst (TBool true)}],{eexpr = TConst (TBool true)}],Some ({eexpr = TConst (TBool false)})) -> + (* introduced by extractors in some cases *) + e1 | _ -> reduce_expr ctx e) @@ -954,7 +1184,20 @@ let rec make_constant_expression ctx ?(concat_strings=false) e = Some (mk (TConst (TString (s1 ^ s2))) ctx.com.basic.tstring (punion e1.epos e2.epos)) | Some e1, Some e2 -> Some (mk (TBinop(op, e1, e2)) e.etype e.epos) | _ -> None) - | TParenthesis e -> Some e + | TCast (e1, None) -> + (match make_constant_expression ctx e1 with + | None -> None + | Some e1 -> Some {e with eexpr = TCast(e1,None)}) + | TParenthesis e1 -> + begin match make_constant_expression ctx ~concat_strings e1 with + | None -> None + | Some e1 -> Some {e with eexpr = TParenthesis e1} + end + | TMeta(m,e1) -> + begin match make_constant_expression ctx ~concat_strings e1 with + | None -> None + | Some e1 -> Some {e with eexpr = TMeta(m,e1)} + end | TTypeExpr _ -> Some e (* try to inline static function calls *) | TCall ({ etype = TFun(_,ret); eexpr = TField (_,FStatic (c,cf)) },el) -> @@ -981,52 +1224,155 @@ let rec make_constant_expression ctx ?(concat_strings=false) e = We replace the variables by their fields lists, and the corresponding fields accesses as well *) +type inline_kind = + | IKCtor of tfunc * tclass_field * tclass * t list * texpr list * texpr list + | IKArray of texpr list * t + | IKStructure of (string * texpr) list + | IKNone + let inline_constructors ctx e = let vars = ref PMap.empty in + let is_valid_ident s = + try + if String.length s = 0 then raise Exit; + begin match String.unsafe_get s 0 with + | 'a'..'z' | 'A'..'Z' | '_' -> () + | _ -> raise Exit + end; + for i = 1 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 + in + let rec get_inline_ctor_info e = match e.eexpr with + | TNew ({ cl_constructor = Some ({ cf_kind = Method MethInline; cf_expr = Some { eexpr = TFunction f } } as cst) } as c,tl,pl) -> + IKCtor (f,cst,c,tl,pl,[]) + | TObjectDecl [] | TArrayDecl [] -> + IKNone + | TArrayDecl el -> + begin match follow e.etype with + | TInst({cl_path = [],"Array"},[t]) -> + IKArray(el,t) + | _ -> + IKNone + end + | TObjectDecl fl -> + if (List.exists (fun (s,_) -> not (is_valid_ident s)) fl) then + IKNone + else + IKStructure fl + | TCast(e,None) | TParenthesis e -> + get_inline_ctor_info e + | TBlock el -> + begin match List.rev el with + | e :: el -> + begin match get_inline_ctor_info e with + | IKCtor(f,cst,c,tl,pl,e_init) -> + IKCtor(f,cst,c,tl,pl,(List.rev el) @ e_init) + | _ -> + IKNone + end + | [] -> + IKNone + end + | _ -> + IKNone + in + let check_field v s e t = + let (a,b,fields,c,d) = PMap.find (-v.v_id) !vars in + if not (List.exists (fun (s2,_,_) -> s = s2) fields) then + vars := PMap.add (-v.v_id) (a,b,(s,e,t) :: fields,c,d) !vars + in + let cancel v = + v.v_id <- -v.v_id; + (* error if the constructor is extern *) + (match PMap.find v.v_id !vars with + | _,_,_,true,p -> + display_error ctx "Extern constructor could not be inlined" p; + error "Variable is used here" e.epos + | _ -> ()); + vars := PMap.remove v.v_id !vars; + in + let rec skip_to_var e = match e.eexpr with + | TLocal v when v.v_id < 0 -> Some v + (* | TCast(e1,None) | TMeta(_,e1) | TParenthesis(e1) -> skip_to_var e1 *) + | _ -> None + in let rec find_locals e = match e.eexpr with - | TVars vl -> + | TVar (v,eo) -> Type.iter find_locals e; - List.iter (fun (v,e) -> - match e with - | Some ({ eexpr = TNew ({ cl_constructor = Some ({ cf_kind = Method MethInline; cf_expr = Some { eexpr = TFunction f } } as cst) } as c,_,pl) } as n) -> - (* inline the constructor *) - (match (try type_inline ctx cst f (mk (TLocal v) v.v_type n.epos) pl ctx.t.tvoid None n.epos true with Error (Custom _,_) -> None) with - | None -> () - | Some ecst -> - let assigns = ref [] in - (* make sure we only have v.field = expr calls *) - let rec get_assigns e = - match e.eexpr with - | TBlock el -> - List.iter get_assigns el - | TBinop (OpAssign, { eexpr = TField ({ eexpr = TLocal vv },FInstance(_,cf)); etype = t }, e) when v == vv -> - assigns := (cf.cf_name,e,t) :: !assigns - | _ -> - raise Exit - in - try - get_assigns ecst; - (* mark variable as candidate for inlining *) - vars := PMap.add v.v_id (v,List.rev !assigns,c.cl_extern || Meta.has Meta.Extern cst.cf_meta,n.epos) !vars; - v.v_id <- -v.v_id; (* mark *) - (* recurse with the constructor code which will be inlined here *) - find_locals ecst - with Exit -> - ()) + begin match eo with + | Some n -> + begin match get_inline_ctor_info n with + | IKCtor (f,cst,c,tl,pl,el_init) when type_iseq v.v_type n.etype -> + (* inline the constructor *) + (match (try type_inline ctx cst f (mk (TLocal v) (TInst (c,tl)) n.epos) pl ctx.t.tvoid None n.epos true with Error (Custom _,_) -> None) with + | None -> () + | Some ecst -> + let assigns = ref [] in + (* add field inits here because the filter has not run yet (issue #2336) *) + List.iter (fun cf -> match cf.cf_kind,cf.cf_expr with + | Var _,Some e -> assigns := (cf.cf_name,e,cf.cf_type) :: !assigns + | _ -> () + ) c.cl_ordered_fields; + (* make sure we only have v.field = expr calls *) + let rec get_assigns e = + match e.eexpr with + | TBlock el -> + List.iter get_assigns el + | TBinop (OpAssign, { eexpr = TField ({ eexpr = TLocal vv },FInstance(_,_,cf)); etype = t }, e) when v == vv -> + assigns := (cf.cf_name,e,t) :: !assigns + | _ -> + raise Exit + in + try + get_assigns ecst; + (* mark variable as candidate for inlining *) + vars := PMap.add v.v_id (v,el_init,List.rev !assigns,c.cl_extern || Meta.has Meta.Extern cst.cf_meta,n.epos) !vars; + v.v_id <- -v.v_id; (* mark *) + (* recurse with the constructor code which will be inlined here *) + find_locals ecst + with Exit -> + ()) + | IKArray (el,t) -> + vars := PMap.add v.v_id (v,[],ExtList.List.mapi (fun i e -> string_of_int i,e,t) el, false, n.epos) !vars; + v.v_id <- -v.v_id; + | IKStructure fl -> + vars := PMap.add v.v_id (v,[],List.map (fun (s,e) -> s,e,e.etype) fl, false, n.epos) !vars; + v.v_id <- -v.v_id; + | _ -> + () + end | _ -> () - ) vl - | TField ({ eexpr = TLocal _ },FInstance (_,{ cf_kind = Var _ })) -> - () + end + | TField(e1, (FInstance(_, _, {cf_kind = Var _; cf_name = s}) | FAnon({cf_kind = Var _; cf_name = s}))) -> + (match skip_to_var e1 with None -> find_locals e1 | Some _ -> ()) + | TArray (e1,{eexpr = TConst (TInt i)}) -> + begin match skip_to_var e1 with + | None -> find_locals e1 + | Some v -> + let (_,_,fields,_,_) = PMap.find (-v.v_id) !vars in + let i = Int32.to_int i in + if i < 0 || i >= List.length fields then cancel v + end + | TBinop((OpAssign | OpAssignOp _),e1,e2) -> + begin match e1.eexpr with + | TArray ({eexpr = TLocal v},{eexpr = TConst (TInt i)}) when v.v_id < 0 -> + check_field v (Int32.to_string i) e2 e2.etype + | TField({eexpr = TLocal v}, (FInstance(_, _, {cf_kind = Var _; cf_name = s}) | FAnon({cf_kind = Var _; cf_name = s}))) when v.v_id < 0 -> + check_field v s e2 e2.etype + | _ -> + find_locals e1 + end; + find_locals e2 | TLocal v when v.v_id < 0 -> - v.v_id <- -v.v_id; - (* error if the constructor is extern *) - (match PMap.find v.v_id !vars with - | _,_,true,p -> - display_error ctx "Extern constructor could not be inlined" p; - error "Variable is used here" e.epos - | _ -> ()); - vars := PMap.remove v.v_id !vars; + cancel v | _ -> Type.iter find_locals e in @@ -1035,40 +1381,86 @@ let inline_constructors ctx e = if PMap.is_empty vars then e else begin - let vfields = PMap.map (fun (v,assigns,_,_) -> - List.fold_left (fun (acc,map) (name,e,t) -> + let vfields = PMap.map (fun (v,el_init,assigns,_,_) -> + (List.fold_left (fun (acc,map) (name,e,t) -> let vf = alloc_var (v.v_name ^ "_" ^ name) t in ((vf,e) :: acc, PMap.add name vf map) - ) ([],PMap.empty) assigns + ) ([],PMap.empty) assigns),el_init ) vars in + let el_b = ref [] in + let append e = el_b := e :: !el_b in + let inline_field c cf v = + let (_, vars),el_init = PMap.find (-v.v_id) vfields in + (try + let v = PMap.find cf.cf_name vars in + mk (TLocal v) v.v_type e.epos + with Not_found -> + if (c.cl_path = ([],"Array") && cf.cf_name = "length") then begin + (* this can only occur for inlined array declarations, so we can use the statically known length here (issue #2568)*) + let l = PMap.fold (fun _ i -> i + 1) vars 0 in + mk (TConst (TInt (Int32.of_int l))) ctx.t.tint e.epos + end else + (* the variable was not set in the constructor, assume null *) + mk (TConst TNull) e.etype e.epos) + in + let inline_anon_field cf v = + let (_, vars),_ = PMap.find (-v.v_id) vfields in + (try + let v = PMap.find cf.cf_name vars in + mk (TLocal v) v.v_type e.epos + with Not_found -> + (* this could happen in untyped code, assume null *) + mk (TConst TNull) e.etype e.epos) + in + let inline_array_access i v = + let (_, vars),_ = PMap.find (-v.v_id) vfields in + (try + let v = PMap.find (Int32.to_string i) vars in + mk (TLocal v) v.v_type e.epos + with Not_found -> + (* probably out-of-bounds, assume null *) + mk (TConst TNull) e.etype e.epos) + in let rec subst e = match e.eexpr with - | TVars vl -> - let rec loop acc vl = - match vl with - | [] -> List.rev acc - | (v,None) :: vl -> loop ((v,None) :: acc) vl - | (v,Some e) :: vl when v.v_id < 0 -> - let vars, _ = PMap.find (-v.v_id) vfields in - loop (List.map (fun (v,e) -> v, Some (subst e)) vars @ acc) vl - | (v,Some e) :: vl -> - loop ((v,Some (subst e)) :: acc) vl + | TBlock el -> + let old = !el_b in + el_b := []; + List.iter (fun e -> append (subst e)) el; + let n = !el_b in + el_b := old; + {e with eexpr = TBlock (List.rev n)} + | TVar (v,Some e) when v.v_id < 0 -> + let (vars, _),el_init = PMap.find (-v.v_id) vfields in + List.iter (fun e -> + append (subst e) + ) el_init; + let (v_first,e_first),vars = match vars with + | v :: vl -> v,vl + | [] -> assert false in - let vl = loop [] vl in - mk (TVars vl) e.etype e.epos - | TField ({ eexpr = TLocal v },FInstance (_,cf)) when v.v_id < 0 -> - let _, vars = PMap.find (-v.v_id) vfields in - (try - let v = PMap.find cf.cf_name vars in - mk (TLocal v) v.v_type e.epos - with Not_found -> - (* the variable was not set in the constructor, assume null *) - mk (TConst TNull) e.etype e.epos) + List.iter (fun (v,e) -> append (mk (TVar(v,Some (subst e))) ctx.t.tvoid e.epos)) (List.rev vars); + mk (TVar (v_first, Some (subst e_first))) ctx.t.tvoid e.epos + | TField (e1,FInstance (c,_,cf)) -> + begin match skip_to_var e1 with + | None -> Type.map_expr subst e + | Some v -> inline_field c cf v + end + | TArray (e1,{eexpr = TConst (TInt i)}) -> + begin match skip_to_var e1 with + | None -> Type.map_expr subst e + | Some v -> inline_array_access i v + end + | TField (e1,FAnon(cf)) -> + begin match skip_to_var e1 with + | None -> Type.map_expr subst e + | Some v -> inline_anon_field cf v + end | _ -> Type.map_expr subst e in let e = (try subst e with Not_found -> assert false) in - PMap.iter (fun _ (v,_,_,_) -> v.v_id <- -v.v_id) vars; + PMap.iter (fun _ (v,_,_,_,_) -> v.v_id <- -v.v_id) vars; e end @@ -1224,6 +1616,8 @@ let optimize_completion_expr e = with Not_found -> (* not found locals are most likely to be member/static vars *) e) + | EFunction (_,f) -> + Ast.map_expr (subst_locals { r = PMap.foldi (fun n i acc -> if List.exists (fun (a,_,_,_) -> a = n) f.f_args then acc else PMap.add n i acc) locals.r PMap.empty }) e | _ -> Ast.map_expr (subst_locals locals) e in diff --git a/parser.ml b/parser.ml old mode 100755 new mode 100644 index 0268fb6afb4953d7b7ddf594f9c6df8866021b0a..e45e9def74b174cdbe8678197f3bc85a78a82cc0 --- a/parser.ml +++ b/parser.ml @@ -32,7 +32,7 @@ type error_msg = | Custom of string exception Error of error_msg * pos -exception TypePath of string list * (string * bool) option +exception TypePath of string list * (string * bool) option * bool (* in import *) exception Display of expr let error_msg = function @@ -50,7 +50,14 @@ let display_error : (error_msg -> pos -> unit) ref = ref (fun _ _ -> assert fals let quoted_ident_prefix = "@$__hx__" let quote_ident s = - try + quoted_ident_prefix ^ s + +let unquote_ident f = + let pf = quoted_ident_prefix in + let pflen = String.length pf in + let is_quoted = String.length f >= pflen && String.sub f 0 pflen = pf in + let s = if is_quoted then String.sub f pflen (String.length f - pflen) else f in + let is_valid = not is_quoted || try for i = 0 to String.length s - 1 do match String.unsafe_get s i with | 'a'..'z' | 'A'..'Z' | '_' -> () @@ -58,13 +65,16 @@ let quote_ident s = | _ -> raise Exit done; if Hashtbl.mem Lexer.keywords s then raise Exit; - s + true with Exit -> - quoted_ident_prefix ^ s + false + in + s,is_quoted,is_valid let cache = ref (DynArray.create()) let last_doc = ref None let use_doc = ref false +let use_parser_resume = ref true let resume_display = ref null_pos let in_macro = ref false @@ -78,9 +88,16 @@ let do_resume() = !resume_display <> null_pos let display e = raise (Display e) +let type_path sl in_import = match sl with + | n :: l when n.[0] >= 'A' && n.[0] <= 'Z' -> raise (TypePath (List.rev l,Some (n,false),in_import)); + | _ -> raise (TypePath (List.rev sl,None,in_import)) + let is_resuming p = let p2 = !resume_display in - p.pmax = p2.pmin && Common.unique_full_path p.pfile = p2.pfile + p.pmax = p2.pmin && !use_parser_resume && Common.unique_full_path p.pfile = p2.pfile + +let set_resume p = + resume_display := { p with pfile = Common.unique_full_path p.pfile } let is_dollar_ident e = match fst e with | EConst (Ident n) when n.[0] = '$' -> @@ -212,12 +229,17 @@ let reify in_macro = ) in mk_enum "TypeParam" n [v] p and to_tpath t p = - let fields = [ - ("pack", to_array to_string t.tpackage p); - ("name", to_string t.tname p); - ("params", to_array to_tparam t.tparams p); - ] in - to_obj (match t.tsub with None -> fields | Some s -> fields @ ["sub",to_string s p]) p + let len = String.length t.tname in + if t.tpackage = [] && len > 1 && t.tname.[0] = '$' then + (EConst (Ident (String.sub t.tname 1 (len - 1))),p) + else begin + let fields = [ + ("pack", to_array to_string t.tpackage p); + ("name", to_string t.tname p); + ("params", to_array to_tparam t.tparams p); + ] in + to_obj (match t.tsub with None -> fields | Some s -> fields @ ["sub",to_string s p]) p + end and to_ctype t p = let ct n vl = mk_enum "ComplexType" n vl p in match t with @@ -227,7 +249,7 @@ let reify in_macro = | CTFunction (args,ret) -> ct "TFunction" [to_array to_ctype args p; to_ctype ret p] | CTAnonymous fields -> ct "TAnonymous" [to_array to_cfield fields p] | CTParent t -> ct "TParent" [to_ctype t p] - | CTExtend (t,fields) -> ct "TExtend" [to_tpath t p; to_array to_cfield fields p] + | CTExtend (tl,fields) -> ct "TExtend" [to_array to_tpath tl p; to_array to_cfield fields p] | CTOptional t -> ct "TOptional" [to_ctype t p] and to_fun f p = let farg (n,o,t,e) p = @@ -303,7 +325,7 @@ let reify in_macro = let pmin = (EConst (Int (string_of_int p.pmin)),p) in let pmax = (EConst (Int (string_of_int p.pmax)),p) in if in_macro then - (EUntyped (ECall ((EConst (Ident "$mk_pos"),p),[file;pmin;pmax]),p),p) + (EUntyped (ECall ((EConst (Ident "__dollar__mk_pos"),p),[file;pmin;pmax]),p),p) else to_obj [("file",file);("min",pmin);("max",pmax)] p and to_expr_array a p = match a with @@ -356,7 +378,20 @@ let reify in_macro = to_obj fields p ) vl p] | EFunction (name,f) -> - expr "EFunction" [to_opt to_string name p; to_fun f p] + let name = match name with + | None -> + to_null p + | Some name -> + if ExtString.String.starts_with name "inline_$" then begin + let real_name = (String.sub name 7 (String.length name - 7)) in + let e_name = to_string real_name p in + let e_inline = to_string "inline_" p in + let e_add = (EBinop(OpAdd,e_inline,e_name),p) in + e_add + end else + to_string name p + in + expr "EFunction" [name; to_fun f p] | EBlock el -> expr "EBlock" [to_expr_array el p] | EFor (e1,e2) -> @@ -407,11 +442,16 @@ let reify in_macro = expr "EBlock" [e1] (* TODO: can $v and $i be implemented better? *) | Meta.Dollar "v", _ -> - (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e; to_pos (pos e)]),p) + begin match fst e1 with + | EParenthesis (ECheckType (e2, CTPath{tname="String";tpackage=[]}),_) -> expr "EConst" [mk_enum "Constant" "CString" [e2] (pos e2)] + | EParenthesis (ECheckType (e2, CTPath{tname="Int";tpackage=[]}),_) -> expr "EConst" [mk_enum "Constant" "CInt" [e2] (pos e2)] + | EParenthesis (ECheckType (e2, CTPath{tname="Float";tpackage=[]}),_) -> expr "EConst" [mk_enum "Constant" "CFloat" [e2] (pos e2)] + | _ -> (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e; to_pos (pos e)]),p) + end | Meta.Dollar "i", _ -> expr "EConst" [mk_enum "Constant" "CIdent" [e1] (pos e1)] | Meta.Dollar "p", _ -> - (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"ExprTools"),p),"toFieldExpr"),p),[e]),p) + (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"MacroStringTools"),p),"toFieldExpr"),p),[e]),p) | Meta.Custom ":pos", [pexpr] -> let old = !cur_pos in cur_pos := Some pexpr; @@ -478,10 +518,12 @@ let dollar_ident_macro pack = parser | [< '(Const (Ident i),p) >] -> i,p | [< '(Dollar i,p) >] -> ("$" ^ i),p | [< '(Kwd Macro,p) when pack <> [] >] -> "macro", p + | [< '(Kwd Extern,p) when pack <> [] >] -> "extern", p let lower_ident_or_macro = parser | [< '(Const (Ident i),p) when is_lower_ident i >] -> i | [< '(Kwd Macro,_) >] -> "macro" + | [< '(Kwd Extern,_) >] -> "extern" let any_enum_ident = parser | [< i = ident >] -> i @@ -522,7 +564,11 @@ let semicolon s = let rec parse_file s = last_doc := None; match s with parser - | [< '(Kwd Package,_); p = parse_package; _ = semicolon; l = parse_type_decls p []; '(Eof,_) >] -> p , l + | [< '(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 + | [< _ = semicolon; l = parse_type_decls pack []; '(Eof,_) >] -> pack , l + end | [< l = parse_type_decls [] []; '(Eof,_) >] -> [] , l and parse_type_decls pack acc s = @@ -530,17 +576,17 @@ and parse_type_decls pack acc s = match s with parser | [< v = parse_type_decl; l = parse_type_decls pack (v :: acc) >] -> l | [< >] -> List.rev acc - with TypePath ([],Some (name,false)) -> + with TypePath ([],Some (name,false),b) -> (* resolve imports *) List.iter (fun d -> match fst d with | EImport (t,_) -> (match List.rev t with - | (n,_) :: path when n = name && List.for_all (fun (i,_) -> is_lower_ident i) path -> raise (TypePath (List.map fst (List.rev path),Some (name,false))) + | (n,_) :: path when n = name && List.for_all (fun (i,_) -> is_lower_ident i) path -> raise (TypePath (List.map fst (List.rev path),Some (name,false),b)) | _ -> ()) | _ -> () ) acc; - raise (TypePath (pack,Some(name,true))) + raise (TypePath (pack,Some(name,true),b)) and parse_type_decl s = match s with parser @@ -593,7 +639,7 @@ and parse_type_decl s = and parse_class doc meta cflags need_name s = let opt_name = if need_name then type_name else (fun s -> match popt type_name s with None -> "" | Some n -> n) in match s with parser - | [< n , p1 = parse_class_flags; name = opt_name; tl = parse_constraint_params; hl = psep Comma parse_class_herit; '(BrOpen,_); fl, p2 = parse_class_fields false p1 >] -> + | [< n , p1 = parse_class_flags; name = opt_name; tl = parse_constraint_params; hl = psep Comma parse_class_herit; '(BrOpen,_); fl, p2 = parse_class_fields (not need_name) p1 >] -> (EClass { d_name = name; d_doc = doc; @@ -607,22 +653,30 @@ and parse_import s p1 = let rec loop acc = match s with parser | [< '(Dot,p) >] -> - if is_resuming p then raise (TypePath (List.rev (List.map fst acc),None)); + let resume() = + type_path (List.map fst acc) true + in + if is_resuming p then resume(); (match s with parser | [< '(Const (Ident k),p) >] -> loop ((k,p) :: acc) | [< '(Kwd Macro,p) >] -> loop (("macro",p) :: acc) + | [< '(Kwd Extern,p) >] -> + loop (("extern",p) :: acc) | [< '(Binop OpMult,_); '(Semicolon,p2) >] -> p2, List.rev acc, IAll | [< '(Binop OpOr,_) when do_resume() >] -> - raise (TypePath (List.rev (List.map fst acc),None)) + set_resume p; + resume() | [< >] -> serror()); | [< '(Semicolon,p2) >] -> p2, List.rev acc, INormal | [< '(Kwd In,_); '(Const (Ident name),_); '(Semicolon,p2) >] -> p2, List.rev acc, IAsName name + | [< '(Const (Ident "as"),_); '(Const (Ident name),_); '(Semicolon,p2) >] -> + p2, List.rev acc, IAsName name | [< >] -> serror() in @@ -695,6 +749,9 @@ and parse_class_field_resume tdecl s = in let rec loop k = match List.rev_map fst (Stream.npeek k s) with + (* metadata *) + | Kwd _ :: At :: _ | Kwd _ :: DblDot :: At :: _ -> + loop (k + 1) (* field declaration *) | Const _ :: Kwd Function :: _ | Kwd New :: Kwd Function :: _ -> @@ -722,8 +779,21 @@ and parse_common_flags = parser | [< '(Kwd Extern,_); l = parse_common_flags >] -> (HExtern, EExtern) :: l | [< >] -> [] +and parse_meta_argument_expr s = + try + expr s + with Display e -> match fst e with + | EDisplay(e,_) -> + begin try + type_path (string_list_of_expr_path_raise e) false + with Exit -> + e + end + | _ -> + e + and parse_meta_params pname s = match s with parser - | [< '(POpen,p) when p.pmin = pname.pmax; params = psep Comma expr; '(PClose,_); >] -> params + | [< '(POpen,p) when p.pmin = pname.pmax; params = psep Comma parse_meta_argument_expr; '(PClose,_); >] -> params | [< >] -> [] and parse_meta_entry = parser @@ -748,24 +818,31 @@ and parse_class_flags = parser | [< '(Kwd Class,p) >] -> [] , p | [< '(Kwd Interface,p) >] -> [HInterface] , p +and parse_type_hint = parser + | [< '(DblDot,_); t = parse_complex_type >] -> t + and parse_type_opt = parser - | [< '(DblDot,_); t = parse_complex_type >] -> Some t + | [< t = parse_type_hint >] -> Some t | [< >] -> None and parse_complex_type s = let t = parse_complex_type_inner s in parse_complex_type_next t s +and parse_structural_extension = parser + | [< '(Binop OpGt,_); t = parse_type_path; '(Comma,_); s >] -> + t + and parse_complex_type_inner = parser | [< '(POpen,_); t = parse_complex_type; '(PClose,_) >] -> CTParent t | [< '(BrOpen,p1); s >] -> (match s with parser | [< l = parse_type_anonymous false >] -> CTAnonymous l - | [< '(Binop OpGt,_); t = parse_type_path; '(Comma,_); s >] -> + | [< t = parse_structural_extension; s>] -> + let tl = t :: plist parse_structural_extension s in (match s with parser - | [< l = parse_type_anonymous false >] -> CTExtend (t,l) - | [< l, _ = parse_class_fields true p1 >] -> CTExtend (t,l) - | [< >] -> serror()) + | [< l = parse_type_anonymous false >] -> CTExtend (tl,l) + | [< l, _ = parse_class_fields true p1 >] -> CTExtend (tl,l)) | [< l, _ = parse_class_fields true p1 >] -> CTAnonymous l | [< >] -> serror()) | [< '(Question,_); t = parse_complex_type_inner >] -> @@ -781,7 +858,7 @@ and parse_type_path1 pack = parser (match s with parser | [< '(Dot,p) >] -> if is_resuming p then - raise (TypePath (List.rev (name :: pack),None)) + raise (TypePath (List.rev (name :: pack),None,false)) else parse_type_path1 (name :: pack) s | [< '(Semicolon,_) >] -> @@ -791,11 +868,12 @@ and parse_type_path1 pack = parser let sub = (match s with parser | [< '(Dot,p); s >] -> (if is_resuming p then - raise (TypePath (List.rev pack,Some (name,false))) + raise (TypePath (List.rev pack,Some (name,false),false)) else match s with parser | [< '(Const (Ident name),_) when not (is_lower_ident name) >] -> Some name | [< '(Binop OpOr,_) when do_resume() >] -> - raise (TypePath (List.rev pack,Some (name,false))) + set_resume p; + raise (TypePath (List.rev pack,Some (name,false),false)) | [< >] -> serror()) | [< >] -> None ) in @@ -810,7 +888,7 @@ and parse_type_path1 pack = parser tsub = sub; } | [< '(Binop OpOr,_) when do_resume() >] -> - raise (TypePath (List.rev pack,None)) + raise (TypePath (List.rev pack,None,false)) and type_name = parser | [< '(Const (Ident name),p) >] -> @@ -818,6 +896,7 @@ and type_name = parser error (Custom "Type name should start with an uppercase letter") p else name + | [< '(Dollar name,_) >] -> "$" ^ name and parse_type_path_or_const = parser (* we can't allow (expr) here *) @@ -838,12 +917,8 @@ and parse_complex_type_next t = parser and parse_type_anonymous opt = parser | [< '(Question,_) when not opt; s >] -> parse_type_anonymous true s - | [< name, p1 = ident; '(DblDot,_); t = parse_complex_type; s >] -> + | [< name, p1 = ident; t = parse_type_hint; s >] -> let next p2 acc = - let t = if not opt then t else (match t with - | CTPath { tpackage = []; tname = "Null" } -> t - | _ -> CTPath { tpackage = []; tname = "Null"; tsub = None; tparams = [TPType t] } - ) in { cff_name = name; cff_meta = if opt then [Meta.Optional,[],p1] else []; @@ -871,10 +946,7 @@ and parse_enum s = | [< '(POpen,_); l = psep Comma parse_enum_param; '(PClose,_) >] -> l | [< >] -> [] ) in - let t = (match s with parser - | [< '(DblDot,_); t = parse_complex_type >] -> Some t - | [< >] -> None - ) in + let t = parse_type_opt s in let p2 = (match s with parser | [< p = semicolon >] -> p | [< >] -> serror() @@ -890,21 +962,18 @@ and parse_enum s = } and parse_enum_param = parser - | [< '(Question,_); name, _ = ident; '(DblDot,_); t = parse_complex_type >] -> (name,true,t) - | [< name, _ = ident; '(DblDot,_); t = parse_complex_type >] -> (name,false,t) + | [< '(Question,_); name, _ = ident; t = parse_type_hint >] -> (name,true,t) + | [< name, _ = ident; t = parse_type_hint >] -> (name,false,t) and parse_class_field s = let doc = get_doc s in match s with parser | [< meta = parse_meta; al = parse_cf_rights true []; s >] -> let name, pos, k = (match s with parser - | [< '(Kwd Var,p1); name, _ = ident; s >] -> + | [< '(Kwd Var,p1); name, _ = dollar_ident; s >] -> (match s with parser | [< '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_) >] -> - let t = (match s with parser - | [< '(DblDot,_); t = parse_complex_type >] -> Some t - | [< >] -> None - ) in + let t = parse_type_opt s in let e , p2 = (match s with parser | [< '(Binop OpAssign,_); e = toplevel_expr; p2 = semicolon >] -> Some e , p2 | [< '(Semicolon,p2) >] -> None , p2 @@ -956,20 +1025,20 @@ and parse_cf_rights allow_static l = parser | [< >] -> l and parse_fun_name = parser - | [< '(Const (Ident name),_) >] -> name + | [< name,_ = dollar_ident >] -> name | [< '(Kwd New,_) >] -> "new" and parse_fun_param = parser - | [< '(Question,_); name, _ = ident; t = parse_type_opt; c = parse_fun_param_value >] -> (name,true,t,c) - | [< name, _ = ident; t = parse_type_opt; c = parse_fun_param_value >] -> (name,false,t,c) + | [< '(Question,_); name, _ = dollar_ident; t = parse_type_opt; c = parse_fun_param_value >] -> (name,true,t,c) + | [< name, _ = dollar_ident; t = parse_type_opt; c = parse_fun_param_value >] -> (name,false,t,c) and parse_fun_param_value = parser | [< '(Binop OpAssign,_); e = toplevel_expr >] -> Some e | [< >] -> None and parse_fun_param_type = parser - | [< '(Question,_); name = ident; '(DblDot,_); t = parse_complex_type >] -> (name,true,t) - | [< name = ident; '(DblDot,_); t = parse_complex_type >] -> (name,false,t) + | [< '(Question,_); name = ident; t = parse_type_hint >] -> (name,true,t) + | [< name = ident; t = parse_type_hint >] -> (name,false,t) and parse_constraint_params = parser | [< '(Binop OpLt,_); l = psep Comma parse_constraint_param; '(Binop OpGt,_) >] -> l @@ -999,7 +1068,7 @@ and parse_class_herit = parser | [< '(Kwd Implements,_); t = parse_type_path >] -> HImplements t and block1 = parser - | [< '(Const (Ident name),p); s >] -> block2 name (Ident name) p s + | [< name,p = dollar_ident; s >] -> block2 name (Ident name) p s | [< '(Const (String name),p); s >] -> block2 (quote_ident name) (String name) p s | [< b = block [] >] -> EBlock b @@ -1029,12 +1098,14 @@ and block acc s = let tk , pos = (match Stream.peek s with None -> last_token s | Some t -> t) in (!display_error) (Unexpected tk) pos; block acc s - | Error (e,p) -> + | Error (e,p) -> (!display_error) e p; block acc s and parse_block_elt = parser - | [< '(Kwd Var,p1); vl = psep Comma parse_var_decl; p2 = semicolon >] -> (EVars vl,punion p1 p2) + | [< '(Kwd Var,p1); vl = parse_var_decls p1; p2 = semicolon >] -> + (EVars vl,punion p1 p2) + | [< '(Kwd Inline,p1); '(Kwd Function,_); e = parse_function p1 true; _ = semicolon >] -> e | [< e = expr; _ = semicolon >] -> e and parse_obj_decl = parser @@ -1053,11 +1124,38 @@ and parse_array_decl = parser | [< >] -> [] +and parse_var_decl_head = parser + | [< name, _ = dollar_ident; t = parse_type_opt >] -> (name,t) + +and parse_var_assignment = parser + | [< '(Binop OpAssign,p1); s >] -> + begin match s with parser + | [< e = expr >] -> Some e + | [< >] -> error (Custom "expression expected after =") p1 + end + | [< >] -> None + +and parse_var_decls_next vl = parser + | [< '(Comma,p1); name,t = parse_var_decl_head; s >] -> + begin try + let eo = parse_var_assignment s in + parse_var_decls_next ((name,t,eo) :: vl) s + with Display e -> + let v = (name,t,Some e) in + let e = (EVars(List.rev (v :: vl)),punion p1 (pos e)) in + display e + end + | [< >] -> + vl + +and parse_var_decls p1 = parser + | [< name,t = parse_var_decl_head; s >] -> + let eo = parse_var_assignment s in + List.rev (parse_var_decls_next [name,t,eo] s) + | [< s >] -> error (Custom "Missing variable identifier") p1 + and parse_var_decl = parser - | [< name, _ = dollar_ident; t = parse_type_opt; s >] -> - match s with parser - | [< '(Binop OpAssign,_); e = expr >] -> (name,t,Some e) - | [< >] -> (name,t,None) + | [< name,t = parse_var_decl_head; eo = parse_var_assignment >] -> (name,t,eo) and inline_function = parser | [< '(Kwd Inline,_); '(Kwd Function,p1) >] -> true, p1 @@ -1081,6 +1179,22 @@ and parse_macro_expr p = parser | [< e = secure_expr >] -> reify_expr e +and parse_function p1 inl = parser + | [< name = popt dollar_ident; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] -> + let make e = + let f = { + f_params = pl; + f_type = t; + f_args = al; + f_expr = Some e; + } in + EFunction ((match name with None -> None | Some (name,_) -> Some (if inl then "inline_" ^ name else name)),f), punion p1 (pos e) + in + (try + expr_next (make (secure_expr s)) s + with + Display e -> display (make e)) + and expr = parser | [< (name,params,p) = parse_meta_entry; s >] -> (try @@ -1102,10 +1216,15 @@ and expr = parser | [< '(Kwd Null,p); s >] -> expr_next (EConst (Ident "null"),p) s | [< '(Kwd Cast,p1); s >] -> (match s with parser - | [< '(POpen,_); e = expr; s >] -> + | [< '(POpen,pp); e = expr; s >] -> (match s with parser | [< '(Comma,_); t = parse_complex_type; '(PClose,p2); s >] -> expr_next (ECast (e,Some t),punion p1 p2) s - | [< '(PClose,p2); s >] -> expr_next (ECast (e,None),punion p1 (pos e)) s + | [< t = parse_type_hint; '(PClose,p2); s >] -> + let ep = EParenthesis (ECheckType(e,t),punion p1 p2), punion p1 p2 in + expr_next (ECast (ep,None),punion p1 (pos ep)) s + | [< '(PClose,p2); s >] -> + let ep = expr_next (EParenthesis(e),punion pp p2) s in + expr_next (ECast (ep,None),punion p1 (pos ep)) s | [< >] -> serror()) | [< e = secure_expr >] -> expr_next (ECast (e,None),punion p1 (pos e)) s) | [< '(Kwd Throw,p); e = expr >] -> (EThrow e,p) @@ -1114,22 +1233,12 @@ and expr = parser (match s with parser | [< al = psep Comma expr; '(PClose,p2); s >] -> expr_next (ENew (t,al),punion p1 p2) s | [< >] -> serror()) - | [< '(POpen,p1); e = expr; '(PClose,p2); s >] -> expr_next (EParenthesis e, punion p1 p2) s + | [< '(POpen,p1); e = expr; s >] -> (match s with parser + | [< '(PClose,p2); s >] -> expr_next (EParenthesis e, punion p1 p2) s + | [< t = parse_type_hint; '(PClose,p2); s >] -> expr_next (EParenthesis (ECheckType(e,t),punion p1 p2), punion p1 p2) s + | [< >] -> serror()) | [< '(BkOpen,p1); l = parse_array_decl; '(BkClose,p2); s >] -> expr_next (EArrayDecl l, punion p1 p2) s - | [< inl, p1 = inline_function; name = popt dollar_ident; pl = parse_constraint_params; '(POpen,_); al = psep Comma parse_fun_param; '(PClose,_); t = parse_type_opt; s >] -> - let make e = - let f = { - f_params = pl; - f_type = t; - f_args = al; - f_expr = Some e; - } in - EFunction ((match name with None -> None | Some (name,_) -> Some (if inl then "inline_" ^ name else name)),f), punion p1 (pos e) - in - (try - expr_next (make (secure_expr s)) s - with - Display e -> display (make e)) + | [< '(Kwd Function,p1); e = parse_function p1 false; >] -> e | [< '(Unop op,p1) when is_prefix op; e = expr >] -> make_unop op e p1 | [< '(Binop OpSub,p1); e = expr >] -> let neg s = @@ -1176,13 +1285,13 @@ and expr = parser Display e -> display (EWhile (cond,e,NormalWhile),punion p1 (pos e))) | [< '(Kwd Do,p1); e = expr; '(Kwd While,_); '(POpen,_); cond = expr; '(PClose,_); s >] -> (EWhile (cond,e,DoWhile),punion p1 (pos e)) | [< '(Kwd Switch,p1); e = expr; '(BrOpen,_); cases , def = parse_switch_cases e []; '(BrClose,p2); s >] -> (ESwitch (e,cases,def),punion p1 p2) - | [< '(Kwd Try,p1); e = expr; cl = plist (parse_catch e); s >] -> (ETry (e,cl),p1) + | [< '(Kwd Try,p1); e = expr; cl = plist (parse_catch e); >] -> (ETry (e,cl),p1) | [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int i),p1) e2 | [< '(Kwd Untyped,p1); e = expr >] -> (EUntyped e,punion p1 (pos e)) | [< '(Dollar v,p); s >] -> expr_next (EConst (Ident ("$"^v)),p) s and expr_next e1 = parser - | [< '(BrOpen,p1) when is_dollar_ident e1; eparam = expr; '(BrClose,p2); s >] -> + | [< '(BrOpen,p1) when is_dollar_ident e1; eparam = expr; '(BrClose,p2); s >] -> (match fst e1 with | EConst(Ident n) -> expr_next (EMeta((Common.MetaInfo.from_string n,[],snd e1),eparam), punion p1 p2) s | _ -> assert false) @@ -1190,9 +1299,12 @@ and expr_next e1 = parser if is_resuming p then display (EDisplay (e1,false),p); (match s with parser | [< '(Kwd Macro,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"macro") , punion (pos e1) p2) s + | [< '(Kwd New,p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,"new") , punion (pos e1) p2) s | [< '(Const (Ident f),p2) when p.pmax = p2.pmin; s >] -> expr_next (EField (e1,f) , punion (pos e1) p2) s | [< '(Dollar v,p2); s >] -> expr_next (EField (e1,"$"^v) , punion (pos e1) p2) s - | [< '(Binop OpOr,p2) when do_resume() >] -> display (EDisplay (e1,false),p) (* help for debug display mode *) + | [< '(Binop OpOr,p2) when do_resume() >] -> + set_resume p; + display (EDisplay (e1,false),p) (* help for debug display mode *) | [< >] -> (* turn an integer followed by a dot into a float *) match e1 with @@ -1201,27 +1313,34 @@ and expr_next e1 = parser | [< '(POpen,p1); s >] -> if is_resuming p1 then display (EDisplay (e1,true),p1); (match s with parser - | [< '(Binop OpOr,p2) when do_resume() >] -> display (EDisplay (e1,true),p1) (* help for debug display mode *) + | [< '(Binop OpOr,p2) when do_resume() >] -> + set_resume p1; + display (EDisplay (e1,true),p1) (* help for debug display mode *) | [< params = parse_call_params e1; '(PClose,p2); s >] -> expr_next (ECall (e1,params) , punion (pos e1) p2) s | [< >] -> serror()) | [< '(BkOpen,_); e2 = expr; '(BkClose,p2); s >] -> expr_next (EArray (e1,e2), punion (pos e1) p2) s - | [< '(Binop OpGt,_); s >] -> + | [< '(Binop OpGt,p1); s >] -> (match s with parser - | [< '(Binop OpGt,_); s >] -> + | [< '(Binop OpGt,p2) when p1.pmax = p2.pmin; s >] -> (match s with parser - | [< '(Binop OpGt,_) >] -> + | [< '(Binop OpGt,p3) when p2.pmax = p3.pmin >] -> (match s with parser - | [< '(Binop OpAssign,_); e2 = expr >] -> make_binop (OpAssignOp OpUShr) e1 e2 + | [< '(Binop OpAssign,p4) when p3.pmax = p4.pmin; e2 = expr >] -> make_binop (OpAssignOp OpUShr) e1 e2 | [< e2 = secure_expr >] -> make_binop OpUShr e1 e2) - | [< '(Binop OpAssign,_); e2 = expr >] -> make_binop (OpAssignOp OpShr) e1 e2 + | [< '(Binop OpAssign,p3) when p2.pmax = p3.pmin; e2 = expr >] -> make_binop (OpAssignOp OpShr) e1 e2 | [< e2 = secure_expr >] -> make_binop OpShr e1 e2) - | [< '(Binop OpAssign,_); s >] -> + | [< '(Binop OpAssign,p2) when p1.pmax = p2.pmin; s >] -> make_binop OpGte e1 (secure_expr s) | [< e2 = secure_expr >] -> make_binop OpGt e1 e2) - | [< '(Binop op,_); e2 = expr >] -> - make_binop op e1 e2 + | [< '(Binop op,_); s >] -> + (try + (match s with parser + | [< e2 = expr >] -> make_binop op e1 e2 + | [< >] -> serror()) + with Display e2 -> + raise (Display (make_binop op e1 e2))) | [< '(Unop op,p) when is_postfix e1 op; s >] -> expr_next (EUnop (op,Postfix,e1), punion (pos e1) p) s | [< '(Question,_); e2 = expr; '(DblDot,_); e3 = expr >] -> @@ -1245,19 +1364,23 @@ and parse_switch_cases eswitch cases = parser (match def with None -> () | Some _ -> error Duplicate_default p1); l , Some b | [< '(Kwd Case,p1); el = psep Comma expr; eg = popt parse_guard; '(DblDot,_); s >] -> - let b = (try block [] s with Display e -> display (ESwitch (eswitch,List.rev ((el,eg,Some e) :: cases),None),punion (pos eswitch) (pos e))) in - let b = match b with - | [] -> None - | _ -> Some ((EBlock b,p1)) - in - parse_switch_cases eswitch ((el,eg,b) :: cases) s + (match el with + | [] -> error (Custom "case without a pattern is not allowed") p1 + | _ -> + let b = (try block [] s with Display e -> display (ESwitch (eswitch,List.rev ((el,eg,Some e) :: cases),None),punion (pos eswitch) (pos e))) in + let b = match b with + | [] -> None + | _ -> Some ((EBlock b,p1)) + in + parse_switch_cases eswitch ((el,eg,b) :: cases) s + ) | [< >] -> List.rev cases , None and parse_catch etry = parser - | [< '(Kwd Catch,p); '(POpen,_); name, _ = ident; s >] -> + | [< '(Kwd Catch,p); '(POpen,_); name, _ = dollar_ident; s >] -> match s with parser - | [< '(DblDot,_); t = parse_complex_type; '(PClose,_); s >] -> + | [< t = parse_type_hint; '(PClose,_); s >] -> (try (name,t,secure_expr s) with @@ -1335,12 +1458,56 @@ and secure_expr s = | [< e = expr >] -> e | [< >] -> serror() +(* eval *) type small_type = | TNull | TBool of bool | TFloat of float | TString of string +let is_true = function + | TBool false | TNull | TFloat 0. | TString "" -> false + | _ -> true + +let cmp v1 v2 = + match v1, v2 with + | TNull, TNull -> 0 + | TFloat a, TFloat b -> compare a b + | TString a, TString b -> compare a b + | TBool a, TBool b -> compare a b + | TString a, TFloat b -> compare (float_of_string a) b + | TFloat a, TString b -> compare a (float_of_string b) + | _ -> raise Exit (* always false *) + +let rec eval ctx (e,p) = + match e with + | EConst (Ident i) -> + (try TString (Common.raw_defined_value ctx i) with Not_found -> TNull) + | EConst (String s) -> TString s + | EConst (Int i) -> TFloat (float_of_string i) + | EConst (Float f) -> TFloat (float_of_string f) + | EBinop (OpBoolAnd, e1, e2) -> TBool (is_true (eval ctx e1) && is_true (eval ctx e2)) + | EBinop (OpBoolOr, e1, e2) -> TBool (is_true (eval ctx e1) || is_true(eval ctx e2)) + | EUnop (Not, _, e) -> TBool (not (is_true (eval ctx e))) + | EParenthesis e -> eval ctx e + | EBinop (op, e1, e2) -> + let v1 = eval ctx e1 in + let v2 = eval ctx e2 in + let compare op = + TBool (try op (cmp v1 v2) 0 with _ -> false) + in + (match op with + | OpEq -> compare (=) + | OpNotEq -> compare (<>) + | OpGt -> compare (>) + | OpGte -> compare (>=) + | OpLt -> compare (<) + | OpLte -> compare (<=) + | _ -> error (Custom "Unsupported operation") p) + | _ -> + error (Custom "Invalid condition expression") p + +(* parse main *) let parse ctx code = let old = Lexer.save() in let old_cache = !cache in @@ -1393,51 +1560,9 @@ let parse ctx code = tk and enter_macro p = - let is_true = function - | TBool false | TNull | TFloat 0. | TString "" -> false - | _ -> true - in - let cmp v1 v2 = - match v1, v2 with - | TNull, TNull -> 0 - | TFloat a, TFloat b -> compare a b - | TString a, TString b -> compare a b - | TBool a, TBool b -> compare a b - | TString a, TFloat b -> compare (float_of_string a) b - | TFloat a, TString b -> compare a (float_of_string b) - | _ -> raise Exit (* always false *) - in - let rec loop (e,p) = - match e with - | EConst (Ident i) -> - (try TString (Common.raw_defined_value ctx i) with Not_found -> TNull) - | EConst (String s) -> TString s - | EConst (Int i) -> TFloat (float_of_string i) - | EConst (Float f) -> TFloat (float_of_string f) - | EBinop (OpBoolAnd, e1, e2) -> TBool (is_true (loop e1) && is_true (loop e2)) - | EBinop (OpBoolOr, e1, e2) -> TBool (is_true (loop e1) || is_true(loop e2)) - | EUnop (Not, _, e) -> TBool (not (is_true (loop e))) - | EParenthesis e -> loop e - | EBinop (op, e1, e2) -> - let v1 = loop e1 in - let v2 = loop e2 in - let compare op = - TBool (try op (cmp v1 v2) 0 with _ -> false) - in - (match op with - | OpEq -> compare (=) - | OpNotEq -> compare (<>) - | OpGt -> compare (>) - | OpGte -> compare (>=) - | OpLt -> compare (<) - | OpLte -> compare (<=) - | _ -> error (Custom "Unsupported operation") p) - | _ -> - error Unclosed_macro p - in let tk, e = parse_macro_cond false sraw in let tk = (match tk with None -> Lexer.token code | Some tk -> tk) in - if is_true (loop e) || (match fst e with EConst (Ident "macro") when Common.unique_full_path p.pfile = (!resume_display).pfile -> true | _ -> false) then begin + if is_true (eval ctx e) || (match fst e with EConst (Ident "macro") when Common.unique_full_path p.pfile = (!resume_display).pfile -> true | _ -> false) then begin mstack := p :: !mstack; tk end else diff --git a/std/Array.hx b/std/Array.hx index bc26d1db9a1d7a1e9cb82da15aa840b43efb8fe6..2645f92214f68d50f5ec7dee8a89ed0ca413286c 100644 --- a/std/Array.hx +++ b/std/Array.hx @@ -21,13 +21,12 @@ */ /** An Array is a storage for values. You can access it using indexes or - with its API. On the server side, it's often better to use a [List] which - is less memory and CPU consuming, unless you really need indexed access. + with its API. **/ extern class Array { /** - The length of [this] Array. + The length of `this` Array. **/ var length(default,null) : Int; @@ -37,141 +36,141 @@ extern class Array { function new() : Void; /** - Returns a new Array by appending the elements of [a] to the elements of - [this] Array. - - This operation does not modify [this] Array. - - If [a] is the empty Array [], a copy of [this] Array is returned. - - The length of the returned Array is equal to the sum of [this].length - and [a].length. - - If [a] is null, the result is unspecified. + Returns a new Array by appending the elements of `a` to the elements of + `this` Array. + + This operation does not modify `this` Array. + + If `a` is the empty Array `[]`, a copy of `this` Array is returned. + + The length of the returned Array is equal to the sum of `this.length` + and `a.length`. + + If `a` is `null`, the result is unspecified. **/ function concat( a : Array ) : Array; /** - Returns a string representation of [this] Array, with [sep] separating + Returns a string representation of `this` Array, with `sep` separating each element. - - The result of this operation is equal to Std.string(this[0]) + sep + - Std.string(this[1]) + sep + ... + sep + Std.string(this[this.length-1]). - - If [this] is the empty Array [], the result is the empty String "". If - [this] has exactly one element, the result is equal to a call to - Std.string(this[0]). - - If [sep] is null, the result is unspecified. + + The result of this operation is equal to `Std.string(this[0]) + sep + + Std.string(this[1]) + sep + ... + sep + Std.string(this[this.length-1])` + + If `this` is the empty Array `[]`, the result is the empty String `""`. + If `this` has exactly one element, the result is equal to a call to + `Std.string(this[0])`. + + If `sep` is null, the result is unspecified. **/ function join( sep : String ) : String; /** - Removes the last element of [this] Array and returns it. - - This operation modifies [this] Array in place. - - If [this] has at least one element, [this].length will decrease by 1. - - If [this] is the empty Array [], null is returned and the length remains - 0. + Removes the last element of `this` Array and returns it. + + This operation modifies `this` Array in place. + + If `this` has at least one element, `this.length` will decrease by 1. + + If `this` is the empty Array `[]`, null is returned and the length + remains 0. **/ function pop() : Null; /** - Adds the element [x] at the end of [this] Array and returns the offset - it was added at. - - This operation modifies [this] Array in place. - - [this].length increases by 1. + Adds the element `x` at the end of `this` Array and returns the new + length of `this` Array. + + This operation modifies `this` Array in place. + + `this.length` increases by 1. **/ function push(x : T) : Int; /** - Reverse the order of elements of [this] Array. - - This operation modifies [this] Array in place. - - If [this].length < 2, [this] remains unchanged. + Reverse the order of elements of `this` Array. + + This operation modifies `this` Array in place. + + If `this.length < 2`, `this` remains unchanged. **/ function reverse() : Void; /** - Removes the first element of [this] Array and returns it. - - This operation modifies [this] Array in place. - - If [this] has at least one element, [this].length and the index of each + Removes the first element of `this` Array and returns it. + + This operation modifies `this` Array in place. + + If `this` has at least one element, `this`.length and the index of each remaining element is decreased by 1. - - If [this] is the empty Array [], null is returned and the length remains - 0. + + If `this` is the empty Array `[]`, `null` is returned and the length + remains 0. **/ function shift() : Null; /** - Creates a shallow copy of the range of [this] Array, starting at and - including [pos], up to but not including [end]. - - This operation does not modify [this] Array. - + Creates a shallow copy of the range of `this` Array, starting at and + including `pos`, up to but not including `end`. + + This operation does not modify `this` Array. + The elements are not copied and retain their identity. - - If [end] is omitted or exceeds [this].length, it defaults to the end of - [this] Array. - - If [pos] or [end] are negative, their offsets are calculated from the - end of [this] Array by [this].length + [pos] and [this].length + [end] + + If `end` is omitted or exceeds `this.length`, it defaults to the end of + `this` Array. + + If `pos` or `end` are negative, their offsets are calculated from the + end of `this` Array by `this.length + pos` and `this.length + end` respectively. If this yields a negative value, 0 is used instead. - - If [pos] exceeds [this].length or if [end} exceeds or equals [pos], - the result is []. + + If `pos` exceeds `this.length` or if `end` exceeds or equals `pos`, + the result is `[]`. **/ function slice( pos : Int, ?end : Int ) : Array; /** - Sorts [this] Array according to the comparison function [f], where - [f(x,y)] returns 0 if x == y, a positive Int if x > y and a + Sorts `this` Array according to the comparison function `f`, where + `f(x,y)` returns 0 if x == y, a positive Int if x > y and a negative Int if x < y. - - This operation modifies [this] Array in place. - + + This operation modifies `this` Array in place. + The sort operation is not guaranteed to be stable, which means that the order of equal elements may not be retained. For a stable Array sorting - algorithm, haxe.ds.sort.MergeSort.sort() can be used instead. - - If [f] is null, the result is unspecified. + algorithm, `haxe.ds.ArraySort.sort()` can be used instead. + + If `f` is null, the result is unspecified. **/ function sort( f : T -> T -> Int ) : Void; /** - Removes [len] elements from [this] Array, starting at and including - [pos], an returns them. - - This operation modifies [this] Array in place. - - If [len] is < 0 or [pos] exceeds [this].length, the result is the empty + Removes `len` elements from `this` Array, starting at and including + `pos`, an returns them. + + This operation modifies `this` Array in place. + + If `len` is < 0 or `pos` exceeds `this`.length, the result is the empty Array []. - - If [pos] is negative, its value is calculated from the end of [this] - Array by [this].length + [pos]. If this yields a negative value, 0 is + + If `pos` is negative, its value is calculated from the end of `this` + Array by `this.length + pos`. If this yields a negative value, 0 is used instead. - - If the sum of the resulting values for [len] and [pos] exceed - [this].length, this operation will affect the elements from [pos] to the - end of [this] Array. - - The length of the returned Array is equal to the new length of [this] - Array subtracted from the original length of [this] Array. In other - words, each element of the original [this] Array either remains in - [this] Array or becomes an element of the returned Array. + + If the sum of the resulting values for `len` and `pos` exceed + `this.length`, this operation will affect the elements from `pos` to the + end of `this` Array. + + The length of the returned Array is equal to the new length of `this` + Array subtracted from the original length of `this` Array. In other + words, each element of the original `this` Array either remains in + `this` Array or becomes an element of the returned Array. **/ function splice( pos : Int, len : Int ) : Array; /** - Returns a string representation of [this] Array. - + Returns a string representation of `this` Array. + The result will include the individual elements' String representations separated by comma. The enclosing [ ] may be missing on some platforms, use Std.string() to get a String representation that is consistent @@ -180,53 +179,83 @@ extern class Array { function toString() : String; /** - Adds the element [x] at the start of [this] Array. - - This operation modifies [this] Array in place. - - [this].length and the index of each Array element increases by 1. + Adds the element `x` at the start of `this` Array. + + This operation modifies `this` Array in place. + + `this.length` and the index of each Array element increases by 1. **/ function unshift( x : T ) : Void; /** - Inserts the element [x] at the position [pos]. - - This operation modifies [this] Array in place. - + Inserts the element `x` at the position `pos`. + + This operation modifies `this` Array in place. + The offset is calculated like so: - - - If [pos] exceeds [this].length, the offset is [this].length. - - If [pos] is negative, the offset is calculated from the end of [this] - Array, i.e. [this].length + [pos]. If this yields a negative value, - the offset is 0. - - Otherwise, the offset is [pos]. - - If the resulting offset does not exceed [this].length, all elements from - and including that offset to the end of [this] Array are moved one index + + - If `pos` exceeds `this.length`, the offset is `this.length`. + - If `pos` is negative, the offset is calculated from the end of `this` + Array, i.e. `this.length + pos`. If this yields a negative value, the + offset is 0. + - Otherwise, the offset is `pos`. + + If the resulting offset does not exceed `this.length`, all elements from + and including that offset to the end of `this` Array are moved one index ahead. **/ function insert( pos : Int, x : T ) : Void; /** - Removes the first occurence of [x] in [this] Array. - - This operation modifies [this] Array in place. - - If [x] is found by checking standard equality, it is removed from [this] + Removes the first occurence of `x` in `this` Array. + + This operation modifies `this` Array in place. + + If `x` is found by checking standard equality, it is removed from `this` Array and all following elements are reindexed acoordingly. The function then returns true. - - If [x] is not found, [this] Array is not changed and the function + + If `x` is not found, `this` Array is not changed and the function returns false. **/ function remove( x : T ) : Bool; /** - Returns a shallow copy of [this] Array. - + Returns position of the first occurense of `x` in `this` Array, searching front to back. + + If `x` is found by checking standard equality, the function returns its index. + + If `x` is not found, the function returns -1. + + If `fromIndex` is specified, it will be used as the starting index to search from, + otherwise search starts with zero index. If it is negative, it will be taken as the + offset from the end of `this` Array to compute the starting index. If given or computed + starting index is less than 0, the whole array will be searched, if it is greater than + or equal to the length of `this` Array, the function returns -1. + **/ + function indexOf( x : T, ?fromIndex:Int ) : Int; + + /** + Returns position of the last occurense of `x` in `this` Array, searching back to front. + + If `x` is found by checking standard equality, the function returns its index. + + If `x` is not found, the function returns -1. + + If `fromIndex` is specified, it will be used as the starting index to search from, + otherwise search starts with the last element index. If it is negative, it will be + taken as the offset from the end of `this` Array to compute the starting index. If + given or computed starting index is greater than or equal to the length of `this` Array, + the whole array will be searched, if it is less than 0, the function returns -1. + **/ + function lastIndexOf( x : T, ?fromIndex:Int ) : Int; + + /** + Returns a shallow copy of `this` Array. + The elements are not copied and retain their identity, so - a[i] == a.copy()[i] is true for any valid i. However, a == a.copy() is - always false. + `a[i] == a.copy()[i]` is true for any valid `i`. However, + `a == a.copy()` is always false. **/ function copy() : Array; @@ -235,6 +264,22 @@ extern class Array { **/ function iterator() : Iterator; + /** + Creates a new Array by applying function `f` to all elements of `this`. + + The order of elements is preserved. + + If `f` is null, the result is unspecified. + **/ function map( f : T -> S ) : Array; + + /** + Returns an Array containing those elements of `this` for which `f` + returned true. + + The individual elements are not duplicated and retain their identity. + + If `f` is null, the result is unspecified. + **/ function filter( f : T -> Bool ) : Array; } diff --git a/std/Class.hx b/std/Class.hx index 39b961faf3ca04971ff2bc7713d3c89f1269e81c..6d28bb2f127bd585751f29f19129be878ebd98fa 100644 --- a/std/Class.hx +++ b/std/Class.hx @@ -21,8 +21,8 @@ */ /** An abstract type that represents a Class. - - See [Type] for the haXe Reflection API. + + See `Type` for the Haxe Reflection API. **/ @:coreType @:runtimeValue abstract Class { } diff --git a/std/Date.hx b/std/Date.hx index 480ef5af2cb2712e1070387fe83987753f01bcc3..6fb58a1457c6b48f729d3ed3dbce7a6608d95abb 100644 --- a/std/Date.hx +++ b/std/Date.hx @@ -23,13 +23,14 @@ /** The Date class provides a basic structure for date and time related information. Date instances can be created by - - new Date() for a specific date, - - Date.now() to obtain information about the current time, - - Date.fromTime() with a given timestamp or - - Date.fromString() by parsing from a String. - - There is some extra functions available in the [DateTools] class. - + + - `new Date()` for a specific date, + - `Date.now()` to obtain information about the current time, + - `Date.fromTime()` with a given timestamp or + - `Date.fromString()` by parsing from a String. + + There is some extra functions available in the `DateTools` class. + In the context of haxe dates, a timestamp is defined as the number of milliseconds elapsed since 1st January 1970. **/ @@ -37,14 +38,15 @@ extern class Date { /** Creates a new date object from the given arguments. - + The behaviour of a Date instance is only consistent across platforms if the the arguments describe a valid date. - - month: 0 to 11 - - day: 1 to 31 - - hour: 0 to 23 - - min: 0 to 59 - - sec: 0 to 59 + + - month: 0 to 11 + - day: 1 to 31 + - hour: 0 to 23 + - min: 0 to 59 + - sec: 0 to 59 **/ function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void; @@ -55,43 +57,43 @@ extern class Date function getTime() : Float; /** - Returns the hours of [this] Date (0-23 range). + Returns the hours of `this` Date (0-23 range). **/ function getHours() : Int; /** - Returns the minutes of [this] Date (0-59 range). + Returns the minutes of `this` Date (0-59 range). **/ function getMinutes() : Int; /** - Returns the seconds of the [this] Date (0-59 range). + Returns the seconds of the `this` Date (0-59 range). **/ function getSeconds() : Int; /** - Returns the full year of [this] Date (4-digits). + Returns the full year of `this` Date (4-digits). **/ function getFullYear() : Int; /** - Returns the month of [this] Date (0-11 range). + Returns the month of `this` Date (0-11 range). **/ function getMonth() : Int; /** - Returns the day of [this] Date (1-31 range). + Returns the day of `this` Date (1-31 range). **/ function getDate() : Int; /** - Returns the day of the week of [this] Date (0-6 range). + Returns the day of the week of `this` Date (0-6 range). **/ function getDay() : Int; /** - Returns a string representation of [this] Date, by using the - standard format [YYYY-MM-DD HH:MM:SS]. See [DateTools.format] for + Returns a string representation of `this` Date, by using the + standard format [YYYY-MM-DD HH:MM:SS]. See `DateTools.format` for other formating rules. **/ function toString():String; @@ -102,16 +104,18 @@ extern class Date static function now() : Date; /** - Returns a Date from timestamp [t]. + Returns a Date from timestamp `t`. **/ static function fromTime( t : Float ) : Date; /** - Returns a Date from a formated string [s], with the following accepted + Returns a Date from a formated string `s`, with the following accepted formats: - - [YYYY-MM-DD hh:mm:ss] - - [YYYY-MM-DD] - - [hh:mm:ss] + + - `"YYYY-MM-DD hh:mm:ss"` + - `"YYYY-MM-DD"` + - `"hh:mm:ss"` + The first two formats are expressed in local time, the third in UTC Epoch. **/ @@ -120,17 +124,13 @@ extern class Date #if flash private static function __init__() : Void untyped { - var d #if !swf_mark : Dynamic #end = Date; + var d : Dynamic = Date; d.now = function() { return __new__(Date); }; d.fromTime = function(t){ var d : Date = __new__(Date); - #if flash9 d.setTime(t); - #else - d["setTime"]( t ); - #end return d; }; d.fromString = function(s : String) { @@ -138,17 +138,10 @@ extern class Date case 8: // hh:mm:ss var k = s.split(":"); var d : Date = __new__(Date); - #if flash9 d.setTime(0); d.setUTCHours(k[0]); d.setUTCMinutes(k[1]); d.setUTCSeconds(k[2]); - #else - d["setTime"](0); - d["setUTCHours"](k[0]); - d["setUTCMinutes"](k[1]); - d["setUTCSeconds"](k[2]); - #end return d; case 10: // YYYY-MM-DD var k = s.split("-"); @@ -162,7 +155,7 @@ extern class Date throw "Invalid date format : " + s; } }; - d.prototype[#if as3 "toStringHX" #else "toString" #end] = function() { + d.prototype[#if (as3 || no_flash_override) "toStringHX" #else "toString" #end] = function() { var date : Date = __this__; var m = date.getMonth() + 1; var d = date.getDate(); @@ -176,12 +169,6 @@ extern class Date +":"+(if( mi < 10 ) "0"+mi else ""+mi) +":"+(if( s < 10 ) "0"+s else ""+s); }; - #if flash9 - #elseif flash - d.prototype[__unprotect__("__class__")] = d; - d[__unprotect__("__name__")] = ["Date"]; - #end } #end } - diff --git a/std/DateTools.hx b/std/DateTools.hx index a8c8a89439a7ea6424090656879c1135bb2276f9..a4a0e1c93871db719ce928e27bdc2d2d33db7130 100644 --- a/std/DateTools.hx +++ b/std/DateTools.hx @@ -21,9 +21,9 @@ */ /** - The DateTools class contains some extra functionalities for handling [Date] + The DateTools class contains some extra functionalities for handling `Date` instances and timestamps. - + In the context of haxe dates, a timestamp is defined as the number of milliseconds elapsed since 1st January 1970. **/ @@ -45,6 +45,8 @@ class DateTools { __format(d,"%m/%d/%y"); case "e": untyped 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); case "I","l": @@ -105,10 +107,10 @@ class DateTools { #end /** - Format the date [d] according to the format [f]. The format is - compatible with the [strftime] standard format, except that there is no + Format the date `d` according to the format `f`. The format is + compatible with the `strftime` standard format, except that there is no support in Flash and JS for day and months names (due to lack of proper - internationalization API). On haXe/Neko/Windows, some formats are not + internationalization API). On Haxe/Neko/Windows, some formats are not supported. **/ public static function format( d : Date, f : String ) : String { @@ -122,10 +124,10 @@ class DateTools { } /** - Returns the result of adding timestamp [t] to Date [d]. - + Returns the result of adding timestamp `t` to Date `d`. + This is a convenience function for calling - Date.fromTime(d.getTime() + t). + `Date.fromTime(d.getTime() + t)`. **/ public static inline function delta( d : Date, t : Float ) : Date { return Date.fromTime( d.getTime() + t ); @@ -134,8 +136,8 @@ class DateTools { static var DAYS_OF_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; /** - Returns the number of days in the month of Date [d]. - + Returns the number of days in the month of Date `d`. + This method handles leap years. **/ public static function getMonthDays( d : Date ) : Int { @@ -199,13 +201,13 @@ class DateTools { public static function make( o : { ms : Float, seconds : Int, minutes : Int, hours : Int, days : Int } ) { return o.ms + 1000.0 * (o.seconds + 60.0 * (o.minutes + 60.0 * (o.hours + 24.0 * o.days))); } - - #if (js || flash || php || cpp) + + #if (js || flash || php || cpp || python) /** Retrieve Unix timestamp value from Date components. Takes same argument sequence as the Date constructor. **/ public static #if (js || flash || php) inline #end function makeUtc(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ):Float { - #if (js || flash) + #if (js || flash || python) return untyped Date.UTC(year, month, day, hour, min, sec); #elseif php return untyped __call__("gmmktime", hour, min, sec, month + 1, day, year) * 1000; diff --git a/std/EReg.hx b/std/EReg.hx index 47f9257f98e2baf6c2cefe84906e1d3f935a9796..509c6c810eab4d033d90b00cf2f71414b2e29aee 100644 --- a/std/EReg.hx +++ b/std/EReg.hx @@ -22,54 +22,54 @@ /** The EReg class represents regular expressions. - + While basic usage and patterns consistently work across platforms, some more complex operations may yield different results. This is a necessary trade- off to retain a certain level of performance. - + EReg instances can be created by calling the constructor, or with the special syntax ~/pattern/modifier - + EReg instances maintain an internal state, which is affected by several of its methods. - + A detailed explanation of the supported operations is available at - http://haxe.org/doc/cross/regexp + http://haxe.org/manual/std-regex.html **/ class EReg { /** - Creates a new regular expression with pattern [r] and modifiers [opt]. - - This is equivalent to the shorthand syntax ~/r/opt - - If [r] or [opt] are null, the result is unspecified. + Creates a new regular expression with pattern `r` and modifiers `opt`. + + This is equivalent to the shorthand syntax `~/r/opt` + + If `r` or `opt` are null, the result is unspecified. **/ public function new( r : String, opt : String ) { throw "Regular expressions are not implemented for this platform"; } /** - Tells if [this] regular expression matches String [s]. - + Tells if `this` regular expression matches String `s`. + This method modifies the internal state. - - If [s] is null, the result is unspecified. + + If `s` is `null`, the result is unspecified. **/ public function match( s : String ) : Bool { return false; } /** - Returns the matched sub-group [n] of [this] EReg. - - This method should only be called after [this].match() or - [this].matchSub(), and then operates on the String of that operation. - - The index [n] corresponds to the n-th set of parentheses in the pattern - of [this] EReg. If no such sub-group exists, an exception is thrown. - - If [n] equals 0, the whole matched substring is returned. + Returns the matched sub-group `n` of `this` EReg. + + This method should only be called after `this.match` or + `this.matchSub`, and then operates on the String of that operation. + + The index `n` corresponds to the n-th set of parentheses in the pattern + of `this` EReg. If no such sub-group exists, an exception is thrown. + + If `n` equals 0, the whole matched substring is returned. **/ public function matched( n : Int ) : String { return null; @@ -77,13 +77,13 @@ class EReg { /** Returns the part to the left of the last matched substring. - - If the most recent call to [this].match() or [this].matchSub() did not + + If the most recent call to `this.match` or `this.matchSub` did not match anything, the result is unspecified. - + If the global g modifier was in place for the matching, only the substring to the left of the leftmost match is returned. - + The result does not include the matched part. **/ public function matchedLeft() : String { @@ -92,13 +92,13 @@ class EReg { /** Returns the part to the right of the last matched substring. - - If the most recent call to [this].match() or [this].matchSub() did not + + If the most recent call to `this.match` or `this.matchSub` did not match anything, the result is unspecified. - + If the global g modifier was in place for the matching, only the substring to the right of the leftmost match is returned. - + The result does not include the matched part. **/ public function matchedRight() : String { @@ -107,12 +107,12 @@ class EReg { /** Returns the position and length of the last matched substring, within - the String which was last used as argument to [this].match() or - [this].matchSub(). - - If the most recent call to [this].match() or [this].matchSub() did not + the String which was last used as argument to `this.match` or + `this.matchSub`. + + If the most recent call to `this.match` or `this.matchSub` did not match anything, the result is unspecified. - + If the global g modifier was in place for the matching, the position and length of the leftmost substring is returned. **/ @@ -121,75 +121,75 @@ class EReg { } /** - Tells if [this] regular expression matches a substring of String [s]. - - This function expects [pos] and [len] to describe a valid substring of - [s], or else the result is unspecified. To get more robust behavior, - [this].matchSub(s.substr(pos,len)) can be used instead. - + Tells if `this` regular expression matches a substring of String `s`. + + This function expects `pos` and `len` to describe a valid substring of + `s`, or else the result is unspecified. To get more robust behavior, + `this.match(s.substr(pos,len))` can be used instead. + This method modifies the internal state. - - If [s] is null, the result is unspecified. + + If `s` is null, the result is unspecified. **/ - public function matchSub( s : String, pos : Int, len : Int = 0):Bool { + public function matchSub( s : String, pos : Int, len : Int = -1):Bool { return false; } /** - Splits String [s] at all substrings [this] EReg matches. - - If a match is found at the start of [s], the result contains a leading + Splits String `s` at all substrings `this` EReg matches. + + If a match is found at the start of `s`, the result contains a leading empty String "" entry. - - If a match is found at the end of [s], the result contains a trailing + + If a match is found at the end of `s`, the result contains a trailing empty String "" entry. - + If two matching substrings appear next to each other, the result contains the empty String "" between them. - - By default, this method splits [s] into two parts at the first matched - substring. If the global g modifier is in place, [s] is split at each + + By default, this method splits `s` into two parts at the first matched + substring. If the global g modifier is in place, `s` is split at each matched substring. - - If [s] is null, the result is unspecified. + + If `s` is null, the result is unspecified. **/ public function split( s : String ) : Array { return null; } /** - Replaces the first substring of [s] which [this] EReg matches with [by]. - - If [this] EReg does not match any substring, the result is [s]. - + Replaces the first substring of `s` which `this` EReg matches with `by`. + + If `this` EReg does not match any substring, the result is `s`. + By default, this method replaces only the first matched substring. If the global g modifier is in place, all matched substrings are replaced. - - If [by] contains [$1] to [$9], the digit corresponds to number of a + + If `by` contains `$1` to `$9`, the digit corresponds to number of a matched sub-group and its value is used instead. If no such sub-group - exists, the replacement is unspecified. The string [$$] becomes [$]. - - If [s] or [by] are null, the result is unspecified. + exists, the replacement is unspecified. The string `$$` becomes `$`. + + If `s` or `by` are null, the result is unspecified. **/ public function replace( s : String, by : String ) : String { return null; } /** - For each occurence of the pattern in the string [s], the function [f] is called and - can return the string that needs to be replaced. All occurences are matched anyway, - and setting the [g] flag might cause some incorrect behavior on some platforms. + Calls the function `f` for the substring of `s` which `this` EReg matches + and replaces that substring with the result of `f` call. + + The `f` function takes `this` EReg object as its first argument and should + return a replacement string for the substring matched. + + If `this` EReg does not match any substring, the result is `s`. + + By default, this method replaces only the first matched substring. If + the global g modifier is in place, all matched substrings are replaced. + + If `s` or `f` are null, the result is unspecified. **/ public function map( s : String, f : EReg -> String ) : String { - var buf = new StringBuf(); - while( true ) { - if( !match(s) ) - break; - buf.add(matchedLeft()); - buf.add(f(this)); - s = matchedRight(); - } - buf.add(s); - return buf.toString(); + return null; } } diff --git a/std/Enum.hx b/std/Enum.hx index 83210ea79ebd27efe75c4dc331c874ca83bebd70..ce1bc76bb26cb16b631e7ac9b1b463d36f7f5567 100644 --- a/std/Enum.hx +++ b/std/Enum.hx @@ -22,10 +22,10 @@ /** An abstract type that represents an Enum type. - - The corresponding enum instance type is EnumValue. - - See [Type] for the haXe Reflection API. + + The corresponding enum instance type is `EnumValue`. + + See `Type` for the Haxe Reflection API. **/ @:coreType @:runtimeValue abstract Enum { } diff --git a/std/EnumValue.hx b/std/EnumValue.hx index 86d9b998dc4e62e61d1319a5b1a982a9aa2f091a..db0b5bfe155683cc4ac10a8f9c796076039bcfff 100644 --- a/std/EnumValue.hx +++ b/std/EnumValue.hx @@ -22,7 +22,7 @@ /** An abstract type that represents any enum value. - See [Type] for the haXe Reflection API. + See `Type` for the Haxe Reflection API. **/ @:coreType abstract EnumValue { } diff --git a/std/IntIterator.hx b/std/IntIterator.hx index 89c7fd584ad5c885b4a32516981c47e77115624e..a97c4297c166c5c2ec00715807d9e20d15a001ec 100644 --- a/std/IntIterator.hx +++ b/std/IntIterator.hx @@ -22,10 +22,10 @@ /** IntIterator is used for implementing interval iterations. - - It is usually not used explicitly, but through it's special syntax: - min...max - + + It is usually not used explicitly, but through its special syntax: + `min...max` + While it is possible to assign an instance of IntIterator to a variable or field, it is worth noting that IntIterator does not reset after being used in a for-loop. Subsequent uses of the same instance will then have no @@ -37,11 +37,11 @@ class IntIterator { var max : Int; /** - Iterates from [min] (inclusive) to [max] (exclusive). - - If [max <= min], the iterator will not act as a countdown. + Iterates from `min` (inclusive) to `max` (exclusive). + + If `max <= min`, the iterator will not act as a countdown. **/ - public function new( min : Int, max : Int ) { + public inline function new( min : Int, max : Int ) { this.min = min; this.max = max; } @@ -49,16 +49,16 @@ class IntIterator { /** Returns true if the iterator has other items, false otherwise. **/ - public function hasNext() { + public inline function hasNext() { return min < max; } /** Moves to the next item of the iterator. - + If this is called while hasNext() is false, the result is unspecified. **/ - public function next() { + public inline function next() { return min++; } diff --git a/std/Lambda.hx b/std/Lambda.hx index e2666eca359713880e047ff3b408033345790bb0..9313d9b246337c8ec09c0f41a1da8a2d55e41fdf 100644 --- a/std/Lambda.hx +++ b/std/Lambda.hx @@ -21,23 +21,23 @@ */ /** - The [Lambda] class is a collection of methods to support functional + The `Lambda` class is a collection of methods to support functional programming. It is ideally used with 'using Lambda' and then acts as an extension to Iterable types. - + On static platforms, working with the Iterable structure might be slower than performing the operations directly on known types, such as Array and List. - + If the first argument to any of the methods is null, the result is unspecified. **/ class Lambda { /** - Creates an Array from Iterable [it]. - - If [it] is an Array, this function returns a copy of it. + Creates an Array from Iterable `it`. + + If `it` is an Array, this function returns a copy of it. **/ public static function array( it : Iterable ) : Array { var a = new Array(); @@ -47,9 +47,9 @@ class Lambda { } /** - Creates a List form Iterable [it]. - - If [it] is a List, this function returns a copy of it. + Creates a List form Iterable `it`. + + If `it` is a List, this function returns a copy of it. **/ public static function list( it : Iterable ) : List { var l = new List(); @@ -59,11 +59,11 @@ class Lambda { } /** - Creates a new List by applying function [f] to all elements of [it]. - + Creates a new List by applying function `f` to all elements of `it`. + The order of elements is preserved. - - If [f] is null, the result is unspecified. + + If `f` is null, the result is unspecified. **/ public static function map( it : Iterable, f : A -> B ) : List { var l = new List(); @@ -73,11 +73,11 @@ class Lambda { } /** - Similar to map, but also passes the index of each element to [f]. - + Similar to map, but also passes the index of each element to `f`. + The order of elements is preserved. - - If [f] is null, the result is unspecified. + + If `f` is null, the result is unspecified. **/ public static function mapi( it : Iterable, f : Int -> A -> B ) : List { var l = new List(); @@ -88,11 +88,11 @@ class Lambda { } /** - Tells if [it] contains [elt]. - + Tells if `it` contains `elt`. + This function returns true as soon as an element is found which is equal - to [elt] according to the [==] operator. - + to `elt` according to the `==` operator. + If no such element is found, the result is false. **/ public static function has( it : Iterable, elt : A ) : Bool { @@ -103,14 +103,14 @@ class Lambda { } /** - Tells if [it] contains an element for which [f] is true. - + Tells if `it` contains an element for which `f` is true. + This function returns true as soon as an element is found for which a - call to [f] returns true. - + call to `f` returns true. + If no such element is found, the result is false. - - If [f] is null, the result is unspecified. + + If `f` is null, the result is unspecified. **/ public static function exists( it : Iterable, f : A -> Bool ) { for( x in it ) @@ -120,16 +120,16 @@ class Lambda { } /** - Tells if [f] is true for all elements of [it]. - + Tells if `f` is true for all elements of `it`. + This function returns false as soon as an element is found for which a - call to [f] returns false. - + call to `f` returns false. + If no such element is found, the result is true. - - In particular, this function always returns true if [it] is empty. - - If [f] is null, the result is unspecified. + + In particular, this function always returns true if `it` is empty. + + If `f` is null, the result is unspecified. **/ public static function foreach( it : Iterable, f : A -> Bool ) { for( x in it ) @@ -139,9 +139,9 @@ class Lambda { } /** - Calls [f] on all elements of [it], in order. - - If [f] is null, the result is unspecified. + Calls `f` on all elements of `it`, in order. + + If `f` is null, the result is unspecified. **/ public static function iter( it : Iterable, f : A -> Void ) { for( x in it ) @@ -149,12 +149,12 @@ class Lambda { } /** - Returns a List containing those elements of [it] for which [f] returned + Returns a List containing those elements of `it` for which `f` returned true. - - If [it] is empty, the result is the empty List even if [f] is null. - - Otherwise if [f] is null, the result is unspecified. + + If `it` is empty, the result is the empty List even if `f` is null. + + Otherwise if `f` is null, the result is unspecified. **/ public static function filter( it : Iterable, f : A -> Bool ) { var l = new List(); @@ -165,16 +165,16 @@ class Lambda { } /** - Functional fold on Iterable [it], using function [f] with start argument - [first]. - - If [it] has no elements, the result is [first]. - - Otherwise the first element of [it] is passed to [f] alongside [first]. - The result of that call is then passed to [f] with the next element of - [it], and so on until [it] has no more elements. - - If [it] or [f] are null, the result is unspecified. + Functional fold on Iterable `it`, using function `f` with start argument + `first`. + + If `it` has no elements, the result is `first`. + + Otherwise the first element of `it` is passed to `f` alongside `first`. + The result of that call is then passed to `f` with the next element of + `it`, and so on until `it` has no more elements. + + If `it` or `f` are null, the result is unspecified. **/ public static function fold( it : Iterable, f : A -> B -> B, first : B ) : B { for( x in it ) @@ -183,9 +183,9 @@ class Lambda { } /** - Returns the number of elements in [it] for which [pred] is true, or the - total number of elements in [it] if [pred] is null. - + Returns the number of elements in `it` for which `pred` is true, or the + total number of elements in `it` if `pred` is null. + This function traverses all elements. **/ public static function count( it : Iterable, ?pred : A -> Bool ) { @@ -201,18 +201,18 @@ class Lambda { } /** - Tells if Iterable [it] does not contain any element. + Tells if Iterable `it` does not contain any element. **/ public static function empty( it : Iterable ) : Bool { return !it.iterator().hasNext(); } /** - Returns the index of the first element [v] within Iterable [it]. - - This function uses operator [==] to check for equality. - - If [v] does not exist in [it], the result is -1. + Returns the index of the first element `v` within Iterable `it`. + + This function uses operator `==` to check for equality. + + If `v` does not exist in `it`, the result is -1. **/ public static function indexOf( it : Iterable, v : T ) : Int { var i = 0; @@ -225,10 +225,27 @@ class Lambda { } /** - Returns a new List containing all elements of Iterable [a] followed by - all elements of Iterable [b]. - - If [a] or [b] are null, the result is unspecified. + Returns 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 null. + + If `f` is null, the result is unspecified. + **/ + public static function find( it : Iterable, f : T -> Bool ) : Null { + for( v in it ) { + if(f(v)) return v; + } + return null; + } + + /** + Returns a new List containing all elements of Iterable `a` followed by + all elements of Iterable `b`. + + If `a` or `b` are null, the result is unspecified. **/ public static function concat( a : Iterable, b : Iterable ) : List { var l = new List(); diff --git a/std/List.hx b/std/List.hx index 0f4d6759e1118277eeed300284f0145b72e6f063..dcb58bd5ecfe294ff9923b4a781149beda37f4f9 100644 --- a/std/List.hx +++ b/std/List.hx @@ -30,7 +30,7 @@ class List { private var q : Array; /** - The length of [this] List. + The length of `this` List. **/ public var length(default,null) : Int; @@ -42,9 +42,9 @@ class List { } /** - Adds element [item] at the end of [this] List. - - [this].length increases by 1. + Adds element `item` at the end of `this` List. + + `this.length` increases by 1. **/ public function add( item : T ) { var x:Array = #if neko untyped __dollar__array(item,null) #else [item] #end; @@ -57,9 +57,9 @@ class List { } /** - Adds element [item] at the beginning of [this] List. - - [this].length increases by 1. + Adds element `item` at the beginning of `this` List. + + `this.length` increases by 1. **/ public function push( item : T ) { var x : Array = #if neko @@ -74,18 +74,18 @@ class List { } /** - Returns the first element of [this] List, or null if no elements exist. - - This function does not modify [this] List. + Returns the first element of `this` List, or null if no elements exist. + + This function does not modify `this` List. **/ public function first() : Null { return if( h == null ) null else h[0]; } /** - Returns the last element of [this] List, or null if no elements exist. - - This function does not modify [this] List. + Returns the last element of `this` List, or null if no elements exist. + + This function does not modify `this` List. **/ public function last() : Null { return if( q == null ) null else q[0]; @@ -93,9 +93,9 @@ class List { /** - Returns the first element of [this] List, or null if no elements exist. - - The element is removed from [this] List. + Returns the first element of `this` List, or null if no elements exist. + + The element is removed from `this` List. **/ public function pop() : Null { if( h == null ) @@ -109,17 +109,17 @@ class List { } /** - Tells if [this] List is empty. + Tells if `this` List is empty. **/ public function isEmpty() : Bool { return (h == null); } /** - Empties [this] List. - + Empties `this` List. + This function does not traverse the elements, but simply sets the - internal references to null and [this].length to 0. + internal references to null and `this.length` to 0. **/ public function clear() : Void { h = null; @@ -128,11 +128,11 @@ class List { } /** - Removes the first occurence of [v] in [this] List. - - If [v] is found by checking standard equality, it is removed from [this] + Removes the first occurence of `v` in `this` List. + + If `v` is found by checking standard equality, it is removed from `this` List and the function returns true. - + Otherwise, false is returned. **/ public function remove( v : T ) : Bool { @@ -158,45 +158,13 @@ class List { /** Returns an iterator on the elements of the list. **/ - public function iterator() : Iterator { - #if (java || cs) - var h = h; - return cast { - hasNext : function() { - return (h != null); - }, - next : function() { - { - if( h == null ) - return null; - var x = h[0]; - h = h[1]; - return x; - } - } - } - #else - return cast { - h : h, - hasNext : function() { - return untyped (__this__.h != null); - }, - next : function() { - untyped { - if( __this__.h == null ) - return null; - var x = __this__.h[0]; - __this__.h = __this__.h[1]; - return x; - } - } - } - #end + public inline function iterator() : ListIterator { + return new ListIterator(h); } /** - Returns a string representation of [this] List. - + Returns a string representation of `this` List. + The result is enclosed in { } with the individual elements being separated by a comma. **/ @@ -218,7 +186,7 @@ class List { } /** - Returns a string representation of [this] List, with [sep] separating + Returns a string representation of `this` List, with `sep` separating each element. **/ public function join(sep : String) { @@ -237,8 +205,8 @@ class List { } /** - Returns a list filtered with [f]. The returned list will contain all - elements for which [f(x) = true]. + Returns a list filtered with `f`. The returned list will contain all + elements for which `f(x) == true`. **/ public function filter( f : T -> Bool ) { var l2 = new List(); @@ -254,7 +222,7 @@ class List { /** Returns a new list where all elements have been converted by the - function [f]. + function `f`. **/ public function map(f : T -> X) : List { var b = new List(); @@ -268,3 +236,23 @@ class List { } } + +private class ListIterator { + var head:Array; + var val:Dynamic; + + public inline function new(head:Array) { + this.head = head; + this.val = null; + } + + public inline function hasNext():Bool { + return head != null; + } + + public inline function next():T { + val = head[0]; + head = head[1]; + return val; + } +} diff --git a/std/Map.hx b/std/Map.hx index 69c9214fcbc183110b26a09d05e06e6c21a464b9..1d0227ac27d29a313d35b87b8f08581ca631de05 100644 --- a/std/Map.hx +++ b/std/Map.hx @@ -1,176 +1,167 @@ -/* - * Copyright (C)2005-2013 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. - */ - -import haxe.ds.StringMap; -import haxe.ds.IntMap; -import haxe.ds.HashMap; -import haxe.ds.ObjectMap; -import haxe.ds.WeakMap; -import haxe.ds.EnumValueMap; - - /** - Map allows key to value mapping for arbitrary value types, and many key - types. - - This is a multi-type abstract, it is instantiated as one of its - specialization types depending on its type parameters. - - A Map can be instantiated without explicit type parameters. Type inference - will then determine the type parameters from the usage. - - Maps can also be created with [key1 => value1, key2 => value2] syntax. - - Map is an abstract type, it is not available at runtime. -**/ -@:multiType -abstract Map(IMap ) { - - /** - Creates a new Map. - - This becomes a constructor call to one of the specialization types in - the output. The rules for that are as follows: - - 1. if K is a String, haxe.ds.StringMap is used - 2. if K is an Int, haxe.ds.IntMap is used - 3. if K is an enum, haxe.ds.EnumValueMap is used - 4. if K is any other class or structure, haxe.ds.ObjectMap is used - 5. if K is any other type, it causes a compile-time error - - (Cpp) Map does not use weak keys on ObjectMap by default. - **/ - public function new(); - - /** - Maps [key] to [value]. - - If [key] already has a mapping, the previous value disappears. - - If [key] is null, the result is unspecified. - **/ - public inline function set(key:K, value:V) this.set(key, value); - - /** - Returns the current mapping of [key]. - - If no such mapping exists, null is returned. - - Note that a check like map.get(key) == null can hold for two reasons: - - 1. the map has no mapping for [key] - 2. the map has a mapping with a value of null - - If it is important to distinguish these cases, exists() should be used. - - If [key] is null, the result is unspecified. - **/ - @:arrayAccess public inline function get(key:K) return this.get(key); - - /** - Returns true if [key] has a mapping, false otherwise. - - If [key] is null, the result is unspecified. - **/ - public inline function exists(key:K) return this.exists(key); - - /** - Removes the mapping of [key] and returns true if such a mapping existed, - false otherwise. - - If [key] is null, the result is unspecified. - **/ - public inline function remove(key:K) return this.remove(key); - - /** - Returns an Iterator over the keys of [this] Map. - - The order of keys is undefined. - **/ - public inline function keys():Iterator { - return this.keys(); - } - - /** - Returns an Iterator over the values of [this] Map. - - The order of values is undefined. - **/ - public inline function iterator():Iterator { - return this.iterator(); - } - - /** - Returns a String representation of [this] Map. - - The exact representation depends on the platform and key-type. - **/ - public inline function toString():String { - return this.toString(); - } - - @:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V { - this.set(k, v); - return v; - } - - @:to static inline function toStringMap(t:IMap):StringMap { - return new StringMap(); - } - - @:to static inline function toIntMap(t:IMap):IntMap { - return new IntMap(); - } - - @:to static inline function toEnumValueMapMap(t:IMap):EnumValueMap { - return new EnumValueMap(); - } - - @:to static inline function toObjectMap(t:IMap):ObjectMap { - return new ObjectMap(); - } - - @:from static inline function fromStringMap(map:StringMap):Map< String, V > { - return map; - } - - @:from static inline function fromIntMap(map:IntMap):Map< Int, V > { - return map; - } - - @:from static inline function fromObjectMap(map:ObjectMap):Map { - return map; - } -} - -interface IMap { - public function get(k:K):Null; - public function set(k:K, v:V):Void; - public function exists(k:K):Bool; - public function remove(k:K):Bool; - public function keys():Iterator; - public function iterator():Iterator; - public function toString():String; -} - -private typedef Hashable = { - function hashCode():Int; -} \ No newline at end of file +/* + * Copyright (C)2005-2013 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. + */ + +import haxe.ds.StringMap; +import haxe.ds.IntMap; +import haxe.ds.HashMap; +import haxe.ds.ObjectMap; +import haxe.ds.WeakMap; +import haxe.ds.EnumValueMap; +import haxe.Constraints.IMap; + + /** + Map allows key to value mapping for arbitrary value types, and many key + types. + + This is a multi-type abstract, it is instantiated as one of its + specialization types depending on its type parameters. + + A Map can be instantiated without explicit type parameters. Type inference + will then determine the type parameters from the usage. + + Maps can also be created with `key1 => value1, key2 => value2` syntax. + + Map is an abstract type, it is not available at runtime. +**/ +@:multiType(K) +abstract Map(IMap ) { + + /** + Creates a new Map. + + This becomes a constructor call to one of the specialization types in + the output. The rules for that are as follows: + + 1. if K is a `String`, `haxe.ds.StringMap` is used + 2. if K is an `Int`, `haxe.ds.IntMap` is used + 3. if K is an `EnumValue`, `haxe.ds.EnumValueMap` is used + 4. if K is any other class or structure, `haxe.ds.ObjectMap` is used + 5. if K is any other type, it causes a compile-time error + + (Cpp) Map does not use weak keys on ObjectMap by default. + **/ + public function new(); + + /** + Maps `key` to `value`. + + If `key` already has a mapping, the previous value disappears. + + If `key` is null, the result is unspecified. + **/ + public inline function set(key:K, value:V) this.set(key, value); + + /** + Returns the current mapping of `key`. + + If no such mapping exists, null is returned. + + Note that a check like `map.get(key) == null` can hold for two reasons: + + 1. the map has no mapping for `key` + 2. the map has a mapping with a value of `null` + + If it is important to distinguish these cases, `exists()` should be + used. + + If `key` is null, the result is unspecified. + **/ + @:arrayAccess public inline function get(key:K) return this.get(key); + + /** + Returns true if `key` has a mapping, false otherwise. + + If `key` is null, the result is unspecified. + **/ + public inline function exists(key:K) return this.exists(key); + + /** + Removes the mapping of `key` and returns true if such a mapping existed, + false otherwise. + + If `key` is null, the result is unspecified. + **/ + public inline function remove(key:K) return this.remove(key); + + /** + Returns an Iterator over the keys of `this` Map. + + The order of keys is undefined. + **/ + public inline function keys():Iterator { + return this.keys(); + } + + /** + Returns an Iterator over the values of `this` Map. + + The order of values is undefined. + **/ + public inline function iterator():Iterator { + return this.iterator(); + } + + /** + Returns a String representation of `this` Map. + + The exact representation depends on the platform and key-type. + **/ + public inline function toString():String { + return this.toString(); + } + + @:arrayAccess @:noCompletion public inline function arrayWrite(k:K, v:V):V { + this.set(k, v); + return v; + } + + @:to static inline function toStringMap(t:IMap):StringMap { + return new StringMap(); + } + + @:to static inline function toIntMap(t:IMap):IntMap { + return new IntMap(); + } + + @:to static inline function toEnumValueMapMap(t:IMap):EnumValueMap { + return new EnumValueMap(); + } + + @:to static inline function toObjectMap(t:IMap):ObjectMap { + return new ObjectMap(); + } + + @:from static inline function fromStringMap(map:StringMap):Map< String, V > { + return cast map; + } + + @:from static inline function fromIntMap(map:IntMap):Map< Int, V > { + return cast map; + } + + @:from static inline function fromObjectMap(map:ObjectMap):Map { + return cast map; + } +} + +@:deprecated +typedef IMap = haxe.Constraints.IMap; \ No newline at end of file diff --git a/std/Math.hx b/std/Math.hx index 8501838060f92ed7d3f8a4795c89783888342ef9..4d246f8aaaa9187825c4aca9d90fe5b67430c13e 100644 --- a/std/Math.hx +++ b/std/Math.hx @@ -22,204 +22,241 @@ /** This class defines mathematical functions and constants. **/ -#if cpp @:include("hxMath") #end +#if cpp @:include("hxMath.h") #end extern class Math { + /** + Represents the ratio of the circumference of a circle to its diameter, + specified by the constant, π. `PI` is approximately 3.141592653589793. + **/ static var PI(default,null) : Float; - + /** - A special Float constant which denotes negative infinity. - + A special `Float` constant which denotes negative infinity. + For example, this is the result of -1.0 / 0.0. - - Operations with NEGATIVE_INFINITY as an operand may result in - Operations with NEGATIVE_INFINITY as an operand may result in - NEGATIVE_INFINITY, POSITIVE_INFINITY or NaN. For detailed information, - see ... - - If this constant is converted to an Int, e.g. through Std.int(), the + + Operations with `NEGATIVE_INFINITY` as an operand may result in + `NEGATIVE_INFINITY`, `POSITIVE_INFINITY` or `NaN`. + + If this constant is converted to an `Int`, e.g. through `Std.int()`, the result is unspecified. **/ static var NEGATIVE_INFINITY(default, null) : Float; + /** - A special Float constant which denotes negative infinity. - + A special `Float` constant which denotes negative infinity. + 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. For detailed information, - see ... - - If this constant is converted to an Int, e.g. through Std.int(), the + + Operations with `POSITIVE_INFINITY` as an operand may result in + `NEGATIVE_INFINITY`, `POSITIVE_INFINITY` or `NaN`. + + If this constant is converted to an `Int`, e.g. through `Std.int()`, the result is unspecified. **/ static var POSITIVE_INFINITY(default,null) : Float; /** - A special Float constant which denotes an invalid number. - + A special `Float` constant which denotes an invalid number. + 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). - - All further operations with NaN as an operand will result in NaN. - - If this constant is converted to an Int, e.g. through Std.int(), the + + All further operations with `NaN` as an operand will result in `NaN`. + + If this constant is converted to an `Int`, e.g. through `Std.int()`, the result is unspecified. - - In order to test if a value is NaN, you should use Math.isNaN() function. - - (Php) In PHP versions prior to 5.3.1 VC 9 there may be unexpected - results when performing arithmetic operations with NaN on Windows, see: - https://bugs.php.net/bug.php?id=42143 + + In order to test if a value is `NaN`, you should use `Math.isNaN()` function. + + @php In PHP versions prior to 5.3.1 VC 9 there may be unexpected + results when performing arithmetic operations with `NaN` on Windows, + see [https://bugs.php.net/bug.php?id=42143] **/ static var NaN(default, null) : Float; /** - 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. + 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`. **/ 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. + 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`. **/ 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. + 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`. **/ static function max(a:Float, b:Float):Float; - + /** - Returns the trigonometric sine of [v]. - - The unit of [v] is radians. - - If [v] is NaN or infinite, the result is NaN. + Returns the trigonometric sine of the specified angle `v`, in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. **/ static function sin(v:Float):Float; - + /** - Returns the trigonometric cosine of [v]. - - The unit of [v] is radians. - - If [v] is NaN or infinite, the result is NaN. + Returns the trigonometric cosine of the specified angle `v`, in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. **/ static function cos(v:Float):Float; - - // TODO + + /** + Returns the trigonometric tangent of the specified angle `v`, in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. + **/ static function tan(v:Float):Float; + + /** + Returns the trigonometric arc of the specified angle `v`, in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. + **/ static function asin(v:Float):Float; + + /** + Returns the trigonometric arc cosine of the specified angle `v`, + in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. + **/ static function acos(v:Float):Float; + + /** + Returns the trigonometric arc tangent of the specified angle `v`, + in radians. + + If `v` is `NaN` or infinite, the result is `NaN`. + **/ static function atan(v:Float):Float; + + /** + Returns the trigonometric arc tangent whose tangent is the quotient of + two specified numbers, in radians. + + If parameter `x` or `y` is `NaN`, `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, + the result is `NaN`. + **/ static function atan2(y:Float, x:Float):Float; - + /** - Returns Euler's number, raised to the power of [v]. - + Returns Euler's number, raised to the power of `v`. + 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; - + /** - Returns the natural logarithm 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 NEGATIVE_INFINITY. - - This is the inverse operation of exp, i.e. log(exp(v)) == v always - holds. + Returns the natural logarithm of `v`. + + 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`. **/ static function log(v:Float):Float; - - // TODO - // http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Math.html#pow(double, double) <-- wtf? + + /** + Returns a specified base `v` raised to the specified power `exp`. + **/ static function pow(v:Float, exp:Float):Float; - + /** - 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. + 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`. **/ static function sqrt(v:Float):Float; - + /** - Rounds [v] to the nearest Int value. + Rounds `v` to the nearest integer value. - If v is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is unspecified. - - TODO: need spec + If `v` is outside of the signed `Int32` range, or is `NaN`, `NEGATIVE_INFINITY` + or `POSITIVE_INFINITY`, the result is unspecified. **/ static function round(v:Float):Int; - + /** - Returns the largest Int value that is not greater than [v]. - - If v is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is unspecified. - - TODO: need spec + Returns the largest integer value that is not greater than `v`. + + If `v` is outside of the signed `Int32` range, or is `NaN`, `NEGATIVE_INFINITY` + or `POSITIVE_INFINITY`, the result is unspecified. **/ static function floor(v:Float):Int; - + /** - Returns the smallest Int value that is not less than [v]. + Returns the smallest integer value that is not less than `v`. - If v is outside of the signed Int32 range, or is NaN, NEGATIVE_INFINITY or POSITIVE_INFINITY, the result is unspecified. - - TODO: need spec + If `v` is outside of the signed `Int32` range, or is `NaN`, `NEGATIVE_INFINITY` + or `POSITIVE_INFINITY`, the result is unspecified. **/ 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. **/ static function random() : Float; - - #if ((flash9 && !as3) || cpp) - + + #if ((flash && !as3) || cpp) + /** + Returns the largest integer value that is not greater than `v`, as a `Float`. + + If `v` is is `NaN`, `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, + the result is unspecified. + **/ static function ffloor( v : Float ) : Float; + + /** + Returns the smallest integer value that is not less than `v`, as a `Float`. + + If `v` is is `NaN`, `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, + the result is unspecified. + **/ static function fceil( v : Float ) : Float; + + /** + Rounds `v` to the nearest integer value, as a Float. + + If `v` is is `NaN`, `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, + the result is unspecified. + **/ static function fround( v : Float ) : Float; - + #else - + static inline function ffloor( v : Float ) : Float { return floor(v); } @@ -231,32 +268,29 @@ extern class Math static inline function fround( v : Float ) : Float { return round(v); } - + #end - + /** - Tells if [f] is a finite number. - - If [f] is POSITIVE_INFINITY, NEGATIVE_INFINITY or NaN, the result is - false. - - Otherwise the result is true. + Tells if `f` is a finite number. + + If `f` is `POSITIVE_INFINITY`, `NEGATIVE_INFINITY` or `NaN`, the result + is `false`, otherwise the result is `true`. **/ static function isFinite( f : Float ) : Bool; - + /** - Tells if [f] is not a valid number. - - If [f] is NaN, the result is true. - - Otherwise the result is false. In particular, both POSITIVE_INFINITY and - NEGATIVE_INFINITY are not considered NaN. + Tells if `f` is not a valid number. + + If `f` is `NaN`, the result is `true`, otherwise the result is `false`. + In particular, both `POSITIVE_INFINITY` and `NEGATIVE_INFINITY` are + not considered `NaN`. **/ static function isNaN( f : Float ) : Bool; private static function __init__() : Void untyped { - #if flash9 + #if flash NaN = __global__["Number"].NaN; NEGATIVE_INFINITY = __global__["Number"].NEGATIVE_INFINITY; POSITIVE_INFINITY = __global__["Number"].POSITIVE_INFINITY; @@ -265,30 +299,19 @@ extern class Math Math.NaN = Number["NaN"]; Math.NEGATIVE_INFINITY = Number["NEGATIVE_INFINITY"]; Math.POSITIVE_INFINITY = Number["POSITIVE_INFINITY"]; - #end - #if js - __feature__("Type.resolveClass",$hxClasses['Math'] = Math); #end Math.isFinite = function(i) { return - #if flash9 + #if flash __global__["isFinite"](i); - #elseif flash - _global["isFinite"](i); - #elseif js - __js__("isFinite")(i); #else false; #end }; Math.isNaN = function(i) { return - #if flash9 + #if flash __global__["isNaN"](i); - #elseif flash - _global["isNaN"](i); - #elseif js - __js__("isNaN")(i); #else false; #end @@ -296,5 +319,3 @@ extern class Math } } - - diff --git a/std/Reflect.hx b/std/Reflect.hx index 132d6b0dad42f2bfafdd08a8292784138e4bb041..e94ac3218337f3e82a4ae4a2f8012bf81909b258 100644 --- a/std/Reflect.hx +++ b/std/Reflect.hx @@ -20,164 +20,166 @@ * DEALINGS IN THE SOFTWARE. */ /** - The Reflect API is a way to manipulate values dynamicly through an + The Reflect API is a way to manipulate values dynamically through an abstract interface in an untyped manner. Use with care. **/ extern class Reflect { /** - Tells if structure [o] has a field named [field]. - + Tells if structure `o` has a field named `field`. + This is only guaranteed to work for anonymous structures. Refer to - [Type.getInstanceFields] for a function supporting class instances. - - If [o] or [field] are null, the result is unspecified. + `Type.getInstanceFields` for a function supporting class instances. + + If `o` or `field` are null, the result is unspecified. **/ public static function hasField( o : Dynamic, field : String ) : Bool; /** - Returns the value of the field named [field] on object [o]. - - If [o] is not an object or has no field named [field], the result is + Returns the value of the field named `field` on object `o`. + + If `o` is not an object or has no field named `field`, the result is null. - + If the field is defined as a property, its accessors are ignored. Refer - to [Reflect.getProperty] for a function supporting property accessors. - - If [field] is null, the result is unspecified. - + 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; /** - Sets the field named [field] of object [o] to value [value]. - - If [o] has no field named [field], this function is only guaranteed to + Sets the field named `field` of object `o` to value `value`. + + If `o` has no field named `field`, this function is only guaranteed to work for anonymous structures. - - If [o] or [field] are null, the result is unspecified. - + + 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. + not possible to set the value directly. **/ public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void; /** - Returns the value of the field named [field] on object [o], taking + Returns the value of the field named `field` on object `o`, taking property getter functions into account. - + If the field is not a property, this function behaves like - [Reflect.field], but might be slower. - - If [o] or [field] are null, the result is unspecified. + `Reflect.field`, but might be slower. + + If `o` or `field` are null, the result is unspecified. **/ public static function getProperty( o : Dynamic, field : String ) : Dynamic; /** - Sets the field named [field] of object [o] to value [value], taking + Sets the field named `field` of object `o` to value `value`, taking property setter functions into account. - + If the field is not a property, this function behaves like - [Reflect.setField], but might be slower. - - If [field] is null, the result is unspecified. + `Reflect.setField`, but might be slower. + + If `field` is null, the result is unspecified. **/ public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void; /** Call a method with the given object and arguments. **/ - public static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic; + public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic; /** - Returns the fields of structure [o]. - + Returns the fields of structure `o`. + This method is only guaranteed to work on anonymous structures. Refer to - [Type.getInstanceFields()] for a function supporting class instances. - - If [o] is null, the result is unspecified. + `Type.getInstanceFields` for a function supporting class instances. + + If `o` is null, the result is unspecified. **/ public static function fields( o : Dynamic ) : Array; /** - Returns true if [f] is a function, false otherwise. - - If [f] is null, the result is false. + Returns true if `f` is a function, false otherwise. + + If `f` is null, the result is false. **/ public static function isFunction( f : Dynamic ) : Bool; /** - Compares [a] and [b]. - - If [a] is less than [b], the result is negative. If [b] is less than - [a], the result is positive. If [a] and [b] are equal, the result is 0. - - This function is only defined if [a] and [b] are of the same type. - + Compares `a` and `b`. + + If `a` is less than `b`, the result is negative. If `b` is less than + `a`, the result is positive. If `a` and `b` are equal, the result is 0. + + This function is only defined if `a` and `b` are of the same type. + If that type is a function, the result is unspecified and - [Reflect.compareMethods] should be used instead. - - For all other types, the result is 0 if [a] and [b] are equal. If they + `Reflect.compareMethods` should be used instead. + + For all other types, the result is 0 if `a` and `b` are equal. If they are not equal, the result depends on the type and is negative if: - Numeric types: a is less than b - String: a is lexicographically less than b - Other: unspecified - - If [a] and [b] are null, the result is 0. If only one of them is null, + + - Numeric types: a is less than b + - String: a is lexicographically less than b + - Other: unspecified + + 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; /** - Compares the functions [f1] and [f2]. - - If [f1] or [f2] are not functions, the result is unspecified. - - Otherwise the result is true if [f1] and the [f2] are physically equal, + Compares the functions `f1` and `f2`. + + If `f1` or `f2` are not functions, the result is unspecified. + + Otherwise the result is true if `f1` and the `f2` are physically equal, false otherwise. **/ public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool; /** - Tells if [v] is an object. - - The result is true if [v] is one of the following: - - class instance - - structure - - Class - - Enum - - Otherwise, including if [v] is null, the result is false. + Tells if `v` is an object. + + The result is true if `v` is one of the following: + + - class instance + - structure + - Class + - Enum + + Otherwise, including if `v` is null, the result is false. **/ public static function isObject( v : Dynamic ) : Bool; /** - Tells if [v] is an enum value. - - The result is true if [v] is of type EnumValue, i.e. an enum + Tells if `v` is an enum value. + + The result is true if `v` is of type EnumValue, i.e. an enum constructor. - - Otherwise, including if [v] is null, the result is false. + + Otherwise, including if `v` is null, the result is false. **/ public static function isEnumValue( v : Dynamic ) : Bool; - + /** - Removes the field named [field] from structure [o]. - + Removes the field named `field` from structure `o`. + This method is only guaranteed to work on anonymous structures. - - If [o] or [field] are null, the result is unspecified. + + If `o` or `field` are null, the result is unspecified. **/ public static function deleteField( o : Dynamic, field : String ) : Bool; /** - Copies the fields of structure [o]. - + Copies the fields of structure `o`. + This is only guaranteed to work on anonymous structures. - - If [o] is null, the result is unspecified. + + If `o` is null, the result is unspecified. **/ public static function copy( o : T ) : T; diff --git a/std/Std.hx b/std/Std.hx index 0e3bad0e9a699a9777a6da04377d6f62acd3ba10..70e64b96f09fc51f56f28382c6d011eab850f49e 100644 --- a/std/Std.hx +++ b/std/Std.hx @@ -29,24 +29,42 @@ extern class Std { /** - Tells if a value v is of the type t. Returns false if v or t are null. + Tells if a value `v` is of the type `t`. Returns `false` if `v` or `t` are null. **/ public static function is( v : Dynamic, t : Dynamic ) : Bool; + /** + Checks if object `value` is an instance of class `c`. + + Compiles only if the class specified by `c` can be assigned to the type + of `value`. + + This method checks if a downcast is possible. That is, if the runtime + type of `value` is assignable to the class specified by `c`, `value` is + returned. Otherwise null is returned. + + This method is not guaranteed to work with interfaces or core types such + as `String`, `Array` and `Date`. + + If `value` is null, the result is null. If `c` is null, the result is + unspecified. + **/ + public static function instance( value : T, c : Class ) : S; + /** Converts any value to a String. - If s is of String, Int, Float or Bool, its value is returned. + If `s` is of `String`, `Int`, `Float` or `Bool`, its value is returned. - If s is an instance of a class and that class or one of its parent classes has - a toString() method, that method is called. If no such method is present, the result + If `s` is an instance of a class and that class or one of its parent classes has + a `toString` method, that method is called. If no such method is present, the result is unspecified. - If s is an enum constructor without argument, the constructor's name is returned. If + If `s` is an enum constructor without argument, the constructor's name is returned. If arguments exists, the constructor's name followed by the String representations of the arguments is returned. - If s is a structure, the field names along with their values are returned. The field order + If `s` is a structure, the field names along with their values are returned. The field order and the operator separating field names and values are unspecified. If s is null, "null" is returned. @@ -54,21 +72,21 @@ extern class Std { public static function string( s : Dynamic ) : String; /** - Converts a Float to an Int, rounded towards 0. + 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. + 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; /** - Converts a String to an Int. + Converts a `String` to an `Int`. Leading whitespaces are ignored. - If x starts with 0x or 0X, hexadecimal notation is recognized where the following digits may + If `x` starts with 0x or 0X, hexadecimal notation is recognized where the following digits may contain 0-9 and A-F. - Otherwise x is read as decimal number with 0-9 being allowed characters. x may also start with + Otherwise `x` is read as decimal number with 0-9 being allowed characters. `x` may also start with a - to denote a negative value. In decimal mode, parsing continues until an invalid character is detected, in which case the @@ -78,24 +96,24 @@ extern class Std { Leading 0s that are not part of the 0x/0X hexadecimal notation are ignored, which means octal notation is not supported. - If the input cannot be recognized, the result is null. + If the input cannot be recognized, the result is `null`. **/ public static function parseInt( x : String ) : Null; /** - Converts a String to a Float. + Converts a `String` to a `Float`. - The parsing rules for parseInt() apply here as well, with the exception of invalid input - resulting in a NaN value instead of null. + The parsing rules for `parseInt` apply here as well, with the exception of invalid input + resulting in a `NaN` value instead of null. - Additionally, decimal notation may contain a single . to denote the start of the fractions. + Additionally, decimal notation may contain a single `.` to denote the start of the fractions. **/ public static function parseFloat( x : String ) : Float; /** - Return a random integer between 0 included and x excluded. + Return a random integer between 0 included and `x` excluded. - If x is <= 1, the result is always 0. + If `x <= 1`, the result is always 0. **/ public static function random( x : Int ) : Int; } diff --git a/std/StdTypes.hx b/std/StdTypes.hx index e1695d5fd1cf3c3e9dc5cc78b633752da0f4da95..76222f7fc445e54b68228768b10b169f97beb285 100644 --- a/std/StdTypes.hx +++ b/std/StdTypes.hx @@ -19,52 +19,55 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -// standard haXe types +// standard Haxe types /** - The standard Void type. Only [null] values can be of the type [Void]. + The standard Void type. Only `null` values can be of the type `Void`. **/ @:coreType abstract Void { } /** The standard Float type, this is a double-precision IEEE 64bit float. + + On static targets, null cannot be assigned to Float. If this is necessary, + `Null` can be used instead. **/ @:coreType @:notNull @:runtimeValue abstract Float { } /** The standard Int type. Its precision depends on the platform. -**/ -@:coreType @:notNull @:runtimeValue abstract Int to Float { } -#if (flash9 || flash9doc || cs) -/** - The unsigned Int type is only defined for Flash9. It's currently - handled the same as a normal Int. + On static targets, null cannot be assigned to Int. If this is necessary, + `Null` can be used instead. **/ -@:coreType @:notNull @:runtimeValue abstract UInt to Int from Int { } -#end +@:coreType @:notNull @:runtimeValue abstract Int to Float { } #if (java || cs) @:coreType @:notNull @:runtimeValue abstract Single to Float from Float {} #end /** - [Null] can be useful in two cases. In order to document some methods - that accepts or can return a [null] value, or for the Flash9 compiler and AS3 + `Null` can be useful in two cases. In order to document some methods + that accepts or can return a `null` value, or for the Flash compiler and AS3 generator to distinguish between base values that can be null and others that can't. **/ typedef Null = T /** - The standard Boolean type is represented as an enum with two choices. + The standard Boolean type, which can either be true or false. + + On static targets, null cannot be assigned to Bool. If this is necessary, + `Null` can be used instead. **/ @:coreType @:notNull @:runtimeValue abstract Bool { } /** - Dynamic is an internal compiler type which has special behavior. - See the haXe language reference for more informations. + Dynamic is a special type which is compatible with all other types. + + Use of Dynamic should be minimized as it prevents several compiler + checks and optimizations. **/ @:coreType @:runtimeValue abstract Dynamic { } @@ -77,30 +80,33 @@ typedef Null = T custom iterators. **/ typedef Iterator = { - + /** Returns false if the iteration is complete, true otherwise. - + Usually iteration is considered to be complete if all elements of the underlying data structure were handled through calls to next(). However, in custom iterators any logic may be used to determine the completion state. **/ function hasNext() : Bool; - + /** Returns the current item of the Iterator and advances to the next one. - - This method is not required to check hasNext() first. A call to this - method while hasNext() is false yields unspecified behavior. + + This method is not required to check `hasNext` first. A call to this + method while `hasNext` is false yields unspecified behavior. + + On the other hand iterators should not require a call to `hasNext` + before the first call to `next` if an element is available. **/ function next() : T; - + } /** An Iterable is a data structure which has an iterator() method. - See [Lambda] for generic functions on iterable structures. + See `Lambda` for generic functions on iterable structures. **/ typedef Iterable = { function iterator() : Iterator; @@ -108,6 +114,6 @@ typedef Iterable = { /** ArrayAccess is used to indicate a class that can be accessed using brackets. - The type parameter represent the type of the elements stored. + The type parameter represents the type of the elements stored. **/ extern interface ArrayAccess { } diff --git a/std/String.hx b/std/String.hx index eff57affe7ada2b5477ce6f4894085cd11c47aba..e523500cf98aa96cec86cecde32591d2032d06e6 100644 --- a/std/String.hx +++ b/std/String.hx @@ -21,19 +21,19 @@ */ /** The basic String class. - + A haxe String is immutable, it is not possible to modify individual - characters. No method of this class changes the state of [this] String. - + characters. No method of this class changes the state of `this` String. + Strings can be constructed using the string literal syntax "string value". - + String can be concatenated by using the + operator. If an operand is not a String, it is passed through Std.string() first. **/ extern class String { /** - The number of characters in [this] String. + The number of characters in `this` String. **/ var length(default,null) : Int; @@ -43,32 +43,32 @@ extern class String { function new(string:String) : Void; /** - Returns a String where all characters of [this] String are upper case. - - Affects the characters [a-z]. Other characters remain unchanged. + Returns a String where all characters of `this` String are upper case. + + Affects the characters `a-z`. Other characters remain unchanged. **/ function toUpperCase() : String; /** - Returns a String where all characters of [this] String are lower case. - - Affects the characters [A-Z]. Other characters remain unchanged. + Returns a String where all characters of `this` String are lower case. + + Affects the characters `A-Z`. Other characters remain unchanged. **/ function toLowerCase() : String; /** - Returns the character at position [index] of [this] String. - - If [index] is negative or exceeds [this].length, the empty String "" + Returns the character at position `index` of `this` String. + + If `index` is negative or exceeds `this.length`, the empty String "" is returned. **/ function charAt(index : Int) : String; /** - Returns the character code at position [index] of [this] String. - - If [index] is negative or exceeds [this].length, null is returned. - + Returns the character code at position `index` of `this` String. + + If `index` is negative or exceeds `this.length`, null is returned. + To obtain the character code of a single character, "x".code can be used instead to inline the character code at compile time. Note that this only works on String literals of length 1. @@ -76,78 +76,81 @@ extern class String { function charCodeAt( index : Int) : Null; /** - Returns the position of the leftmost occurence of [str] within [this] + Returns the position of the leftmost occurence of `str` within `this` String. - - If [startIndex] is given, the search is performed within the substring - of [this] String starting from [startIndex]. Otherwise the search is - performed within [this] String. In either case, the returned position - is relative to the beginning of [this] String. - - If [str] cannot be found, -1 is returned. + + If `startIndex` is given, the search is performed within the substring + of `this` String starting from `startIndex`. Otherwise the search is + performed within `this` String. In either case, the returned position + is relative to the beginning of `this` String. + + If `str` cannot be found, -1 is returned. **/ function indexOf( str : String, ?startIndex : Int ) : Int; /** - Returns the position of the rightmost occurence of [str] within [this] + Returns the position of the rightmost occurence of `str` within `this` String. - - If [startIndex] is given, the search is performed within the substring - of [this] String from 0 to [startIndex]. Otherwise the search is - performed within [this] String. In either case, the returned position - is relative to the beginning of [this] String. - - If [str] cannot be found, -1 is returned. + + If `startIndex` is given, the search is performed within the substring + of `this` String from 0 to `startIndex`. Otherwise the search is + performed within `this` String. In either case, the returned position + is relative to the beginning of `this` String. + + If `str` cannot be found, -1 is returned. **/ function lastIndexOf( str : String, ?startIndex : Int ) : Int; /** - Splits [this] String at each occurence of [delimiter]. - - If [delimiter] is the empty String "", [this] String is split into an - Array of [this].length elements, where the elements correspond to the - characters of [this] String. - - If [delimiter] is not found within [this] String, the result is an Array - with one element, which equals [this] String. - - If [delimiter] is null, the result is unspecified. - - Otherwise, [this] String is split into parts at each occurence of - [delimiter]. If [this] String starts (or ends) with [delimiter}, the + Splits `this` String at each occurence of `delimiter`. + + If `this` String is the empty String "", the result is not consistent + across targets and may either be `[]` (on Js, Cpp) or `[""]`. + + If `delimiter` is the empty String "", `this` String is split into an + Array of `this.length` elements, where the elements correspond to the + characters of `this` String. + + If `delimiter` is not found within `this` String, the result is an Array + with one element, which equals `this` String. + + If `delimiter` is null, the result is unspecified. + + Otherwise, `this` String is split into parts at each occurence of + `delimiter`. If `this` String starts (or ends) with [delimiter}, the result Array contains a leading (or trailing) empty String "" element. Two subsequent delimiters also result in an empty String "" element. **/ function split( delimiter : String ) : Array; /** - Returns [len] characters of [this] String, starting at position [pos]. - - If [len] is omitted, all characters from position [pos] to the end of - [this] String are included. - - If [pos] is negative, its value is calculated from the end of [this] - String by [this].length + [pos]. If this yields a negative value, 0 is + Returns `len` characters of `this` String, starting at position `pos`. + + If `len` is omitted, all characters from position `pos` to the end of + `this` String are included. + + If `pos` is negative, its value is calculated from the end of `this` + String by `this.length + pos`. If this yields a negative value, 0 is used instead. - - If the calculated position + [len] exceeds [this].length, the characters - from that position to the end of [this] String are returned. - - If [len] is negative, the result is unspecified. + + If the calculated position + `len` exceeds `this.length`, the characters + from that position to the end of `this` String are returned. + + If `len` is negative, the result is unspecified. **/ function substr( pos : Int, ?len : Int ) : String; /** - Returns the part of [this] String from [startIndex] to [endIndex]. - - If [startIndex] or [endIndex] are negative, 0 is used instead. - - If [startIndex] exceeds [endIndex], they are swapped. - - If the (possibly swapped) [endIndex] is omitted or exceeds - [this].length, [this].length is used instead. - - If the (possibly swapped) [startIndex] exceeds [this].length, the empty + Returns the part of `this` String from `startIndex` to but not including `endIndex`. + + If `startIndex` or `endIndex` are negative, 0 is used instead. + + If `startIndex` exceeds `endIndex`, they are swapped. + + If the (possibly swapped) `endIndex` is omitted or exceeds + `this.length`, `this.length` is used instead. + + If the (possibly swapped) `startIndex` exceeds `this.length`, the empty String "" is returned. **/ function substring( startIndex : Int, ?endIndex : Int ) : String; @@ -158,9 +161,9 @@ extern class String { function toString() : String; /** - Returns the String corresponding to the character code [code]. - - If [code] is negative or has another invalid value, the result is + Returns the String corresponding to the character code `code`. + + If `code` is negative or has another invalid value, the result is unspecified. **/ static function fromCharCode( code : Int ) : String; diff --git a/std/StringBuf.hx b/std/StringBuf.hx index 965c509fa7c55ae3e2273b0894376701618ce5a1..2684e2a007c9d3d24e35d3bfacc1ce7f3f0afb17 100644 --- a/std/StringBuf.hx +++ b/std/StringBuf.hx @@ -22,42 +22,53 @@ /** 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. **/ class StringBuf { - var b:String = ""; - + var b:String; + + /** + The length of `this` StringBuf in characters. + **/ + public var length(get,never) : Int; + /** Creates a new StringBuf instance. - + This may involve initialization of the internal buffer. **/ - public function new() {} + public inline function new() { + b = ""; + } + + inline function get_length() : Int { + return b.length; + } /** - Appends the representation of [x] to [this] StringBuf. - - The exact representation of [x] may vary per platform. To get more + Appends the representation of `x` to `this` StringBuf. + + The exact representation of `x` may vary per platform. To get more consistent behavior, this function should be called with Std.string(x). - - If [x] is null, the String "null" is appended. + + If `x` is null, the String "null" is appended. **/ - public inline function add( x : Dynamic ) : Void { + public inline function add( x : T ) : Void { b += x; } /** - Appends the character identified by [c] to [this] StringBuf. - - If [c] is negative or has another invalid value, the result is + Appends the character identified by `c` to `this` StringBuf. + + If `c` is negative or has another invalid value, the result is unspecified. **/ public inline function addChar( c : Int ) : Void { @@ -65,24 +76,24 @@ class StringBuf { } /** - Appends a substring of [s] to [this] StringBuf. - - This function expects [pos] and [len] to describe a valid substring of - [s], or else the result is unspecified. To get more robust behavior, - [this].add(s.substr(pos,len)) can be used instead. - - If [s] or [pos] are null, the result is unspecified. - - If [len] is omitted or null, the substring ranges from [pos] to the end - of [s]. + Appends a substring of `s` to `this` StringBuf. + + This function expects `pos` and `len` to describe a valid substring of + `s`, or else the result is unspecified. To get more robust behavior, + `this.add(s.substr(pos,len))` can be used instead. + + If `s` or `pos` are null, the result is unspecified. + + If `len` is omitted or null, the substring ranges from `pos` to the end + of `s`. **/ public inline function addSub( s : String, pos : Int, ?len : Int) : Void { b += (len == null ? s.substr(pos) : s.substr(pos, len)); } /** - Returns the content of [this] StringBuf as String. - + Returns the content of `this` StringBuf as String. + The buffer is not emptied by this operation. **/ public inline function toString() : String { diff --git a/std/StringTools.hx b/std/StringTools.hx index be4cec5daec40e093147c39e4b540e32203f59d0..23fb84d7db1e674d3a3aca9572e817822a75a04a 100644 --- a/std/StringTools.hx +++ b/std/StringTools.hx @@ -26,31 +26,30 @@ If the first argument to any of the methods is null, the result is unspecified. **/ -#if cs -@:keep +#if cpp +using cpp.NativeString; #end class StringTools { - /** Encode an URL by using the standard format. **/ - public static function urlEncode( s : String ) : String untyped { - #if flash9 - return __global__["encodeURIComponent"](s); - #elseif flash - return _global["escape"](s); + #if (!java && !cpp) inline #end public static function urlEncode( s : String ) : String { + #if flash + return untyped __global__["encodeURIComponent"](s); #elseif neko - return new String(_urlEncode(s.__s)); + return untyped new String(_urlEncode(s.__s)); #elseif js - return encodeURIComponent(s); + return untyped encodeURIComponent(s); #elseif cpp - return s.__URLEncode(); + return untyped s.__URLEncode(); #elseif java try return untyped __java__("java.net.URLEncoder.encode(s, \"UTF-8\")") catch (e:Dynamic) throw e; #elseif cs - return untyped __cs__("System.Uri.EscapeUriString(s)"); + return untyped cs.system.Uri.EscapeDataString(s); + #elseif python + return python.lib.urllib.Parse.quote(s, ""); #else return null; #end @@ -59,38 +58,41 @@ class StringTools { /** Decode an URL using the standard format. **/ - public static function urlDecode( s : String ) : String untyped { - #if flash9 - return __global__["decodeURIComponent"](s.split("+").join(" ")); - #elseif flash - return _global["unescape"](s); + #if (!java && !cpp) inline #end public static function urlDecode( s : String ) : String { + #if flash + return untyped __global__["decodeURIComponent"](s.split("+").join(" ")); #elseif neko - return new String(_urlDecode(s.__s)); + return untyped new String(_urlDecode(s.__s)); #elseif js - return decodeURIComponent(s.split("+").join(" ")); + return untyped decodeURIComponent(s.split("+").join(" ")); #elseif cpp - return s.__URLDecode(); + return untyped s.__URLDecode(); #elseif java try return untyped __java__("java.net.URLDecoder.decode(s, \"UTF-8\")") catch (e:Dynamic) throw e; #elseif cs - return untyped __cs__("System.Uri.UnescapeDataString(s)"); + return untyped cs.system.Uri.UnescapeDataString(s); + #elseif python + return python.lib.urllib.Parse.unquote(s); #else return null; #end } /** - Escapes HTML special characters of the string [s]. + Escapes HTML special characters of the string `s`. The following replacements are made: - - & becomes & - - < becomes < - - > becomes > - If [quotes] is true, the following characters are also replaced: - - " becomes " - - ' becomes ' + + - `&` becomes `&`; + - `<` becomes `<`; + - `>` becomes `>`; + + If `quotes` is true, the following characters are also replaced: + + - `"` becomes `"`; + - `'` becomes `'`; **/ public static function htmlEscape( s : String, ?quotes : Bool ) : String { s = s.split("&").join("&").split("<").join("<").split(">").join(">"); @@ -98,51 +100,70 @@ class StringTools { } /** - Unescapes HTML special characters of the string [s]. + Unescapes HTML special characters of the string `s`. This is the inverse operation to htmlEscape, i.e. the following always holds: htmlUnescape(htmlEscape(s)) == s The replacements follow: - - & becomes & - - < becomes < - - > becomes > - - " becomes " - - ' becomes ' + + - `&` becomes `&` + - `<` becomes `<` + - `>` becomes `>` + - `"` becomes `"` + - `'` becomes `'` **/ public static function htmlUnescape( s : String ) : String { return s.split(">").join(">").split("<").join("<").split(""").join('"').split("'").join("'").split("&").join("&"); } /** - Tells if the string [s] starts with the string [start]. + Tells if the string `s` starts with the string `start`. - If [start] is null, the result is unspecified. + If `start` is null, the result is unspecified. - If [start] is the empty String "", the result is true. + If `start` is the empty String "", the result is true. **/ public static #if (cs || java) inline #end function startsWith( s : String, start : String ) : Bool { #if java return untyped s.startsWith(start); #elseif cs return untyped s.StartsWith(start); + #elseif cpp + if (s.length= start.length && s.substr(0, start.length) == start ); #end } /** - Tells if the string [s] ends with the string [end]. + Tells if the string `s` ends with the string `end`. - If [end] is null, the result is unspecified. + If `end` is null, the result is unspecified. - If [end] is the empty String "", the result is true. + If `end` is the empty String "", the result is true. **/ public static #if (cs || java) inline #end function endsWith( s : String, end : String ) : Bool { #if java return untyped s.endsWith(end); #elseif cs return untyped s.EndsWith(end); + #elseif cpp + if (s.length= s.length) return false; + #end var c = s.charCodeAt( pos ); return (c > 8 && c < 14) || c == 32; } /** - Removes leading space characters of [s]. + Removes leading space characters of `s`. This function internally calls isSpace() to decide which characters to remove. - If [s] is the empty String "" or consists only of space characters, the + If `s` is the empty String "" or consists only of space characters, the result is the empty String "". **/ public #if cs inline #end static function ltrim( s : String ) : String { @@ -190,12 +214,12 @@ class StringTools { } /** - Removes trailing space characters of [s]. + Removes trailing space characters of `s`. This function internally calls isSpace() to decide which characters to remove. - If [s] is the empty String "" or consists only of space characters, the + If `s` is the empty String "" or consists only of space characters, the result is the empty String "". **/ public #if cs inline #end static function rtrim( s : String ) : String { @@ -216,7 +240,7 @@ class StringTools { } /** - Removes leading and trailing space characters of [s]. + Removes leading and trailing space characters of `s`. This is a convenience function for ltrim(rtrim(s)). **/ @@ -231,16 +255,16 @@ class StringTools { } /** - Concatenates [c] to [s] until [s].length is at least [l]. + Concatenates `c` to `s` until `s.length` is at least `l`. - If [c] is the empty String "" or if [l] does not exceed [s].length, - [s] is returned unchanged. + If `c` is the empty String "" or if `l` does not exceed `s.length`, + `s` is returned unchanged. - If [c].length is 1, the resulting String length is exactly [l]. + If `c.length` is 1, the resulting String length is exactly `l`. - Otherwise the length may exceed [l]. + Otherwise the length may exceed `l`. - If [c] is null, the result is unspecified. + If `c` is null, the result is unspecified. **/ public static function lpad( s : String, c : String, l : Int ) : String { if (c.length <= 0) @@ -253,16 +277,16 @@ class StringTools { } /** - Appends [c] to [s] until [s].length is at least [l]. + Appends `c` to `s` until `s.length` is at least `l`. - If [c] is the empty String "" or if [l] does not exceed [s].length, - [s] is returned unchanged. + If `c` is the empty String "" or if `l` does not exceed `s.length`, + `s` is returned unchanged. - If [c].length is 1, the resulting String length is exactly [l]. + If `c.length` is 1, the resulting String length is exactly `l`. - Otherwise the length may exceed [l]. + Otherwise the length may exceed `l`. - If [c] is null, the result is unspecified. + If `c` is null, the result is unspecified. **/ public static function rpad( s : String, c : String, l : Int ) : String { if (c.length <= 0) @@ -275,15 +299,15 @@ class StringTools { } /** - Replace all occurences of the String [sub] in the String [s] by the - String [by]. + Replace all occurences of the String `sub` in the String `s` by the + String `by`. - If [sub] is the empty String "", [by] is inserted after each character - of [s]. If [by] is also the empty String "", [s] remains unchanged. + If `sub` is the empty String "", `by` is inserted after each character + of `s`. If `by` is also the empty String "", `s` remains unchanged. - This is a convenience function for [s].split([sub]).join([by]). + This is a convenience function for `s.split(sub).join(by)`. - If [sub] or [by] are null, the result is unspecified. + If `sub` or `by` are null, the result is unspecified. **/ public static function replace( s : String, sub : String, by : String ) : String { #if java @@ -302,13 +326,13 @@ class StringTools { } /** - Encodes [n] into a hexadecimal representation. + Encodes `n` into a hexadecimal representation. - If [digits] is specified, the resulting String is padded with "0" until - its length equals [digits]. + If `digits` is specified, the resulting String is padded with "0" until + its length equals `digits`. **/ public static function hex( n : Int, ?digits : Int ) { - #if flash9 + #if flash var n : UInt = n; var s : String = untyped n.toString(16); s = s.toUpperCase(); @@ -320,54 +344,61 @@ class StringTools { n >>>= 4; } while( n > 0 ); #end + #if python + if (digits != null && s.length < digits) { + var diff = digits - s.length; + for (_ in 0...diff) { + s = "0" + s; + } + } + #else if( digits != null ) while( s.length < digits ) s = "0"+s; + #end return s; } /** - Returns the character code at position [index] of String [s]. + Returns the character code at position `index` of String `s`, or an + end-of-file indicator at if `position` equals `s.length`. + + This method is faster than String.charCodeAt() on some platforms, but + the result is unspecified if `index` is negative or greater than + `s.length`. - This method is faster than String.charCodeAt() on most platforms. - However, unlike String.charCodeAt(), the result is unspecified if - [index] is negative or exceeds [s].length. + End of file status can be checked by calling `StringTools.isEof` with + the returned value as argument. - This operation is not guaranteed to work if [s] contains the \0 + This operation is not guaranteed to work if `s` contains the \0 character. **/ - public static inline function fastCodeAt( s : String, index : Int ) : Int untyped { + public static inline function fastCodeAt( s : String, index : Int ) : Int { #if neko return untyped __dollar__sget(s.__s, index); #elseif cpp - return s.cca(index); - #elseif flash9 - return s.cca(index); + return untyped s.cca(index); #elseif flash - return s["cca"](index); + return untyped s.cca(index); #elseif java return ( index < s.length ) ? cast(_charAt(s, index), Int) : -1; #elseif cs - return ( cast(index, UInt) < s.length ) ? cast(untyped s[index], Int) : -1; + return ( cast(index, UInt) < s.length ) ? cast(s[index], Int) : -1; #elseif js - #if mt - return (untyped s).cca(index); - #else return (untyped s).charCodeAt(index); - #end + #elseif python + return if (index >= s.length) -1 else python.internal.UBuiltins.ord(python.Syntax.arrayAccess(s, index)); #else - return s.cca(index); + return untyped s.cca(index); #end } /* - Tells if [c] represents the end-of-file (EOF) character. + Tells if `c` represents the end-of-file (EOF) character. */ @:noUsing public static inline function isEof( c : Int ) : Bool { - #if (flash9 || cpp) + #if (flash || cpp) return c == 0; - #elseif flash8 - return c <= 0; // fast NaN #elseif js return c != c; // fast NaN #elseif neko @@ -376,6 +407,8 @@ class StringTools { return c == -1; #elseif java return c == -1; + #elseif python + return c == -1; #else return false; #end diff --git a/std/Sys.hx b/std/Sys.hx index c52c479e3c8b3c30298ce545a7e6ecaea190a37a..687a12485a8e3909ed97d43175c33ec57f412f12 100644 --- a/std/Sys.hx +++ b/std/Sys.hx @@ -1,132 +1,132 @@ -/* - * Copyright (C)2005-2012 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. - */ -/** - This class gives you access to many base functionalities of system platforms. Looks in [sys] sub packages for more system APIs. -**/ -@:require(sys) -extern class Sys { - - /** - Print any value on the standard output. - **/ - static function print( v : Dynamic ) : Void; - - /** - Print any value on the standard output, followed by a newline - **/ - static function println( v : Dynamic ) : Void; - - /** - Returns all the arguments that were passed by the commandline. - **/ - static function args() : Array; - - /** - Returns the value of the given environment variable. - **/ - static function getEnv( s : String ) : String; - - /** - Set the value of the given environment variable. - **/ - static function putEnv( s : String, v : String ) : Void; - - /** - Returns the whole environement variables. - **/ - static function environment() : haxe.ds.StringMap; - - /** - Suspend the current execution for the given time (in seconds). - **/ - static function sleep( seconds : Float ) : Void; - - /** - Change the current time locale, which will affect [DateTools.format] date formating. - Returns true if the locale was successfully changed - **/ - static function setTimeLocale( loc : String ) : Bool; - - /** - Get the current working directory (usually the one in which the program was started) - **/ - static function getCwd() : String; - - /** - Change the current working directory. - **/ - static function setCwd( s : String ) : Void; - - /** - Returns the name of the system you are running on. For instance : - "Windows", "Linux", "BSD" and "Mac" depending on your desktop OS. - **/ - static function systemName() : String; - - /** - Run the given command with the list of arguments. The command output will be printed on the same output as the current process. - The current process will block until the command terminates and it will return the command result (0 if there was no error). - Read the [sys.io.Process] api for a more complete way to start background processes. - **/ - static function command( cmd : String, ?args : Array ) : Int; - - /** - Exit the current process with the given error code. - **/ - static function exit( code : Int ) : Void; - - /** - Gives the most precise timestamp value (in seconds). - **/ - static function time() : Float; - - /** - Gives the most precise timestamp value (in seconds) but only account for the actual time spent running on the CPU for the current thread/process. - **/ - static function cpuTime() : Float; - - /** - Returns the path to the current executable that we are running. - **/ - static function executablePath() : String; - - /** - Read a single input character from the standard input (without blocking) and returns it. Setting [echo] to true will also display it on the output. - **/ - static function getChar( echo : Bool ) : Int; - - /** - Returns the process standard input, from which you can read what user enters. Usually it will block until the user send a full input line. See [getChar] for an alternative. - **/ - static function stdin() : haxe.io.Input; - - /** - Returns the process standard output on which you can write. - **/ - static function stdout() : haxe.io.Output; - - /** - Returns the process standard error on which you can write. - **/ - static function stderr() : haxe.io.Output; - +/* + * Copyright (C)2005-2012 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. + */ +/** + This class gives you access to many base functionalities of system platforms. Looks in [sys] sub packages for more system APIs. +**/ +@:require(sys) +extern class Sys { + + /** + Print any value on the standard output. + **/ + static function print( v : Dynamic ) : Void; + + /** + Print any value on the standard output, followed by a newline + **/ + static function println( v : Dynamic ) : Void; + + /** + Returns all the arguments that were passed by the commandline. + **/ + static function args() : Array; + + /** + Returns the value of the given environment variable. + **/ + static function getEnv( s : String ) : String; + + /** + Set the value of the given environment variable. + **/ + static function putEnv( s : String, v : String ) : Void; + + /** + Returns the whole environement variables. + **/ + static function environment() : Map; + + /** + Suspend the current execution for the given time (in seconds). + **/ + static function sleep( seconds : Float ) : Void; + + /** + Change the current time locale, which will affect [DateTools.format] date formating. + Returns true if the locale was successfully changed + **/ + static function setTimeLocale( loc : String ) : Bool; + + /** + Get the current working directory (usually the one in which the program was started) + **/ + static function getCwd() : String; + + /** + Change the current working directory. + **/ + static function setCwd( s : String ) : Void; + + /** + Returns the name of the system you are running on. For instance : + "Windows", "Linux", "BSD" and "Mac" depending on your desktop OS. + **/ + static function systemName() : String; + + /** + Run the given command with the list of arguments. The command output will be printed on the same output as the current process. + The current process will block until the command terminates and it will return the command result (0 if there was no error). + Read the [sys.io.Process] api for a more complete way to start background processes. + **/ + static function command( cmd : String, ?args : Array ) : Int; + + /** + Exit the current process with the given error code. + **/ + static function exit( code : Int ) : Void; + + /** + Gives the most precise timestamp value (in seconds). + **/ + static function time() : Float; + + /** + Gives the most precise timestamp value (in seconds) but only account for the actual time spent running on the CPU for the current thread/process. + **/ + static function cpuTime() : Float; + + /** + Returns the path to the current executable that we are running. + **/ + static function executablePath() : String; + + /** + Read a single input character from the standard input (without blocking) and returns it. Setting [echo] to true will also display it on the output. + **/ + static function getChar( echo : Bool ) : Int; + + /** + Returns the process standard input, from which you can read what user enters. Usually it will block until the user send a full input line. See [getChar] for an alternative. + **/ + static function stdin() : haxe.io.Input; + + /** + Returns the process standard output on which you can write. + **/ + static function stdout() : haxe.io.Output; + + /** + Returns the process standard error on which you can write. + **/ + static function stderr() : haxe.io.Output; + } \ No newline at end of file diff --git a/std/Type.hx b/std/Type.hx index 011363ca1320692e6dfb142a3960b96d2c183c37..fe1c831552c2c688e3ab1f8a53e30f1bab047024 100644 --- a/std/Type.hx +++ b/std/Type.hx @@ -21,7 +21,6 @@ */ /** The diffent possible runtime types of a value. - See [Type] for the haXe Reflection API. **/ enum ValueType { TNull; @@ -37,262 +36,262 @@ enum ValueType { /** The haxe Reflection API allows retrieval of type information at runtime. - + This class complements the more lightweight Reflect class, with a focus on class and enum instances. **/ extern class Type { /** - Returns the class of [o], if [o] is a class instance. - - If [o] is null or of a different type, null is returned. - + Returns the class of `o`, if `o` is a class instance. + + If `o` is null or of a different type, null is returned. + In general, type parameter information cannot be obtained at runtime. **/ public static function getClass( o : T ) : Class; /** - Returns the enum of enum instance [o]. - + Returns the enum of enum instance `o`. + An enum instance is the result of using an enum constructor. Given an - enum Color { Red; }, getEnum(Red) returns Enum. - - If [o] is null, null is returned. - + `enum Color { Red; }`, `getEnum(Red)` returns `Enum`. + + If `o` is null, null is returned. + In general, type parameter information cannot be obtained at runtime. **/ public static function getEnum( o : EnumValue ) : Enum; /** - Returns the super-class of class [c]. - - If [c] has no super class, null is returned. - - If [c] is null, the result is unspecified. - + Returns the super-class of class `c`. + + If `c` has no super class, null is returned. + + If `c` is null, the result is unspecified. + In general, type parameter information cannot be obtained at runtime. **/ public static function getSuperClass( c : Class ) : Class; /** - Returns the name of class [c], including its path. - - If [c] is inside a package, the package structure is returned dot- + Returns the name of class `c`, including its path. + + If `c` is inside a package, the package structure is returned dot- separated, with another dot separating the class name: - pack1.pack2.(...).packN.ClassName - If [c] is a sub-type of a haxe module, that module is not part of the + `pack1.pack2.(...).packN.ClassName` + If `c` is a sub-type of a haxe module, that module is not part of the package structure. - - If [c] has no package, the class name is returned. - - If [c] is null, the result is unspecified. - + + If `c` has no package, the class name is returned. + + If `c` is null, the result is unspecified. + The class name does not include any type parameters. **/ public static function getClassName( c : Class ) : String; /** - Returns the name of enum [e], including its path. - - If [e] is inside a package, the package structure is returned dot- + Returns the name of enum `e`, including its path. + + If `e` is inside a package, the package structure is returned dot- separated, with another dot separating the enum name: - pack1.pack2.(...).packN.EnumName - If [e] is a sub-type of a haxe module, that module is not part of the + `pack1.pack2.(...).packN.EnumName` + If `e` is a sub-type of a haxe module, that module is not part of the package structure. - - If [e] has no package, the enum name is returned. - - If [e] is null, the result is unspecified. - + + If `e` has no package, the enum name is returned. + + If `e` is null, the result is unspecified. + The enum name does not include any type parameters. **/ public static function getEnumName( e : Enum ) : String; /** Resolves a class by name. - - If [name] is the path of an existing class, that class is returned. - + + If `name` is the path of an existing class, that class is returned. + Otherwise null is returned. - - If [name] is null or the path to a different type, the result is + + If `name` is null or the path to a different type, the result is unspecified. - + The class name must not include any type parameters. **/ public static function resolveClass( name : String ) : Class; /** Resolves an enum by name. - - If [name] is the path of an existing enum, that enum is returned. - + + If `name` is the path of an existing enum, that enum is returned. + Otherwise null is returned. - - If [name] is null the result is unspecified. - - If [name] is the path to a different type, null is returned. - + + If `name` is null the result is unspecified. + + If `name` is the path to a different type, null is returned. + The enum name must not include any type parameters. **/ public static function resolveEnum( name : String ) : Enum; /** - Creates an instance of class [cl], using [args] as arguments to the + Creates an instance of class `cl`, using `args` as arguments to the class constructor. - + This function guarantees that the class constructor is called. - + Default values of constructors arguments are not guaranteed to be taken into account. - - If [cl] or [args] are null, or if the number of elements in [args] does + + If `cl` or `args` are null, or if the number of elements in `args` does not match the expected number of constructor arguments, or if any - argument has an invalid type, or if [cl] has no own constructor, the + argument has an invalid type, or if `cl` has no own constructor, the result is unspecified. - + In particular, default values of constructor arguments are not guaranteed to be taken into account. **/ public static function createInstance( cl : Class, args : Array ) : T; - + /** - Creates an instance of class [cl]. - + Creates an instance of class `cl`. + This function guarantees that the class constructor is not called. - - If [cl] is null, the result is unspecified. + + If `cl` is null, the result is unspecified. **/ public static function createEmptyInstance( cl : Class ) : T; /** - Creates an instance of enum [e] by calling its constructor [constr] with - arguments [params]. - - If [e] or [constr] is null, or if enum [e] has no constructor named - [constr], or if the number of elements in [params] does not match the + Creates an instance of enum `e` by calling its constructor `constr` with + arguments `params`. + + If `e` or `constr` is null, or if enum `e` has no constructor named + `constr`, or if the number of elements in `params` does not match the 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; /** - Creates an instance of enum [e] by calling its constructor number - [index] with arguments [params]. - + Creates an instance of enum `e` by calling its constructor number + `index` with arguments `params`. + The constructor indices are preserved from haxe syntax, so the first declared is index 0, the next index 1 etc. - - If [e] or [constr] is null, or if enum [e] has no constructor named - [constr], or if the number of elements in [params] does not match the + + If `e` or `constr` is null, or if enum `e` has no constructor named + `constr`, or if the number of elements in `params` does not match the 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; /** - Returns a list of the instance fields of class [c]. - + Returns a list of the instance fields of class `c`. + This only includes fields which are known at compile-time. In particular, using getInstanceFields(getClass(obj)) will not include any fields which were added to obj at runtime. - + The order of the fields in the returned Array is unspecified. - - If [c] is null, the result 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; /** - Returns a list of static fields of class [c]. - + Returns a list of static fields of class `c`. + This does not include static fields of parent classes. - + The order of the fields in the returned Array is unspecified. - - If [c] is null, the result 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; /** - Returns a list of the names of all constructors of enum [e]. - + Returns a list of the names of all constructors of enum `e`. + The order of the constructor names in the returned Array is preserved from the original syntax. - - If [c] is null, the result is unspecified. + + If `c` is null, the result is unspecified. **/ public static function getEnumConstructs( e : Enum ) : Array; /** - Returns the runtime type of value [v]. - - The result corresponds to the type [v] has at runtime, which may vary + Returns the runtime type of value `v`. + + The result corresponds to the type `v` has at runtime, which may vary per platform. Assumptions regarding this should be minimized to avoid surprises. **/ public static function typeof( v : Dynamic ) : ValueType; /** - Recursively compares two enum instances [a] and [b] by value. - - Unlike [a] == [b], this function performs a deep equality check on the + Recursively compares two enum instances `a` and `b` by value. + + Unlike `a == b`, this function performs a deep equality check on the arguments of the constructors, if exists. - - If [a] or [b] are null, the result is unspecified. + + If `a` or `b` are null, the result is unspecified. **/ public static function enumEq( a : T, b : T ) : Bool; /** - Returns the constructor name of enum instance [e]. - + Returns the constructor name of enum instance `e`. + The result String does not contain any constructor arguments. - - If [e] is null, the result is unspecified. + + If `e` is null, the result is unspecified. **/ public static function enumConstructor( e : EnumValue ) : String; /** - Returns a list of the constructor arguments of enum instance [e]. - - If [e] has no arguments, the result is []. - - Otherwise the result are the values that were used as arguments to [e], + Returns a list of the constructor arguments of enum instance `e`. + + If `e` has no arguments, the result is []. + + Otherwise the result are the values that were used as arguments to `e`, in the order of their declaration. - - If [e] is null, the result is unspecified. + + If `e` is null, the result is unspecified. **/ public static function enumParameters( e : EnumValue ) : Array; /** - Returns the index of enum instance [e]. - - This corresponds to the original syntactic position of [e]. The index of + Returns the index of enum instance `e`. + + This corresponds to the original syntactic position of `e`. The index of the first declared constructor is 0, the next one is 1 etc. - - If [e] is null, the result is unspecified. + + If `e` is null, the result is unspecified. **/ public static function enumIndex( e : EnumValue ) : Int; /** - Returns a list of all constructors of enum [e] that require no + Returns a list of all constructors of enum `e` that require no arguments. - - This may return the empty Array [] if all constructors of [e] require + + This may return the empty Array [] if all constructors of `e` require arguments. - - Otherwise an instance of [e] constructed through each of its non- + + Otherwise an instance of `e` constructed through each of its non- argument constructors is returned, in the order of the constructor declaration. - - If [e] is null, the result is unspecified. + + If `e` is null, the result is unspecified. **/ public static function allEnums( e : Enum ) : Array; diff --git a/std/UInt.hx b/std/UInt.hx new file mode 100644 index 0000000000000000000000000000000000000000..458ce7f4602c76d8272676bd508d83c5ecea1376 --- /dev/null +++ b/std/UInt.hx @@ -0,0 +1,290 @@ +/* + * Copyright (C)2005-2013 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. + */ + +#if ((flash || flash9doc || cs) && !doc_gen) +/** + The unsigned Int type is only defined for Flash and C#. It's currently + handled the same as a normal Int. +**/ +@:coreType +@:notNull +@:runtimeValue +@:analyzer(no_const_propagation) +abstract UInt to Int from Int +{ + @:commutative @:op(A+B) private static function addI(lhs:UInt, rhs:Int):UInt; + @:commutative @:op(A+B) private static function addF(lhs:UInt, rhs:Float):Float; + @:op(A+B) private static function add(lhs:UInt, rhs:UInt):UInt; + + @:commutative @:op(A*B) private static function mulI(lhs:UInt, rhs:Int):UInt; + @:commutative @:op(A*B) private static function mulF(lhs:UInt, rhs:Float):Float; + @:op(A*B) private static function mul(lhs:UInt, rhs:UInt):UInt; + + @:op(A%B) private static function modI(lhs:UInt, rhs:Int):UInt; + @:op(A%B) private static function modF(lhs:UInt, rhs:Float):Float; + @:op(A%B) private static function mod(lhs:UInt, rhs:UInt):UInt; + + @:op(A-B) private static function subI(lhs:UInt, rhs:Int):UInt; + @:op(A-B) private static function subF(lhs:UInt, rhs:Float):Float; + @:op(A-B) private static function sub(lhs:UInt, rhs:UInt):UInt; + + @:op(A/B) private static function divI(lhs:UInt, rhs:Int):Float; + @:op(A/B) private static function divF(lhs:UInt, rhs:Float):Float; + @:op(A/B) private static function div(lhs:UInt, rhs:UInt):Float; + + @:commutative @:op(A|B) private static function orI(lhs:UInt, rhs:Int):UInt; + @:op(A|B) private static function or(lhs:UInt, rhs:UInt):UInt; + + @:commutative @:op(A^B) private static function xorI(lhs:UInt, rhs:Int):UInt; + @:op(A^B) private static function xor(lhs:UInt, rhs:UInt):UInt; + + @:commutative @:op(A&B) private static function andI(lhs:UInt, rhs:Int):UInt; + @:op(A&B) private static function and(lhs:UInt, rhs:UInt):UInt; + + @:op(A<>B) private static function shr(lhs:UInt, rhs:Int):UInt; + @:op(A>>>B) private static function ushr(lhs:UInt, rhs:Int):UInt; + + @:op(A>B) private static function gt(lhs:UInt, rhs:UInt):Bool; + @:op(A>=B) private static function gte(lhs:UInt, rhs:UInt):Bool; + @:op(AB) private static function gtf(lhs:UInt, rhs:Float):Bool; + @:op(A>B) private static function gtf(lhs:Float, rhs:UInt):Bool; + @:op(A>=B) private static function gtef(lhs:UInt, rhs:Float):Bool; + @:op(A>=B) private static function gtef(lhs:Float, rhs:UInt):Bool; + @:op(A(a:UInt, b:T):Bool; + @:commutative @:op(A != B) private static function notEqualsInt(a:UInt, b:T):Bool; + @:commutative @:op(A == B) private static function equalsFloat(a:UInt, b:T):Bool; + @:commutative @:op(A != B) private static function notEqualsFloat(a:UInt, b:T):Bool; + + @:op(++A) private function prefixIncrement():UInt; + @:op(A++) private function postfixIncrement():UInt; + @:op(--A) private function prefixDecrement():UInt; + @:op(A--) private function postfixDecrement():UInt; +} +#else +/** + The unsigned Int type is only defined for Flash and C#. + Simulate it for other platforms. +**/ +abstract UInt(Int) from Int to Int { + + @:op(A + B) private static inline function add(a:UInt, b:UInt):UInt { + return a.toInt() + b.toInt(); + } + + @:op(A / B) private static inline function div(a:UInt, b:UInt):Float { + return a.toFloat() / b.toFloat(); + } + + @:op(A * B) private static inline function mul(a:UInt, b:UInt):UInt { + return a.toInt() * b.toInt(); + } + + @:op(A - B) private static inline function sub(a:UInt, b:UInt):UInt { + return a.toInt() - b.toInt(); + } + + @:op(A > B) private static #if !js inline #end function gt(a:UInt, b:UInt):Bool { + var aNeg = a.toInt() < 0; + var bNeg = b.toInt() < 0; + return + if( aNeg != bNeg ) aNeg; + else a.toInt() > b.toInt(); + } + + @:op(A >= B) private static #if !js inline #end function gte(a:UInt, b:UInt):Bool { + var aNeg = a.toInt() < 0; + var bNeg = b.toInt() < 0; + return + if( aNeg != bNeg ) aNeg; + else a.toInt() >= b.toInt(); + } + + @:op(A < B) private static inline function lt(a:UInt, b:UInt):Bool { + return gt(b, a); + } + + @:op(A <= B) private static inline function lte(a:UInt, b:UInt):Bool { + return gte(b, a); + } + + @:op(A & B) private static inline function and(a:UInt, b:UInt):UInt { + return a.toInt() & b.toInt(); + } + + @:op(A | B) private static inline function or(a:UInt, b:UInt):UInt { + return a.toInt() | b.toInt(); + } + + @:op(A ^ B) private static inline function xor(a:UInt, b:UInt):UInt { + return a.toInt() ^ b.toInt(); + } + + @:op(A << B) private static inline function shl(a:UInt, b:Int):UInt { + return a.toInt() << b; + } + + @:op(A >> B) private static inline function shr(a:UInt, b:Int):UInt { + return a.toInt() >> b; + } + + @:op(A >>> B) private static inline function ushr(a:UInt, b:Int):UInt { + return a.toInt() >>> b; + } + + @:op(A % B) private static inline function mod(a:UInt, b:UInt):UInt { + return Std.int( a.toFloat() % b.toFloat() ); + } + + @:commutative @:op(A + B) private static inline function addWithFloat(a:UInt, b:Float):Float { + return a.toFloat() + b; + } + + @:commutative @:op(A * B) private static inline function mulWithFloat(a:UInt, b:Float):Float { + return a.toFloat() * b; + } + + @:op(A / B) private static inline function divFloat(a:UInt, b:Float):Float { + return a.toFloat() / b; + } + + @:op(A / B) private static inline function floatDiv(a:Float, b:UInt):Float { + return a / b.toFloat(); + } + + @:op(A - B) private static inline function subFloat(a:UInt, b:Float):Float { + return a.toFloat() - b; + } + + @:op(A - B) private static inline function floatSub(a:Float, b:UInt):Float { + return a - b.toFloat(); + } + + @:op(A > B) private static inline function gtFloat(a:UInt, b:Float):Bool { + return a.toFloat() > b; + } + + @:commutative @:op(A == B) private static inline function equalsInt(a:UInt, b:T):Bool { + return a.toInt() == b; + } + + @:commutative @:op(A != B) private static inline function notEqualsInt(a:UInt, b:T):Bool { + return a.toInt() != b; + } + + @:commutative @:op(A == B) private static inline function equalsFloat(a:UInt, b:T):Bool { + return a.toFloat() == b; + } + + @:commutative @:op(A != B) private static inline function notEqualsFloat(a:UInt, b:T):Bool { + return a.toFloat() != b; + } + + @:op(A >= B) private static inline function gteFloat(a:UInt, b:Float):Bool { + return a.toFloat() >= b; + } + + + @:op(A > B) private static inline function floatGt(a:Float, b:UInt):Bool { + return a > b.toFloat(); + } + + @:op(A >= B) private static inline function floatGte(a:Float, b:UInt):Bool { + return a >= b.toFloat(); + } + + @:op(A < B) private static inline function ltFloat(a:UInt, b:Float):Bool { + return a.toFloat() < b; + } + + @:op(A <= B) private static inline function lteFloat(a:UInt, b:Float):Bool { + return a.toFloat() <= b; + } + + @:op(A < B) private static inline function floatLt(a:Float, b:UInt):Bool { + return a < b.toFloat(); + } + + @:op(A <= B) private static inline function floatLte(a:Float, b:UInt):Bool { + return a <= b.toFloat(); + } + + @:op(A % B) private static inline function modFloat(a:UInt, b:Float):Float { + return a.toFloat() % b; + } + + @:op(A % B) private static inline function floatMod(a:Float, b:UInt):Float { + return a % b.toFloat(); + } + + @:op(~A) private inline function negBits():UInt { + return ~this; + } + + @:op(++A) private inline function prefixIncrement():UInt { + return ++this; + } + + @:op(A++) private inline function postfixIncrement():UInt { + return this++; + } + + @:op(--A) private inline function prefixDecrement():UInt { + return --this; + } + + @:op(A--) private inline function postfixDecrement():UInt { + return this--; + } + + // TODO: radix is just defined to deal with doc_gen issues + private inline function toString(?radix:Int):String { + return Std.string(toFloat()); + } + + private inline function toInt():Int { + return this; + } + + @:to private #if (!js || analyzer) inline #end function toFloat():Float { + var int = toInt(); + if (int < 0) { + return 4294967296.0 + int; + } + else { + // + 0.0 here to make sure we promote to Float on some platforms + // In particular, PHP was having issues when comparing to Int in the == op. + return int + 0.0; + } + } +} +#end diff --git a/std/Xml.hx b/std/Xml.hx index 0671b4f014983b8edd626f1c8c9e40614fa49373..0cd40d403bb0ca04fa3afc03069828b329074484 100644 --- a/std/Xml.hx +++ b/std/Xml.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2012 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,201 +19,309 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -/** - An abstract type representing the type of the Xml - Node. You can compare it to [Xml] statics and can - use [Std.string(t)] to get a string reprensation - of the type. -**/ - - -enum XmlType { +@:enum abstract XmlType(Int) { + var Element = 0; + var PCData = 1; + var CData = 2; + var Comment = 3; + var DocType = 4; + var ProcessingInstruction = 5; + var Document = 6; } -/** - The standard Xml class and parsing. - More API to manipulate XML are available in the [haxe.xml] package. -**/ +class Xml { -extern class Xml { + static public var Element(default,null) = XmlType.Element; + static public var PCData(default,null) = XmlType.PCData; + static public var CData(default,null) = XmlType.CData; + static public var Comment(default,null) = XmlType.Comment; + static public var DocType(default,null) = XmlType.DocType; + static public var ProcessingInstruction(default,null) = XmlType.ProcessingInstruction; + static public var Document(default,null) = XmlType.Document; - /** - A type of Xml node. - **/ - static var Element(default,null) : XmlType; + static public function parse( str : String ) : Xml { + return haxe.xml.Parser.parse(str); + } /** - A type of Xml node. + Returns the type of the Xml Node. This should be used before + accessing other functions since some might raise an exception + if the node type is not correct. **/ - static var PCData(default,null) : XmlType; + public var nodeType(default, null) : XmlType; /** - A type of Xml node. + Returns the node name of an Element. **/ - static var CData(default,null) : XmlType; + @:isVar public var nodeName(get, set) : String; /** - A type of Xml node. + Returns the node value. Only works if the Xml node is not an Element or a Document. **/ - static var Comment(default,null) : XmlType; + @:isVar public var nodeValue(get, set) : String; /** - A type of Xml node. + Returns the parent object in the Xml hierarchy. + The parent can be [null], an Element or a Document. **/ - static var DocType(default,null) : XmlType; + public var parent(default, null) : Xml; - /** - A type of Xml node. - **/ - static var ProcessingInstruction(default,null) : XmlType; + var children:Array; + var attributeMap:Map; - /** - A type of Xml node. - **/ - static var Document(default,null) : XmlType; + inline function get_nodeName() { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + return nodeName; + } - /** - Parse a String into an Xml object. - **/ - static function parse( str : String ) : Xml; + inline function set_nodeName(v) { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + return this.nodeName = v; + } - /** - Creates a node of the given type. - **/ - static function createElement( name : String ) : Xml; + inline function get_nodeValue() { + if (nodeType == Document || nodeType == Element) { + throw 'Bad node type, unexpected $nodeType'; + } + return nodeValue; + } - /** - Creates a node of the given type. - **/ - static function createPCData( data : String ) : Xml; + inline function set_nodeValue(v) { + if (nodeType == Document || nodeType == Element) { + throw 'Bad node type, unexpected $nodeType'; + } + return this.nodeValue = v; + } /** Creates a node of the given type. **/ - static function createCData( data : String ) : Xml; + static public function createElement( name : String ) : Xml { + var xml = new Xml(Element); + xml.nodeName = name; + return xml; + } /** Creates a node of the given type. **/ - static function createComment( data : String ) : Xml; + static public function createPCData( data : String ) : Xml { + var xml = new Xml(PCData); + xml.nodeValue = data; + return xml; + } /** Creates a node of the given type. **/ - static function createDocType( data : String ) : Xml; + static public function createCData( data : String ) : Xml { + var xml = new Xml(CData); + xml.nodeValue = data; + return xml; + } /** Creates a node of the given type. **/ - static function createProcessingInstruction( data : String ) : Xml; + static public function createComment( data : String ) : Xml { + var xml = new Xml(Comment); + xml.nodeValue = data; + return xml; + } /** Creates a node of the given type. **/ - static function createDocument() : Xml; - - /** - Returns the type of the Xml Node. This should be used before - accessing other functions since some might raise an exception - if the node type is not correct. - **/ - var nodeType(default,null) : XmlType; + static public function createDocType( data : String ) : Xml { + var xml = new Xml(DocType); + xml.nodeValue = data; + return xml; + } /** - Returns the node name of an Element. + Creates a node of the given type. **/ - var nodeName(get,set) : String; + static public function createProcessingInstruction( data : String ) : Xml { + var xml = new Xml(ProcessingInstruction); + xml.nodeValue = data; + return xml; + } /** - Returns the node value. Only works if the Xml node is not an Element or a Document. + Creates a node of the given type. **/ - var nodeValue(get,set) : String; + static public function createDocument() : Xml { + return new Xml(Document); + } /** Get the given attribute of an Element node. Returns [null] if not found. Attributes are case-sensitive. **/ - function get( att : String ) : String; // check case insensitivy + public function get( att : String ) : String { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + return attributeMap[att]; + } /** Set the given attribute value for an Element node. Attributes are case-sensitive. **/ - function set( att : String, value : String ) : Void; + public function set( att : String, value : String ) : Void { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + attributeMap.set(att, value); + } /** Removes an attribute for an Element node. Attributes are case-sensitive. **/ - function remove( att : String ) : Void; + public function remove( att : String ) : Void { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + attributeMap.remove(att); + } /** Tells if the Element node has a given attribute. Attributes are case-sensitive. **/ - function exists( att : String ) : Bool; + public function exists( att : String ) : Bool { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + return attributeMap.exists(att); + } /** Returns an [Iterator] on all the attribute names. **/ - function attributes() : Iterator; - - /** - Returns the parent object in the Xml hierarchy. - The parent can be [null], an Element or a Document. - **/ - var parent(get,null) : Xml; + public function attributes() : Iterator { + if (nodeType != Element) { + throw 'Bad node type, expected Element but found $nodeType'; + } + return attributeMap.keys(); + } /** Returns an iterator of all child nodes. Only works if the current node is an Element or a Document. **/ - function iterator() : Iterator; + public inline function iterator() : Iterator { + ensureElementType(); + return children.iterator(); + } /** Returns an iterator of all child nodes which are Elements. Only works if the current node is an Element or a Document. **/ - function elements() : Iterator; + public function elements() : Iterator { + ensureElementType(); + var ret = [for (child in children) if (child.nodeType == Element) child]; + return ret.iterator(); + } /** Returns an iterator of all child nodes which are Elements with the given nodeName. Only works if the current node is an Element or a Document. **/ - function elementsNamed( name : String ) : Iterator; + public function elementsNamed( name : String ) : Iterator { + ensureElementType(); + var ret = [for (child in children) if (child.nodeType == Element && child.nodeName == name) child]; + return ret.iterator(); + } /** Returns the first child node. **/ - function firstChild() : Xml; + public inline function firstChild() : Xml { + ensureElementType(); + return children[0]; + } /** Returns the first child node which is an Element. **/ - function firstElement() : Xml; - + public function firstElement() : Xml { + ensureElementType(); + for (child in children) { + if (child.nodeType == Element) { + return child; + } + } + return null; + } /** Adds a child node to the Document or Element. - One node can only be inside one given node which is indicated by the [parent] property. + A child node can only be inside one given parent node, which is indicated by the [parent] property. + If the child is already inside this Document or Element, it will be moved to the last position among the Document or Element's children. + If the child node was previously inside a different node, it will be moved to this Document or Element. **/ - function addChild( x : Xml ) : Void; + public function addChild( x : Xml ) : Void { + ensureElementType(); + if (x.parent != null) { + x.parent.removeChild(x); + } + children.push(x); + x.parent = this; + } /** Removes a child from the Document or Element. Returns true if the child was successfuly removed. **/ - function removeChild( x : Xml ) : Bool; + public function removeChild( x : Xml ) : Bool { + ensureElementType(); + if (children.remove(x)) { + x.parent = null; + return true; + } + return false; + } /** Inserts a child at the given position among the other childs. + A child node can only be inside one given parent node, which is indicated by the [parent] property. + If the child is already inside this Document or Element, it will be moved to the new position among the Document or Element's children. + If the child node was previously inside a different node, it will be moved to this Document or Element. **/ - function insertChild( x : Xml, pos : Int ) : Void; + public function insertChild( x : Xml, pos : Int ) : Void { + ensureElementType(); + if (x.parent != null) { + x.parent.children.remove(x); + } + children.insert(pos, x); + x.parent = this; + } /** Returns a String representation of the Xml node. **/ - function toString() : String; - -} \ No newline at end of file + public inline function toString() : String { + return haxe.xml.Printer.print(this); + } + + function new(nodeType:XmlType) { + this.nodeType = nodeType; + children = []; + attributeMap = new Map(); + } + + inline function ensureElementType() { + if (nodeType != Document && nodeType != Element) { + throw 'Bad node type, expected Element or Document but found $nodeType'; + } + } +} diff --git a/std/cpp/ArrayBase.hx b/std/cpp/ArrayBase.hx new file mode 100644 index 0000000000000000000000000000000000000000..06e26eab204875211b4aa3994bf6a4a18872481e --- /dev/null +++ b/std/cpp/ArrayBase.hx @@ -0,0 +1,11 @@ +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; +} + diff --git a/std/cpp/Callable.hx b/std/cpp/Callable.hx new file mode 100644 index 0000000000000000000000000000000000000000..6488a1dc072b869b7e9054aad89a1010d4e18fec --- /dev/null +++ b/std/cpp/Callable.hx @@ -0,0 +1,22 @@ +package cpp; + +#if cpp + +typedef Callable = Function + +#else + +@:noPackageRestrict +abstract Callable(T) +{ + public var call(get,never):T; + + inline public function new(inValue:T) this = inValue; + + inline function get_call():T return this; +} + + +#end + + diff --git a/std/cpp/CastCharStar.hx b/std/cpp/CastCharStar.hx new file mode 100644 index 0000000000000000000000000000000000000000..0d6d2957ee543e1029594b414d510fec2159550e --- /dev/null +++ b/std/cpp/CastCharStar.hx @@ -0,0 +1,13 @@ +package cpp; + +abstract CastCharStar( RawPointer ) to(RawPointer) +{ + inline function new(s:String) this = cast untyped s.__s; + + @:from + static public inline function fromString(s:String) return new CastCharStar(s); + + @:to + public inline function toPointer() return this; +} + diff --git a/std/cpp/Char.hx b/std/cpp/Char.hx new file mode 100644 index 0000000000000000000000000000000000000000..bff39e9ed99eb02b59a6607136200c9e9464b8ce --- /dev/null +++ b/std/cpp/Char.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Char from Int to Int {} diff --git a/std/cpp/ConstCharStar.hx b/std/cpp/ConstCharStar.hx new file mode 100644 index 0000000000000000000000000000000000000000..10818f955253f85c666295de3abe605c0c89a7be --- /dev/null +++ b/std/cpp/ConstCharStar.hx @@ -0,0 +1,16 @@ +package cpp; + +abstract ConstCharStar( RawConstPointer ) to(RawConstPointer) +{ + inline function new(s:String) this = untyped s.__s; + + @:from + static public inline function fromString(s:String) return new ConstCharStar(s); + + @:to @:extern + public inline function toString():String return new String(untyped this); + + @:to @:extern + public inline function toPointer() return this; +} + diff --git a/std/cpp/ConstPointer.hx b/std/cpp/ConstPointer.hx new file mode 100644 index 0000000000000000000000000000000000000000..27dd222c0a5ab62de9bcc26d7b8e9897a0473474 --- /dev/null +++ b/std/cpp/ConstPointer.hx @@ -0,0 +1,41 @@ +package cpp; + +@:coreType @:include("cpp/Pointer.h") @:native("cpp.Pointer") +@:analyzer(no_simplification) +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:T; + + @:analyzer(no_simplification) + public var value(get,never):T; + public var raw(get,never):RawConstPointer; + + @:analyzer(no_simplification) + public function get_value() : T; + + public function lt(inOther:Pointer):Bool; + public function leq(inOther:Pointer):Bool; + public function gt(inOther:Pointer):Bool; + public function geq(inOther:Pointer):Bool; + + public static function fromRaw(ptr:RawConstPointer) : ConstPointer; + + public static function fromPointer(inNativePointer:Dynamic) : ConstPointer; + + public function reinterpret():Pointer; + public function rawCast():RawPointer; + + @:analyzer(no_simplification) + public function at(inIndex:Int):T; + + public function inc():ConstPointer; + public function dec():ConstPointer; + @:analyzer(no_simplification) + public function postIncVal():T; + public function incBy(inT:Int):ConstPointer; + public function add(inT:Int):ConstPointer; + +} + diff --git a/std/cpp/FastIterator.hx b/std/cpp/FastIterator.hx index 8a26936815cd069c0097d373a27528c821f2252a..bf31025e53c4177d1642c9f35b7a8ff03d159170 100644 --- a/std/cpp/FastIterator.hx +++ b/std/cpp/FastIterator.hx @@ -1,29 +1,29 @@ -/* - * Copyright (C)2005-2012 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 cpp; - -extern class FastIterator -{ - public function hasNext():Bool; - public function next():T; -} - +/* + * Copyright (C)2005-2012 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 cpp; + +extern class FastIterator +{ + public function hasNext():Bool; + public function next():T; +} + diff --git a/std/cpp/Float32.hx b/std/cpp/Float32.hx new file mode 100644 index 0000000000000000000000000000000000000000..16fee0e14b5a48ee888d38d87cc0a76b484c43e6 --- /dev/null +++ b/std/cpp/Float32.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Float32 from Float to Float {} diff --git a/std/cpp/Float64.hx b/std/cpp/Float64.hx new file mode 100644 index 0000000000000000000000000000000000000000..122a738244b7564a44dde3c75c7e376334b65a67 --- /dev/null +++ b/std/cpp/Float64.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Float64 from Float to Float {} diff --git a/std/cpp/Function.hx b/std/cpp/Function.hx new file mode 100644 index 0000000000000000000000000000000000000000..0f266a51b344849cdf39c3337476e59b5fbbaf1d --- /dev/null +++ b/std/cpp/Function.hx @@ -0,0 +1,22 @@ +package cpp; + +@:coreType @:structAccess @:include("cpp/Pointer.h") +@:analyzer(no_simplification) +extern class Function +{ + public function new(d:Dynamic); + + // Actually a function pointer, but can be called using haxe notation + public var call(default,null):T; + + public static function getProcAddress(inModule:String, inFunction:String) : Function; + public static function fromStaticFunction(inStaticFunction:T) : Callable; + + public function lt(inOther:Function):Bool; + public function leq(inOther:Function):Bool; + public function gt(inOther:Function):Bool; + public function geq(inOther:Function):Bool; +} + + + diff --git a/std/cpp/Int16.hx b/std/cpp/Int16.hx new file mode 100644 index 0000000000000000000000000000000000000000..3a4e5d5a93af358de8438c8bf409d48051f0da8d --- /dev/null +++ b/std/cpp/Int16.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Int16 from Int to Int {} diff --git a/std/cpp/Int32.hx b/std/cpp/Int32.hx new file mode 100644 index 0000000000000000000000000000000000000000..200d91df2929e8334a61416cd53ccef85a701716 --- /dev/null +++ b/std/cpp/Int32.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Int32 from Int to Int {} diff --git a/std/cpp/Int64.hx b/std/cpp/Int64.hx new file mode 100644 index 0000000000000000000000000000000000000000..0ceed936ad02bcc1f8c0e2397d1ce2ed178e7dc8 --- /dev/null +++ b/std/cpp/Int64.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Int64 from Int to Int {} diff --git a/std/cpp/Int8.hx b/std/cpp/Int8.hx new file mode 100644 index 0000000000000000000000000000000000000000..bd195bc186de9fc3d615776912ee51da966378f9 --- /dev/null +++ b/std/cpp/Int8.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract Int8 from Int to Int {} diff --git a/std/cpp/Lib.hx b/std/cpp/Lib.hx index 610c587a49dc3bdc784f82018dd2687f418d2e27..af6bcd0a479fa0e43ebb884a798857ca859d5af7 100644 --- a/std/cpp/Lib.hx +++ b/std/cpp/Lib.hx @@ -21,6 +21,7 @@ */ package cpp; + class Lib { /** @@ -35,12 +36,28 @@ class Lib { } /** - Load and return a Cpp primitive from a DLL library. + Unloaded all dynamic libraries in reverse order of loading. + Returns the number of libraries unloaded. **/ - @:extern public static inline function getProcAddress( lib : String, prim : String ) : Dynamic { - return untyped __global__.__hxcpp_cast_get_proc_address(lib,prim); + public static function unloadAllLibraries() : Int { + return untyped __global__.__hxcpp_unload_all_libraries(); + } + + @:analyzer(no_simplification) + public static function _loadPrime( lib : String, prim : String, signature : String, quietFail = false ) : Dynamic { + var factory:Callable< ConstCharStar -> Object > = + untyped __global__.__hxcpp_cast_get_proc_address(lib, prim + "__prime", quietFail); + if (factory!=null) + { + var func:Dynamic = factory.call(signature); + if (func==null && !quietFail) + throw '$prim does not have signature $signature'; + return func; + } + return null; } + /** Tries to load, and always returns a valid function, but the function may throw if called. @@ -63,7 +80,33 @@ class Lib { public static function rethrow(inExp:Dynamic) { throw inExp; } - public static function stringReference(inExp:Dynamic) { throw inExp; } + public static function stringReference(inBytes:haxe.io.Bytes) : String + { + var result:String = ""; + untyped __global__.__hxcpp_string_of_bytes(inBytes.b, result, 0, 0, true); + return result; + } + + public static function pushDllSearchPath(inPath:String) : Void + untyped __global__.__hxcpp_push_dll_path(inPath); + + public static function getDllExtension() : String + return untyped __global__.__hxcpp_get_dll_extension(); + + public static function getBinDirectory() : String + return untyped __global__.__hxcpp_get_bin_dir(); + + /** + Returns bytes referencing the content of a string. + Use with extreme caution - changing constant strings will crash. + Changing one string can cause others to change unexpectedly. + Only really safe if you are using it read-only or if it comes from stringReference above + **/ + public inline static function bytesReference( s : String ) : haxe.io.Bytes { + var bytes = new haxe.io.BytesData(); + untyped bytes.__unsafeStringReference(s); + return haxe.io.Bytes.ofData(bytes); + } /** Print the specified value on the default output. @@ -94,4 +137,9 @@ class Lib { untyped __global__.__hxcpp_println(v); } + public static function setFloatFormat(inFormat:String):Void + { + untyped __global__.__hxcpp_set_float_format(inFormat); + } + } diff --git a/std/cpp/NativeArray.hx b/std/cpp/NativeArray.hx new file mode 100644 index 0000000000000000000000000000000000000000..901d9e36125527c03a8459b325cc2d039a163c12 --- /dev/null +++ b/std/cpp/NativeArray.hx @@ -0,0 +1,46 @@ +package cpp; + +extern class NativeArray { + + public 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 { + return untyped inArray; + } + + public static inline function address( inArray:Array,inIndex:Int ) : Pointer { + return Pointer.arrayElem(inArray,inIndex); + } + + public static inline function setData( inArray:Array,inData:Pointer,inElementCount:Int ) : Void { + untyped inArray.setData(inData.raw,inElementCount); + } + public static inline function setUnmanagedData( inArray:Array,inData:Pointer,inElementCount:Int ) : Void { + untyped inArray.setUnmanagedData(inData.raw,inElementCount); + } + + + public static inline function zero( ioDestArray:Array, ?inFirst:Int, ?inElements:Int ) : Void { + untyped ioDestArray.zero(inFirst, inElements); + }; + + public 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 { + return untyped ioDestArray.__unsafe_set(inIndex,inValue); + } + + public static inline function memcmp( inArrayA:Array, inArrayB:Array) : Int { + return untyped inArrayA.memcmp(inArrayB); + } + + public static inline function setSize( ioArray:Array, inSize:Int) : Array { + return untyped ioArray.__SetSizeExact(inSize); + } +} diff --git a/std/cpp/NativeString.hx b/std/cpp/NativeString.hx new file mode 100644 index 0000000000000000000000000000000000000000..c0f9d5c991a81334b2d2bde28d059440ffc30362 --- /dev/null +++ b/std/cpp/NativeString.hx @@ -0,0 +1,15 @@ +package cpp; + +extern class NativeString { + + public static inline function raw( inString:String ) : RawConstPointer { + return untyped inString.__s; + } + public static inline function c_str( inString:String ) : ConstPointer { + return cpp.ConstPointer.fromPointer(untyped inString.__s); + } + public static inline function fromPointer(inPtr:ConstPointer ) : String { + return untyped __global__.String(inPtr.ptr); + } +} + diff --git a/std/cpp/_std/Xml.hx b/std/cpp/NativeXml.hx similarity index 97% rename from std/cpp/_std/Xml.hx rename to std/cpp/NativeXml.hx index 8025eea32a624c70777121ffb8c6dacd8bb3a1f7..9e2a6f220961703f92b96ef4eaf320fa109a032f 100644 --- a/std/cpp/_std/Xml.hx +++ b/std/cpp/NativeXml.hx @@ -19,10 +19,14 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +package cpp; + enum XmlType { } -@:coreApi class Xml { +typedef NativeXml = Xml; + +class Xml { public static var Element(default,null) : XmlType; public static var PCData(default,null) : XmlType; public static var CData(default,null) : XmlType; @@ -43,7 +47,7 @@ enum XmlType { private static var _parse = cpp.Lib.load("std","parse_xml",2); - public static function parse( str : String ) : Xml { + @:analyzer(ignore) public static function parse( str : String ) : Xml { var x = new Xml(); x._children = new Array(); var parser = { @@ -235,7 +239,7 @@ enum XmlType { } - public function elements(): Iterator { + @:analyzer(ignore) public function elements(): Iterator { if( _children == null ) throw "bad nodetype"; var children = _children; @@ -268,7 +272,7 @@ enum XmlType { } } - public function elementsNamed( name : String ) : Iterator { + @:analyzer(ignore) public function elementsNamed( name : String ) : Iterator { if( _children == null ) throw "bad nodetype"; var children = _children; @@ -417,5 +421,4 @@ enum XmlType { __global__.__hxcpp_enum_force(Document , "document", 6); } -} - +} \ No newline at end of file diff --git a/std/cpp/Object.hx b/std/cpp/Object.hx new file mode 100644 index 0000000000000000000000000000000000000000..266970926beb17dbc661330efff52e833559fca1 --- /dev/null +++ b/std/cpp/Object.hx @@ -0,0 +1,16 @@ +package cpp; + +@:native("::hx::Object *") +extern class HxObjectPtr +{ + @:native("hx::DynamicPtr") + static function fromDynamic(x:Dynamic):Object; + @:native("Dynamic") + static function toDynamic(x:Object):Dynamic; +} + +@:extern +abstract Object(HxObjectPtr) { + @:from public inline static function from(x:Dynamic):Object return HxObjectPtr.fromDynamic(x); + @:to public inline static function to(inVal:HxObjectPtr):Dynamic return HxObjectPtr.toDynamic(inVal); +} diff --git a/std/cpp/Pointer.hx b/std/cpp/Pointer.hx new file mode 100644 index 0000000000000000000000000000000000000000..de4aa7f48d3ee658048350ebd870788defc60bb3 --- /dev/null +++ b/std/cpp/Pointer.hx @@ -0,0 +1,39 @@ +package cpp; + +@:coreType +@:analyzer(no_simplification) +extern class Pointer extends ConstPointer implements ArrayAccess +{ + @:analyzer(no_simplification) + public var ref(get,set):T; + + @:analyzer(no_simplification) + public function get_ref() : T; + @:analyzer(no_simplification) + public function set_ref(t:T) : T; + + + public static function fromRaw(ptr:RawPointer) : Pointer; + + public static function fromHandle(inHandle:Dynamic,?inKind:String) : Pointer; + + public static function fromPointer(inNativePointer:Dynamic) : Pointer; + + public static function addressOf(inVariable:T) : Pointer; + + public static function arrayElem(array:Array, inElem:Int):Pointer; + + public function get_raw() : RawPointer; + + override public function inc():Pointer; + override public function dec():Pointer; + override public function incBy(inT:Int):Pointer; + override public function add(inT:Int):Pointer; + + @:analyzer(no_simplification) + public function postIncRef():T; + + public function destroy():Void; + public function destroyArray():Void; +} + diff --git a/std/cpp/Prime.hx b/std/cpp/Prime.hx new file mode 100644 index 0000000000000000000000000000000000000000..5f6019078836d5e949b49382f62cc9f4cf2ed8e1 --- /dev/null +++ b/std/cpp/Prime.hx @@ -0,0 +1,123 @@ +/* + * Copyright (C)2005-2012 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 cpp; + +#if macro +import haxe.macro.Context; +import haxe.macro.Type; +import haxe.macro.Expr; +#end + +@:noPackageRestrict +class Prime { + + #if (!macro && cpp) + + @:analyzer(no_simplification) + public static function _loadPrime( lib : String, prim : String, signature : String, quietFail = false ) : Dynamic { + var factory:Callable< ConstCharStar -> Object > = + untyped __global__.__hxcpp_cast_get_proc_address(lib, prim + "__prime", quietFail); + if (factory!=null) + { + var func:Dynamic = factory.call(signature); + if (func==null && !quietFail) + throw '$prim does not have signature $signature'; + return func; + } + return null; + } + #end + + #if (macro) + static function codeToType(code:String,forCpp:Bool) : String + { + var isCpp = Context.defined("cpp"); + + switch(code) + { + case "b" : return "Bool"; + case "i" : return "Int"; + case "d" : return "Float"; + case "s" : return "String"; + case "f" : return forCpp ? "cpp.Float32" : "Float"; + case "o" : return forCpp ? "cpp.Object" : "Dynamic"; + case "v" : return forCpp ? "cpp.Void" : "Dynamic"; + case "c" : + if (forCpp) + return "cpp.ConstCharStar"; + throw "const char * type only supported in cpp mode"; + default: + throw "Unknown signature type :" + code; + } + } + #end + + public static function nekoInit(inModuleName:String) : Bool + { + #if neko + var init = neko.Lib.load(inModuleName, "neko_init", 5); + + if (init != null) + { + init( function(s) return new String(s), + function(len:Int) { var r = []; if (len > 0) r[len - 1] = null; return r; }, + null, + true, + false); + return true; + + } + #end + return false; + } + + + public static macro function load(inModule:String, inName:String, inSig:String,inAllowFail:Bool = false) + { + var parts = inSig.split(""); + if (parts.length<1) + throw "Invalid function signature " + inSig; + + var cppMode = Context.defined("cpp"); + + var typeString = parts.length==1 ? codeToType("v",cppMode) : codeToType(parts.shift(),cppMode); + for(p in parts) + typeString += "->" + codeToType(p,cppMode); + + if (cppMode) + { + typeString = "cpp.Callable<" + typeString + ">"; + var expr = 'new $typeString(cpp.Prime._loadPrime("$inModule","$inName","$inSig",$inAllowFail))'; + return Context.parse( expr, Context.currentPos() ); + } + else + { + var len = parts.length; + if (len>5) + len = -1; + var lazy = inAllowFail ? "loadLazy" : "load"; + var expr = 'new cpp.Callable<$typeString>(neko.Lib.$lazy("$inModule","$inName",$len))'; + return Context.parse( expr, Context.currentPos() ); + } + } + +} diff --git a/std/cpp/RawConstPointer.hx b/std/cpp/RawConstPointer.hx new file mode 100644 index 0000000000000000000000000000000000000000..80a51ade90885579ac595ae2bd62dabec6676876 --- /dev/null +++ b/std/cpp/RawConstPointer.hx @@ -0,0 +1,6 @@ +package cpp; + +@:unreflective +extern class RawConstPointer +{ +} diff --git a/std/cpp/RawPointer.hx b/std/cpp/RawPointer.hx new file mode 100644 index 0000000000000000000000000000000000000000..17bdc048170ba8619cc452f32f8c963e2afb8111 --- /dev/null +++ b/std/cpp/RawPointer.hx @@ -0,0 +1,6 @@ +package cpp; + +@:unreflective +extern class RawPointer extends RawConstPointer +{ +} diff --git a/std/cpp/UInt16.hx b/std/cpp/UInt16.hx new file mode 100644 index 0000000000000000000000000000000000000000..5cc859b5d35f6c8c484d2529e5f6f5809439cfa6 --- /dev/null +++ b/std/cpp/UInt16.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract UInt16 from Int to Int {} diff --git a/std/cpp/UInt32.hx b/std/cpp/UInt32.hx new file mode 100644 index 0000000000000000000000000000000000000000..825497bcd3f7daf15547426d07b372cbc7cc24ec --- /dev/null +++ b/std/cpp/UInt32.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract UInt32 from Int to Int {} diff --git a/std/cpp/UInt64.hx b/std/cpp/UInt64.hx new file mode 100644 index 0000000000000000000000000000000000000000..ee729164510f278df2724db6ccedb4e922bbe1fc --- /dev/null +++ b/std/cpp/UInt64.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract UInt64 from Int to Int {} diff --git a/std/cpp/UInt8.hx b/std/cpp/UInt8.hx new file mode 100644 index 0000000000000000000000000000000000000000..5514225eac547160d89b665434ccecfd66d8b5f2 --- /dev/null +++ b/std/cpp/UInt8.hx @@ -0,0 +1,3 @@ +package cpp; + +@:coreType @:notNull @:runtimeValue abstract UInt8 from Int to Int {} diff --git a/std/cpp/Void.hx b/std/cpp/Void.hx new file mode 100644 index 0000000000000000000000000000000000000000..4f5bea4854baf15d59d1622610a9884ff660820b --- /dev/null +++ b/std/cpp/Void.hx @@ -0,0 +1,5 @@ +package cpp; + +@:native("void") +extern class Void { } + diff --git a/std/cpp/_std/Date.hx b/std/cpp/_std/Date.hx index e913675599be8c423f387c22537500df4bf35734..f448b1f82d53bd140dc2e3999b8b9da762987202 100644 --- a/std/cpp/_std/Date.hx +++ b/std/cpp/_std/Date.hx @@ -50,6 +50,9 @@ public static function now() : Date { return fromTime( untyped __global__.__hxcpp_date_now()*1000.0); } + private static function new1(t : Dynamic) : Date { + return new Date(2005,1,1,0,0,0); + } public static function fromTime( t : Float ) : Date { var result = new Date(0,0,0,0,0,0); @@ -75,7 +78,6 @@ default: throw "Invalid date format : " + s; } - return null; } } diff --git a/std/cpp/_std/Reflect.hx b/std/cpp/_std/Reflect.hx index e6999f340aeacfb4928ce47e983f308448c56d96..c6d53f6ca39e1ac089a3f1b7c12be790ff83bdf8 100644 --- a/std/cpp/_std/Reflect.hx +++ b/std/cpp/_std/Reflect.hx @@ -26,26 +26,26 @@ } public static function field( o : Dynamic, field : String ) : Dynamic untyped { - return (o==null) ? null : o.__Field(field,false); + return (o==null) ? null : o.__Field(field,untyped __cpp__("hx::paccNever") ); } - public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped { + public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped { if (o!=null) - o.__SetField(field,value,false); + o.__SetField(field,value,untyped __cpp__("hx::paccNever") ); } - public static inline function getProperty( o : Dynamic, field : String ) : Dynamic { - return (o==null) ? null : o.__Field(field,true); + public static function getProperty( o : Dynamic, field : String ) : Dynamic { + return (o==null) ? null : o.__Field(field,untyped __cpp__("hx::paccAlways") ); } - public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void { + public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void { if (o!=null) - o.__SetField(field,value,true); + o.__SetField(field,value,untyped __cpp__("hx::paccAlways") ); } - public static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic untyped { + public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic untyped { if (func!=null && func.__GetType()==__global__.vtString) - func = o.__Field(func,true); + func = o.__Field(func,untyped __cpp__("hx::paccDynamic")); untyped func.__SetThis(o); return untyped func.__Run(args); } @@ -62,7 +62,7 @@ } public static function compare( a : T, b : T ) : Int { - return ( a == b ) ? 0 : (((cast a) > (cast b)) ? 1 : -1); + return ( a == b ) ? 0 : (((a:Dynamic) > (b:Dynamic)) ? 1 : -1); } public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool { @@ -79,7 +79,7 @@ return t == __global__.vtObject || t==__global__.vtClass || t==__global__.vtString || t==__global__.vtArray; } - + public static function isEnumValue( v : Dynamic ) : Bool untyped { return v!=null && v.__GetType() == __global__.vtEnum; } @@ -93,7 +93,7 @@ if (o==null) return null; if(untyped o.__GetType()==__global__.vtString ) return o; if(untyped o.__GetType()==__global__.vtArray ) - return untyped o.__Field("copy",true)(); + return untyped o.__Field("copy", untyped __cpp__("hx::paccDynamic"))(); var o2 : Dynamic = {}; for( f in Reflect.fields(o) ) Reflect.setField(o2,f,Reflect.field(o,f)); diff --git a/std/cpp/_std/Std.hx b/std/cpp/_std/Std.hx index 917bb686b2b47aea2b57fcf6cbca23122f8d8356..1ea51dc3309a8769f54fc1eaa3a561b96b8305f6 100644 --- a/std/cpp/_std/Std.hx +++ b/std/cpp/_std/Std.hx @@ -20,27 +20,31 @@ * DEALINGS IN THE SOFTWARE. */ @:coreApi class Std { - public static function is( v : Dynamic, t : Dynamic ) : Bool { + @:keep public static function is( v : Dynamic, t : Dynamic ) : Bool { return untyped __global__.__instanceof(v,t); } - public static function string( s : Dynamic ) : String { + @:keep public static function instance( value : T, c : Class ) : S { + return Std.is(value, c) ? cast value : null; + } + + @:keep public static function string( s : Dynamic ) : String { return untyped s==null ? "null" : s.toString(); } - public static function int( x : Float ) : Int { + @:keep public static function int( x : Float ) : Int { return untyped __global__.__int__(x); } - public static function parseInt( x : String ) : Null { + @:keep public static function parseInt( x : String ) : Null { return untyped __global__.__hxcpp_parse_int(x); } - public static function parseFloat( x : String ) : Float { + @:keep public static function parseFloat( x : String ) : Float { return untyped __global__.__hxcpp_parse_float(x); } - public static function random( x : Int ) : Int { + @:keep public static function random( x : Int ) : Int { if (x <= 0) return 0; return untyped __global__.__hxcpp_irand(x); } diff --git a/std/cpp/_std/StringBuf.hx b/std/cpp/_std/StringBuf.hx index 4dfc452f98d59de3fb757408671fedbee26ca796..5f4dd1a04557fc82d9e2cffac55300f32adb14c8 100644 --- a/std/cpp/_std/StringBuf.hx +++ b/std/cpp/_std/StringBuf.hx @@ -1,47 +1,56 @@ -/* - * Copyright (C)2005-2012 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 : Array; - - public function new() : Void { - b = new Array(); - } - - public function add( x : Dynamic ) : Void { - b.push(x); - } - - public inline function addSub( s : String, pos : Int, ?len : Int ) : Void { - b.push(s.substr(pos,len)); - } - - public inline function addChar( c : Int ) : Void untyped { - b.push(String.fromCharCode(c)); - } - - public inline function toString() : String { - return b.join(""); - } - -} +/* + * Copyright (C)2005-2012 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 : Array; + + public var length(get,never) : Int; + + public function new() : Void { + b = new Array(); + } + + function get_length() : Int { + var len = 0; + for(s in b) + len += s==null ? 4 : s.length; + return len; + } + + public function add( x : T ) : Void { + b.push(Std.string(x)); + } + + public inline function addSub( s : String, pos : Int, ?len : Int ) : Void { + b.push(s.substr(pos,len)); + } + + public inline function addChar( c : Int ) : Void untyped { + b.push(String.fromCharCode(c)); + } + + public inline function toString() : String { + return b.join(""); + } + +} diff --git a/std/cpp/_std/Sys.hx b/std/cpp/_std/Sys.hx index f47fdb589b14a7d1f4fdab4bc1d2fe491eb5b135..e5bd3f98bd03917db9ae7ade98947a9b7294f7c3 100644 --- a/std/cpp/_std/Sys.hx +++ b/std/cpp/_std/Sys.hx @@ -1,153 +1,153 @@ -/* - * Copyright (C)2005-2012 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 Sys { - - public static function print( v : Dynamic ) : Void { - untyped __global__.__hxcpp_print(v); - } - - public static function println( v : Dynamic ) : Void { - print(v); - print("\n"); - } - - public static function stdin() : haxe.io.Input { - return untyped new sys.io.FileInput(file_stdin()); - } - - public static function stdout() : haxe.io.Output { - return untyped new sys.io.FileOutput(file_stdout()); - } - - public static function stderr() : haxe.io.Output { - return untyped new sys.io.FileOutput(file_stderr()); - } - - public static function getChar( echo : Bool ) : Int { - return getch(echo); - } - - public static function args() : Array untyped { - return __global__.__get_args(); - } - - public static function getEnv( s : String ):String { - var v = get_env(s); - if( v == null ) - return null; - return v; - } - - public static function putEnv( s : String, v : String ) : Void { - put_env(s,v); - } - - public static function sleep( seconds : Float ) : Void { - _sleep(seconds); - } - - public static function setTimeLocale( loc : String ) : Bool { - return set_time_locale(loc); - } - - public static function getCwd() : String { - return new String(get_cwd()); - } - - public static function setCwd( s : String ) : Void { - set_cwd(s); - } - - public static function systemName() : String { - return sys_string(); - } - - static function escapeArgument( arg : String ) : String { - var ok = true; - for( i in 0...arg.length ) - switch( arg.charCodeAt(i) ) { - case 32, 34: // [space] " - ok = false; - case 0, 13, 10: // [eof] [cr] [lf] - arg = arg.substr(0,i); - } - if( ok ) - return arg; - return '"'+arg.split('"').join('\\"')+'"'; - } - - public static function command( cmd : String, ?args : Array ) : Int { - if( args != null ) { - cmd = escapeArgument(cmd); - for( a in args ) - cmd += " "+escapeArgument(a); - } - return sys_command(cmd); - } - - public static function exit( code : Int ) : Void { - sys_exit(code); - } - - public static function time() : Float { - return sys_time(); - } - - public static function cpuTime() : Float { - return sys_cpu_time(); - } - - public static function executablePath() : String { - return new String(sys_exe_path()); - } - - public static function environment() : haxe.ds.StringMap { - var vars:Array = sys_env(); - var result = new haxe.ds.StringMap(); - var i = 0; - while(i untyped { + return __global__.__get_args(); + } + + public static function getEnv( s : String ):String { + var v = get_env(s); + if( v == null ) + return null; + return v; + } + + public static function putEnv( s : String, v : String ) : Void { + put_env(s,v); + } + + public static function sleep( seconds : Float ) : Void { + _sleep(seconds); + } + + public static function setTimeLocale( loc : String ) : Bool { + return set_time_locale(loc); + } + + public static function getCwd() : String { + return new String(get_cwd()); + } + + public static function setCwd( s : String ) : Void { + set_cwd(s); + } + + public static function systemName() : String { + return sys_string(); + } + + static function escapeArgument( arg : String ) : String { + var ok = true; + for( i in 0...arg.length ) + switch( arg.charCodeAt(i) ) { + case ' '.code, '\t'.code, '"'.code, '&'.code, '|'.code, '<'.code, '>'.code, '#'.code , ';'.code, '*'.code, '?'.code, '('.code, ')'.code, '{'.code, '}'.code, '$'.code: + ok = false; + case 0, 13, 10: // [eof] [cr] [lf] + arg = arg.substr(0,i); + } + if( ok ) + return arg; + return '"'+arg.split('\\').join("\\\\").split('"').join('\\"')+'"'; + } + + public static function command( cmd : String, ?args : Array ) : Int { + if( args != null ) { + cmd = escapeArgument(cmd); + for( a in args ) + cmd += " "+escapeArgument(a); + } + if (systemName() == "Windows") cmd = '"$cmd"'; + return sys_command(cmd); + } + + public static function exit( code : Int ) : Void { + untyped __global__.__hxcpp_exit(code); + } + + public static function time() : Float { + return sys_time(); + } + + public static function cpuTime() : Float { + return sys_cpu_time(); + } + + public static function executablePath() : String { + return new String(sys_exe_path()); + } + + public static function environment() : Map { + var vars:Array = sys_env(); + var result = new haxe.ds.StringMap(); + var i = 0; + while(i> 31 ) + throw "Overflow"; + + return x.low; + } + + /** + Returns whether the value `val` is of type `haxe.Int64` + **/ + public static #if !cppia inline #end function is( val : Dynamic ) : Bool + return untyped __cpp__("(cpp::Int64Struct::is({0}))",val); + + /** + Returns the high 32-bit word of `x`. + **/ + @:deprecated("Use high instead") + public static #if !cppia inline #end function getHigh( x : Int64 ) : Int32 + return x.high; + + /** + Returns the low 32-bit word of `x`. + **/ + @:deprecated("Use low instead") + public static #if !cppia inline #end function getLow( x : Int64 ) : Int32 + return x.low; + + /** + Returns `true` if `x` is less than zero. + **/ + public static #if !cppia inline #end function isNeg( x : Int64) : Bool + return untyped __cpp__("(({0}.get()) < 0)", x); + + /** + Returns `true` if `x` is exactly zero. + **/ + public static #if !cppia inline #end function isZero( x : Int64 ) : Bool + return untyped __cpp__("(({0}.get()) == 0)", x); + + /** + Compares `a` and `b` in signed mode. + Returns a negative value if `a < b`, positive if `a > b`, + or 0 if `a == b`. + **/ + public static #if !cppia inline #end function compare( a : Int64, b : Int64 ) : Int { + return untyped __cpp__("( ({0}.get()) < ({1}.get()) ? -1 : ({0})==({1}) ? 0 : 1)", a, b, a, b); + } + + /** + Compares `a` and `b` in unsigned mode. + Returns a negative value if `a < b`, positive if `a > b`, + or 0 if `a == b`. + **/ + public static #if !cppia inline #end function ucompare( a : Int64, b : Int64 ) : Int { + return untyped __cpp__("( (cpp::UInt64)({0}.get()) < (cpp::UInt64)({1}.get()) ? -1 : ({0}.get())==({1}.get()) ? 0 : 1)", a, b, a, b); + } + + /** + Returns a signed decimal `String` representation of `x`. + **/ + public static #if !cppia inline #end function toStr(x:Int64) : String + return x.toString(); + + private function toString() : String + { + return untyped __cpp__("String( ({0}).get() )", this); + } + + /** + Performs signed integer divison of `dividend` by `divisor`. + Returns `{ quotient : Int64, modulus : Int64 }`. + **/ + public static function divMod( dividend : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } + { + var q = dividend/divisor; + + if (isZero(divisor)) + throw "divide by zero"; + + var m = dividend - q*divisor; + + return { quotient : q, modulus : m }; + } + + /** + Returns the negative of `x`. + **/ + @:op(-A) public static #if !cppia inline #end function neg( x : Int64 ) : Int64 { + return untyped __cpp__("(-({0}.get()))",x); + } + + @:op(++A) private inline function preIncrement() : Int64 { + #if cppia + this = this + make(0,1); + return this; + #else + return untyped __cpp__("(++({0}.get()))",this); + #end + } + + @:op(A++) private inline function postIncrement() : Int64 { + #if cppia + var result = this; + this = this + make(0,1); + return result; + #else + return untyped __cpp__("(({0}.get())++)",this); + #end + } + + @:op(--A) private inline function preDecrement() : Int64 { + #if cppia + untyped this = this - make(0,1); + return this; + #else + return untyped __cpp__("(--({0}.get()))",this); + #end + } + + @:op(A--) private inline function postDecrement() : Int64 { + #if cppia + var result = this; + this = this - make(0,1); + return result; + #else + return untyped __cpp__("(({0}.get())--)",this); + #end + } + + /** + Returns the sum of `a` and `b`. + **/ + @:op(A + B) public static #if !cppia inline #end function add( a : Int64, b : Int64 ) : Int64 { + return untyped __cpp__("(({0}.get()) + ({1}.get()))", a, b); + } + + @:op(A + B) @:commutative private static #if !cppia inline #end function addInt( a : Int64, b : Int ) : Int64 + return add( a, b ); + + /** + Returns `a` minus `b`. + **/ + @:op(A - B) public static #if !cppia inline #end function sub( a : Int64, b : Int64 ) : Int64 { + return untyped __cpp__("(({0}.get()) - ({1}.get()))", a, b); + } + + @:op(A - B) private static #if !cppia inline #end function subInt( a : Int64, b : Int ) : Int64 + return sub( a, b ); + + @:op(A - B) private static #if !cppia inline #end function intSub( a : Int, b : Int64 ) : Int64 + return sub( a, b ); + + /** + Returns the product of `a` and `b`. + **/ + @:op(A * B) public static #if !cppia inline #end function mul( a : Int64, b : Int64 ) : Int64 { + return untyped __cpp__("(({0}.get()) * ({1}.get()))", a, b); + } + + @:op(A * B) @:commutative private static #if !cppia inline #end function mulInt( a : Int64, b : Int ) : Int64 + return mul( a, b ); + + /** + Returns the quotient of `a` divided by `b`. + **/ + @:op(A / B) public static function div( a : Int64, b : Int64 ) : Int64 { + if (untyped __cpp__("(({0}.get()) == 0)",b) ) + throw "divide by zero"; + return untyped __cpp__("(({0}.get()) / ({1}.get()))", a, b); + } + + + @:op(A / B) private static #if !cppia inline #end function divInt( a : Int64, b : Int ) : Int64 + return div( a, b ); + + @:op(A / B) private static #if !cppia inline #end function intDiv( a : Int, b : Int64 ) : Int64 + return toInt(div( a, b )); + + /** + Returns the modulus of `a` divided by `b`. + **/ + @:op(A % B) public static #if !cppia inline #end function mod( a : Int64, b : Int64 ) : Int64 + { + if (untyped __cpp__("(({0}.get()) == 0)",b) ) + throw "divide by zero"; + return untyped __cpp__("(({0}.get()) % ({1}.get()))", a, b); + } + + @:op(A % B) private static #if !cppia inline #end function modInt( a : Int64, b : Int ) : Int64 + return toInt(mod( a, b )); + + @:op(A % B) private static #if !cppia inline #end function intMod( a : Int, b : Int64 ) : Int64 + return toInt(mod( a, b )); + + /** + Returns `true` if `a` is equal to `b`. + **/ + @:op(A == B) public static #if !cppia inline #end function eq( a : Int64, b : Int64 ) : Bool + return untyped __cpp__("(({0}.get()) == ({1}.get()))", a, b); + + @:op(A == B) @:commutative private static #if !cppia inline #end function eqInt( a : Int64, b : Int ) : Bool + return eq( a, b ); + + /** + Returns `true` if `a` is not equal to `b`. + **/ + @:op(A != B) public static #if !cppia inline #end function neq( a : Int64, b : Int64 ) : Bool + return untyped __cpp__("(({0}.get()) != ({1}.get()))", a, b); + + @:op(A != B) @:commutative private static #if !cppia inline #end function neqInt( a : Int64, b : Int ) : Bool + return neq(a, b); + + @:op(A < B) private static #if !cppia inline #end function lt( a : Int64, b : Int64 ) : Bool + return compare(a, b) < 0; + + @:op(A < B) private static #if !cppia inline #end function ltInt( a : Int64, b : Int ) : Bool + return lt(a, b); + + @:op(A < B) private static #if !cppia inline #end function intLt( a : Int, b : Int64 ) : Bool + return lt(a, b); + + @:op(A <= B) private static #if !cppia inline #end function lte( a : Int64, b : Int64 ) : Bool + return compare(a, b) <= 0; + + @:op(A <= B) private static #if !cppia inline #end function lteInt( a : Int64, b : Int ) : Bool + return lte(a, b); + + @:op(A <= B) private static #if !cppia inline #end function intLte( a : Int, b : Int64 ) : Bool + return lte(a, b); + + @:op(A > B) private static #if !cppia inline #end function gt( a : Int64, b : Int64 ) : Bool + return compare(a, b) > 0; + + @:op(A > B) private static #if !cppia inline #end function gtInt( a : Int64, b : Int ) : Bool + return gt(a, b); + + @:op(A > B) private static #if !cppia inline #end function intGt( a : Int, b : Int64 ) : Bool + return gt( a, b ); + + @:op(A >= B) private static #if !cppia inline #end function gte( a : Int64, b : Int64 ) : Bool + return compare(a, b) >= 0; + + @:op(A >= B) private static #if !cppia inline #end function gteInt( a : Int64, b : Int ) : Bool + return gte(a, b); + + @:op(A >= B) private static #if !cppia inline #end function intGte( a : Int, b : Int64 ) : Bool + return gte(a, b); + + /** + Returns the bitwise NOT of `a`. + **/ + @:op(~A) private static #if !cppia inline #end function complement( a : Int64 ) : Int64 + return untyped __cpp__("(~({0}.get()))", a); + + /** + Returns the bitwise AND of `a` and `b`. + **/ + @:op(A & B) public static #if !cppia inline #end function and( a : Int64, b : Int64 ) : Int64 + return untyped __cpp__("(({0}) & ({1}))", a, b); + + /** + Returns the bitwise OR of `a` and `b`. + **/ + @:op(A | B) public static #if !cppia inline #end function or( a : Int64, b : Int64 ) : Int64 + return untyped __cpp__("(({0}) | ({1}))", a, b); + + /** + Returns the bitwise XOR of `a` and `b`. + **/ + @:op(A ^ B) public static #if !cppia inline #end function xor( a : Int64, b : Int64 ) : Int64 + return untyped __cpp__("(({0}) ^ ({1}))", a, b); + + /** + Returns `a` left-shifted by `b` bits. + **/ + @:op(A << B) public static #if !cppia inline #end function shl( a : Int64, b : Int ) : Int64 + return untyped __cpp__("(({0}) << ({1}))", a, (b&63)); + + /** + Returns `a` right-shifted by `b` bits in signed mode. + `a` is sign-extended. + **/ + @:op(A >> B) public static #if !cppia inline #end function shr( a : Int64, b : Int) : Int64 + return untyped __cpp__("(({0}) >> ({1}))", a, (b&63)); + + /** + Returns `a` right-shifted by `b` bits in unsigned mode. + `a` is padded with zeroes. + **/ + @:op(A >>> B) public static #if !cppia inline #end function ushr( a : Int64, b : Int ) : Int64 + return untyped __cpp__("(((cpp::UInt64)({0})) >> ({1}))", a, (b&63)); + + public var high(get, never) : Int32; + private #if !cppia inline #end function get_high() : Int32 + return untyped __cpp__("(int)(((cpp::Int64)({0}))>>32)",this); + + public var low(get, never) : Int32; + private #if !cppia inline #end function get_low() : Int32 + return untyped __cpp__("(int)(({0})&0xffffffff)", this); + +} + diff --git a/std/cpp/_std/haxe/Resource.hx b/std/cpp/_std/haxe/Resource.hx index ab0c61b60a99b0b87bb0036abfc95b5e0ba57794..96a040e48ec181b47d12cf452e542ca569b96b94 100644 --- a/std/cpp/_std/haxe/Resource.hx +++ b/std/cpp/_std/haxe/Resource.hx @@ -1,39 +1,39 @@ -/* - * Copyright (C)2005-2012 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 { - - public static function listNames() : Array { - return untyped __global__.__hxcpp_resource_names(); - } - public static function getString(name:String) : String { - return untyped __global__.__hxcpp_resource_string(name); - } - public static function getBytes(name:String) : haxe.io.Bytes { - var array:haxe.io.BytesData = untyped __global__.__hxcpp_resource_bytes(name); - if (array==null) return null; - return haxe.io.Bytes.ofData(array); - } - -} +/* + * Copyright (C)2005-2012 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 { + + public static function listNames() : Array { + return untyped __global__.__hxcpp_resource_names(); + } + public static function getString(name:String) : String { + return untyped __global__.__hxcpp_resource_string(name); + } + public static function getBytes(name:String) : haxe.io.Bytes { + var array:haxe.io.BytesData = untyped __global__.__hxcpp_resource_bytes(name); + if (array==null) return null; + return haxe.io.Bytes.ofData(array); + } + +} diff --git a/std/cpp/_std/haxe/Utf8.hx b/std/cpp/_std/haxe/Utf8.hx index 3b24d2bdc18b6138ced036e5971d0a25c1b5b533..a5a13dd9ff2cb26373c4e7b0ceec26991f46c799 100644 --- a/std/cpp/_std/haxe/Utf8.hx +++ b/std/cpp/_std/haxe/Utf8.hx @@ -90,7 +90,9 @@ class Utf8 public static function sub( s : String, pos : Int, len : Int ) : String { var array:Array = untyped __global__.__hxcpp_utf8_string_to_char_array(s); - var sub = array.slice(pos,len); + var last = len < 0 ? array.length : pos+len; + if (last>array.length) last = array.length; + var sub = array.slice(pos,last); return untyped __global__.__hxcpp_char_array_to_utf8_string(sub); } diff --git a/std/cpp/_std/haxe/ds/IntMap.hx b/std/cpp/_std/haxe/ds/IntMap.hx index 80ee1720ed4999079eacee39e28064b397e3cd4d..b2b2a9893a711052fd862d249b4d82a3b2d4c7c2 100644 --- a/std/cpp/_std/haxe/ds/IntMap.hx +++ b/std/cpp/_std/haxe/ds/IntMap.hx @@ -21,13 +21,35 @@ */ package haxe.ds; -@:coreApi class IntMap implements Map.IMap { +@:headerClassCode(" + inline void set(int key, ::null value) { __int_hash_set(h,key,value); } + inline void set(int key, bool value) { __int_hash_set(h,key,value); } + inline void set(int key, char value) { __int_hash_set_int(h,key,value); } + inline void set(int key, unsigned char value) { __int_hash_set_int(h,key,value); } + inline void set(int key, signed char value) { __int_hash_set_int(h,key,value); } + inline void set(int key, short value) { __int_hash_set_int(h,key,value); } + inline void set(int key, unsigned short value) { __int_hash_set_int(h,key,value); } + inline void set(int key, int value) { __int_hash_set_int(h,key,value); } + inline void set(int key, unsigned int value) { __int_hash_set_int(h,key,value); } + inline void set(int key, float value) { __int_hash_set_float(h,key,value); } + inline void set(int key, double value) { __int_hash_set_float(h,key,value); } + inline void set(int key, ::String value) { __int_hash_set_string(h,key,value); } - private var h : Dynamic; + template + inline void set(int key, const ::cpp::Struct &value) {__int_hash_set(h,key,value); } + template + inline void set(int key, const ::cpp::Function &value) {__int_hash_set(h,key,value); } + template + inline void set(int key, const ::cpp::Pointer &value) {__int_hash_set(h,key,(Dynamic)value ); } - public function new() : Void { - h = untyped __global__.__int_hash_create(); - } + template + inline Void set(Dynamic &key, const VALUE &value) { set( (int)key, value ); return null(); } +") +@:coreApi class IntMap implements haxe.Constraints.IMap { + + @:ifFeature("haxe.ds.IntMap.*") private var h : Dynamic; + + public function new() : Void { } public function set( key : Int, value : T ) : Void { untyped __global__.__int_hash_set(h,key,value); @@ -56,18 +78,6 @@ package haxe.ds; } 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(); + return untyped __global__.__int_hash_to_string(h); } - } diff --git a/std/cpp/_std/haxe/ds/ObjectMap.hx b/std/cpp/_std/haxe/ds/ObjectMap.hx index e341cf6fd109ca96ec91e95f87f5b8902eef8d10..6a454ce6136c1ff948251d1044e397bbc207922c 100644 --- a/std/cpp/_std/haxe/ds/ObjectMap.hx +++ b/std/cpp/_std/haxe/ds/ObjectMap.hx @@ -1,76 +1,82 @@ -/* - * Copyright (C)2005-2013 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 ObjectMap implements Map.IMap { - private var __Internal : IntMap; - private var __KeyRefs : IntMap; - - public function new() : Void { - __Internal = new IntMap(); - __KeyRefs = new IntMap(); - } - - public function set( key : K, value : V ) : Void { - var id = untyped __global__.__hxcpp_obj_id(key); - __Internal.set( id, value ); - __KeyRefs.set( id, key ); - } - - public function get( key : K ) : Null { - return __Internal.get( untyped __global__.__hxcpp_obj_id(key) ); - } - - public inline function exists( key : K ) : Bool { - return __Internal.exists( untyped __global__.__hxcpp_obj_id(key) ); - } - - public function remove( key : K ) : Bool { - var id = untyped __global__.__hxcpp_obj_id(key); - return __Internal.remove(id); - return __KeyRefs.remove(id); - } - - public function keys() : Iterator { - return __KeyRefs.iterator(); - } - - public function iterator() : Iterator { - return __Internal.iterator(); - } - - public function toString() : String { - var s = new StringBuf(); - s.add("{"); - var it = __Internal.keys(); - for( i in it ) { - s.add(Std.string(__KeyRefs.get(i))); - s.add(" => "); - s.add(Std.string(__Internal.get(i))); - if( it.hasNext() ) - s.add(", "); - } - s.add("}"); - return s.toString(); - } -} +/* + * Copyright (C)2005-2013 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; + +@:headerClassCode(" + inline void set(Dynamic key, ::null value) { __object_hash_set(h,key,value); } + inline void set(Dynamic key, bool value) { __object_hash_set(h,key,value); } + inline void set(Dynamic key, char value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, unsigned char value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, signed char value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, short value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, unsigned short value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, int value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, unsigned int value) { __object_hash_set_int(h,key,value); } + inline void set(Dynamic key, float value) { __object_hash_set_float(h,key,value); } + inline void set(Dynamic key, double value) { __object_hash_set_float(h,key,value); } + inline void set(Dynamic key, ::String value) { __object_hash_set_string(h,key,value); } + + + template + inline void set(Dynamic key, const ::cpp::Struct &value) {__object_hash_set(h,key,value); } + template + inline void set(Dynamic key, const ::cpp::Function &value) {__object_hash_set(h,key,(Dynamic)value ); } + template + inline void set(Dynamic key, const ::cpp::Pointer &value) {__object_hash_set(h,key,(Dynamic)value ); } + +") +@:coreApi +class ObjectMap implements haxe.Constraints.IMap { + private var h : Dynamic; + + public function new() : Void { } + + public function set( key : K, value : V ) : Void { + untyped __global__.__object_hash_set(h,key,value); + } + + public function get( key : K ) : Null { + return untyped __global__.__object_hash_get(h,key); + } + + public function exists( key : K ) : Bool { + return untyped __global__.__object_hash_exists(h,key); + } + + public function remove( key : K ) : Bool { + return untyped __global__.__object_hash_remove(h,key); + } + + public function keys() : Iterator { + var a:Array = untyped __global__.__object_hash_keys(h); + return a.iterator(); + } + + public function iterator() : Iterator { + var a:Array = untyped __global__.__object_hash_values(h); + return a.iterator(); + } + + public function toString() : String { + return untyped __global__.__object_hash_to_string(h); + } +} diff --git a/std/cpp/_std/haxe/ds/StringMap.hx b/std/cpp/_std/haxe/ds/StringMap.hx index f36ea05e8cbec0bd0c5c4f14f8f680588eea3152..37d01b419476382fa083510933a9c7c616358eb2 100644 --- a/std/cpp/_std/haxe/ds/StringMap.hx +++ b/std/cpp/_std/haxe/ds/StringMap.hx @@ -21,68 +21,62 @@ */ package haxe.ds; -@:coreApi class StringMap implements Map.IMap { - private var __Internal : Dynamic; +@:headerClassCode(" + inline void set(String key, ::null value) { __string_hash_set(h,key,value); } + inline void set(String key, bool value) { __string_hash_set(h,key,value); } + inline void set(String key, char value) { __string_hash_set_int(h,key,value); } + inline void set(String key, unsigned char value) { __string_hash_set_int(h,key,value); } + inline void set(String key, signed char value) { __string_hash_set_int(h,key,value); } + inline void set(String key, short value) { __string_hash_set_int(h,key,value); } + inline void set(String key, unsigned short value) { __string_hash_set_int(h,key,value); } + inline void set(String key, int value) { __string_hash_set_int(h,key,value); } + inline void set(String key, unsigned int value) { __string_hash_set_int(h,key,value); } + inline void set(String key, float value) { __string_hash_set_float(h,key,value); } + inline void set(String key, double value) { __string_hash_set_float(h,key,value); } + inline void set(String key, ::String value) { __string_hash_set_string(h,key,value); } - public function new() : Void { - __Internal = {}; - } + template + inline void set(String key, const ::cpp::Struct &value) {__string_hash_set(h,key,value); } + template + inline void set(String key, const ::cpp::Function &value) {__string_hash_set(h,key,(Dynamic)value ); } + template + inline void set(String key, const ::cpp::Pointer &value) {__string_hash_set(h,key,(Dynamic)value ); } + + template + inline Void set(Dynamic &key, const VALUE &value) { set( (String)key, value ); return null(); } +") +@:coreApi class StringMap implements haxe.Constraints.IMap { + private var h : Dynamic; + + public function new() : Void { } public function set( key : String, value : T ) : Void { - untyped __Internal.__SetField(key,value,true); + untyped __global__.__string_hash_set(h,key,value); } public function get( key : String ) : Null { - return untyped __Internal.__Field(key,true); + return untyped __global__.__string_hash_get(h,key); } public function exists( key : String ) : Bool { - return untyped __Internal.__HasField(key); + return untyped __global__.__string_hash_exists(h,key); } public function remove( key : String ) : Bool { - return untyped __global__.__hxcpp_anon_remove(__Internal,key); + return untyped __global__.__string_hash_remove(h,key); } - /** - Returns an iterator of all keys in the hashtable. - **/ public function keys() : Iterator { - var a:Array = []; - untyped __Internal.__GetFields(a); + var a:Array = untyped __global__.__string_hash_keys(h); return a.iterator(); } - /** - Returns an iterator of all values in the hashtable. - **/ public function iterator() : Iterator { - var a:Array = []; - untyped __Internal.__GetFields(a); - var it = a.iterator(); - var me = this; - return untyped { - hasNext : function() { return it.hasNext(); }, - next : function() { return me.__Internal.__Field(it.next(),true); } - }; + var a:Array = untyped __global__.__string_hash_values(h); + return a.iterator(); } - /** - Returns an displayable representation of the hashtable content. - **/ - 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(); + return untyped __global__.__string_hash_to_string(h); } } diff --git a/std/cpp/_std/haxe/ds/WeakMap.hx b/std/cpp/_std/haxe/ds/WeakMap.hx new file mode 100644 index 0000000000000000000000000000000000000000..ac0df37e8fb137387669168bf1ac0c607a08c332 --- /dev/null +++ b/std/cpp/_std/haxe/ds/WeakMap.hx @@ -0,0 +1,80 @@ +/* + * Copyright (C)2005-2013 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; + +@:headerClassCode(" + inline void set(Dynamic key, ::null value) { __object_hash_set(h,key,value,true); } + inline void set(Dynamic key, bool value) { __object_hash_set(h,key,value,true); } + inline void set(Dynamic key, char value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, unsigned char value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, signed char value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, short value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, unsigned short value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, int value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, unsigned int value) { __object_hash_set_int(h,key,value,true); } + inline void set(Dynamic key, float value) { __object_hash_set_float(h,key,value,true); } + inline void set(Dynamic key, double value) { __object_hash_set_float(h,key,value,true); } + inline void set(Dynamic key, ::String value) { __object_hash_set_string(h,key,value,true); } + + template + inline void set(Dynamic key, const ::cpp::Struct &value) {__object_hash_set(h,key,value,true); } + template + inline void set(Dynamic key, const ::cpp::Pointer &value) {__object_hash_set(h,key,(Dynamic)value,true ); } + template + inline void set(Dynamic key, const ::cpp::Function &value) {__object_hash_set(h,key,(Dynamic)value,true ); } +") +@:coreApi +class WeakMap implements haxe.Constraints.IMap { + private var h : Dynamic; + + public function new() : Void { } + + public function set( key : K, value : V ) : Void { + untyped __global__.__object_hash_set(h,key,value,true); + } + + public function get( key : K ) : Null { + return untyped __global__.__object_hash_get(h,key); + } + + public function exists( key : K ) : Bool { + return untyped __global__.__object_hash_exists(h,key); + } + + public function remove( key : K ) : Bool { + return untyped __global__.__object_hash_remove(h,key); + } + + public function keys() : Iterator { + var a:Array = untyped __global__.__object_hash_keys(h); + return a.iterator(); + } + + public function iterator() : Iterator { + var a:Array = untyped __global__.__object_hash_values(h); + return a.iterator(); + } + + public function toString() : String { + return untyped __global__.__object_hash_to_string(h); + } +} diff --git a/std/cpp/_std/haxe/zip/Compress.hx b/std/cpp/_std/haxe/zip/Compress.hx new file mode 100644 index 0000000000000000000000000000000000000000..eba277957ad9e1087568a501a51d0c1f263f715b --- /dev/null +++ b/std/cpp/_std/haxe/zip/Compress.hx @@ -0,0 +1,62 @@ +/* + * Copyright (C)2005-2012 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.zip; + +@:coreApi +class Compress { + + var s : Dynamic; + + public function new( level : Int ) : Void { + s = _deflate_init(level); + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return _deflate_buffer(s,src.getData(),srcPos,dst.getData(),dstPos); + } + + public function setFlushMode( f : FlushMode ) : Void { + _set_flush_mode(s,Std.string(f)); + } + + public function close() : Void { + _deflate_end(s); + } + + public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes { + var c = new Compress(level); + c.setFlushMode(FlushMode.FINISH); + var out = haxe.io.Bytes.alloc(_deflate_bound(c.s,s.length)); + var r = c.execute(s,0,out,0); + c.close(); + if( !r.done || r.read != s.length ) + throw "Compression failed"; + return out.sub(0,r.write); + } + + static var _deflate_init = cpp.Lib.load("zlib","deflate_init",1); + static var _deflate_bound = cpp.Lib.load("zlib","deflate_bound",2); + static var _deflate_buffer = cpp.Lib.load("zlib","deflate_buffer",5); + static var _deflate_end = cpp.Lib.load("zlib","deflate_end",1); + static var _set_flush_mode = cpp.Lib.load("zlib","set_flush_mode",2); + +} diff --git a/std/cpp/_std/haxe/zip/Uncompress.hx b/std/cpp/_std/haxe/zip/Uncompress.hx new file mode 100644 index 0000000000000000000000000000000000000000..92e236441b5f169395631754d94189afe4c8c339 --- /dev/null +++ b/std/cpp/_std/haxe/zip/Uncompress.hx @@ -0,0 +1,67 @@ +/* + * Copyright (C)2005-2012 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.zip; + +@:coreApi +class Uncompress { + var s : Dynamic; + + public function new( ?windowBits : Int ) : Void { + s = _inflate_init(windowBits); + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return _inflate_buffer(s,src.getData(),srcPos,dst.getData(),dstPos); + } + + public function setFlushMode( f : FlushMode ) : Void { + _set_flush_mode(s,untyped f.__Tag()); + } + + public function close() : Void { + _inflate_end(s); + } + + public static function run( src : haxe.io.Bytes, ?bufsize : Int ) : haxe.io.Bytes { + var u = new Uncompress(null); + if( bufsize == null ) bufsize = 1 << 16; // 64K + var tmp = haxe.io.Bytes.alloc(bufsize); + var b = new haxe.io.BytesBuffer(); + var pos = 0; + u.setFlushMode(FlushMode.SYNC); + while( true ) { + var r = u.execute(src,pos,tmp,0); + b.addBytes(tmp,0,r.write); + pos += r.read; + if( r.done ) + break; + } + u.close(); + return b.getBytes(); + } + + static var _inflate_init = cpp.Lib.load("zlib","inflate_init",1); + static var _inflate_buffer = cpp.Lib.load("zlib","inflate_buffer",5); + static var _inflate_end = cpp.Lib.load("zlib","inflate_end",1); + static var _set_flush_mode = cpp.Lib.load("zlib","set_flush_mode",2); + +} diff --git a/std/cpp/_std/sys/FileSystem.hx b/std/cpp/_std/sys/FileSystem.hx index 6fd1d4b984421e52ea7574b8a75aa7c6a636af3c..3972505569328fff8036f47cb8edf86d6a2fb242 100644 --- a/std/cpp/_std/sys/FileSystem.hx +++ b/std/cpp/_std/sys/FileSystem.hx @@ -30,13 +30,13 @@ private enum FileKind { @:coreApi class FileSystem { - public static inline function exists( path : String ) : Bool { - return sys_exists(path); + public static function exists( path : String ) : Bool { + return sys_exists(haxe.io.Path.removeTrailingSlashes(path)); } - public static function rename( path : String, newpath : String ) : Void { - if (sys_rename(path,newpath)==null) - throw "Could not rename:" + path + " to " + newpath; + public static function rename( path : String, newPath : String ) : Void { + if (sys_rename(path,newPath)==null) + throw "Could not rename:" + path + " to " + newPath; } public static function stat( path : String ) : FileStat { @@ -49,12 +49,17 @@ class FileSystem { return s; } - public static function fullPath( relpath : String ) : String { - return new String(file_full_path(relpath)); + public static function fullPath( relPath : String ) : String { + return new String(file_full_path(relPath)); + } + + public static function absolutePath ( relPath : String ) : String { + if (haxe.io.Path.isAbsolute(relPath)) return relPath; + return haxe.io.Path.join([Sys.getCwd(), relPath]); } static function kind( path : String ) : FileKind { - var k:String = sys_file_type(path); + var k:String = sys_file_type(haxe.io.Path.removeTrailingSlashes(path)); return switch(k) { case "file": kfile; case "dir": kdir; @@ -68,8 +73,12 @@ class FileSystem { public static function createDirectory( path : String ) : Void { var path = haxe.io.Path.addTrailingSlash(path); - var parts = [while ((path = haxe.io.Path.directory(path)) != "") path]; - parts.reverse(); + var _p = null; + var parts = []; + while (path != (_p = haxe.io.Path.directory(path))) { + parts.unshift(path); + path = _p; + } for (part in parts) { if (part.charCodeAt(part.length - 1) != ":".code && !exists(part) && sys_create_dir( part, 493 )==null) throw "Could not create directory:" + part; diff --git a/std/cpp/_std/sys/db/Mysql.hx b/std/cpp/_std/sys/db/Mysql.hx new file mode 100644 index 0000000000000000000000000000000000000000..c6783360ddc3aeb9029c4dae3063ae9ac233bdbe --- /dev/null +++ b/std/cpp/_std/sys/db/Mysql.hx @@ -0,0 +1,204 @@ +/* + * Copyright (C)2005-2012 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.db; + +private class D { + + static function load(fun,args) : Dynamic { + return cpp.Lib.load(lib,fun,args); + } + + static var lib = "mysql5"; + public static var connect = load("mysql_connect",1); + public static var select_db = load("select_db",2); + public static var request = load("request",2); + public static var close = load("close",1); + public static var escape = load("escape", 2); + public static var set_conv_funs = load("set_conv_funs", 4); + public static var result_get_length = load("result_get_length",1); + public static var result_get_nfields = load("result_get_nfields",1); + public static var result_next = load("result_next",1); + public static var result_get = load("result_get",2); + public static var result_get_int = load("result_get_int",2); + public static var result_get_float = load("result_get_float",2); + public static var result_fields_names = cpp.Lib.loadLazy(lib,"result_get_fields_names",1); + +} + +private class MysqlResultSet implements sys.db.ResultSet { + + public var length(get,null) : Int; + public var nfields(get,null) : Int; + private var __r : Dynamic; + private var cache : Dynamic; + + public function new(r) { + __r = r; + } + + private function get_length() { + return D.result_get_length(__r); + } + + private function get_nfields() { + return D.result_get_nfields(__r); + } + + public function hasNext() { + if( cache == null ) + cache = next(); + return (cache != null); + } + + public function next() : Dynamic { + var c = cache; + if( c != null ) { + cache = null; + return c; + } + c = D.result_next(__r); + return c; + } + + public function results() : List { + var l = new List(); + while( hasNext() ) + l.add(next()); + return l; + } + + public function getResult( n : Int ) { + return new String(D.result_get(__r,n)); + } + + public function getIntResult( n : Int ) : Int { + return D.result_get_int(__r,n); + } + + public function getFloatResult( n : Int ) : Float { + return D.result_get_float(__r,n); + } + + public function getFieldsNames() : Array { + var a = D.result_fields_names(__r); + return a; + } + +} + +private class MysqlConnection implements sys.db.Connection { + + private var __c : Dynamic; + + public function new(c) { + __c = c; + D.set_conv_funs(c, function(s) return new String(s), function(d) return untyped Date.new1(d), function(b) return haxe.io.Bytes.ofData(b)); + } + + public function request( s : String ) : sys.db.ResultSet { + var r = D.request(this.__c, s); + return new MysqlResultSet(r); + } + + public function close() { + D.close(__c); + } + + public function escape( s : String ) { + return new String(D.escape(__c,s)); + } + + public function quote( s : String ) { + return "'"+escape(s)+"'"; + } + + public function addValue( s : StringBuf, v : Dynamic ) { + if (v == null) { + s.add(v); + } + else if (Std.is(v,Bool)) { + s.add( v ? 1 : 0 ); + } else { + var t:Int = untyped v.__GetType(); + if( t == 0xff ) + s.add(v); + else if( t == 2 ) + s.add( untyped v.__GetInt() ? "1".code : "0".code ); + else { + s.addChar("'".code); + s.add(escape(Std.string(v))); + s.addChar("'".code); + } + } + } + + public function lastInsertId() { + return request("SELECT LAST_INSERT_ID()").getIntResult(0); + } + + public function dbName() { + return "MySQL"; + } + + public function startTransaction() { + request("START TRANSACTION"); + } + + public function commit() { + request("COMMIT"); + } + + public function rollback() { + request("ROLLBACK"); + } + + private static var __use_date = Date; +} + +@:coreApi class Mysql { + + public static function connect( params : { + host : String, + ?port : Int, + user : String, + pass : String, + ?socket : String, + database : String + } ) : sys.db.Connection { + var o = { + host : params.host, + port : if( params.port == null ) 3306 else params.port, + user : params.user, + pass : params.pass, + socket : if( params.socket == null ) null else params.socket + }; + var c = D.connect(o); + try { + D.select_db(c,params.database); + } catch( e : Dynamic ) { + D.close(c); + cpp.Lib.rethrow(e); + } + return new MysqlConnection(c); + } + +} diff --git a/std/cpp/_std/sys/db/Sqlite.hx b/std/cpp/_std/sys/db/Sqlite.hx new file mode 100644 index 0000000000000000000000000000000000000000..4fe60d37f2c23ea5a28d9192ac4bd32e038c24ac --- /dev/null +++ b/std/cpp/_std/sys/db/Sqlite.hx @@ -0,0 +1,188 @@ +/* + * Copyright (C)2005-2012 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.db; + +private class SqliteConnection implements Connection { + + var c : Dynamic; + + public function new( file : String ) { + c = _connect(file); + } + + public function close() { + _close(c); + } + + public function request( s : String ) : ResultSet { + try { + return new SqliteResultSet(_request(c,s)); + } catch( e : String ) { + throw "Error while executing "+s+" ("+e+")"; + } + } + + public function escape( s : String ) { + return s.split("'").join("''"); + } + + public function quote( s : String ) { + if( s.indexOf("\000") >= 0 ) + return "x'"+new String(_encode(s,"0123456789ABCDEF"))+"'"; + return "'"+s.split("'").join("''")+"'"; + } + + public function addValue( s : StringBuf, v : Dynamic ) { + if (v == null) { + s.add(v); + } + else if (Std.is(v,Bool)) { + s.add( v ? 1 : 0 ); + } else { + var t:Int = untyped v.__GetType(); + if( t == 0xff ) + s.add(v); + else if( t == 2 ) + s.add( untyped v.__GetInt() ); + else + s.add(quote(Std.string(v))); + } + } + + public function lastInsertId() { + return _last_id(c); + } + + public function dbName() { + return "SQLite"; + } + + public function startTransaction() { + request("BEGIN TRANSACTION"); + } + + public function commit() { + request("COMMIT"); + startTransaction(); // match mysql usage + } + + public function rollback() { + request("ROLLBACK"); + startTransaction(); // match mysql usage + } + + static var _encode = cpp.Lib.load("std","base_encode",2); + static var _connect = cpp.Lib.load("sqlite","sqlite_connect",1); + static var _close = cpp.Lib.load("sqlite","close",1); + static var _request = cpp.Lib.load("sqlite","request",2); + static var _last_id = cpp.Lib.load("sqlite","last_insert_id",1); +} + + +private class SqliteResultSet implements ResultSet { + + public var length(get,null) : Int; + public var nfields(get,null) : Int; + var r : Dynamic; + var cache : List; + + public function new( r ) { + cache = new List(); + this.r = r; + hasNext(); // execute the request + } + + function get_length() { + if( nfields != 0 ) { + while( true ) { + var c = result_next(r); + if( c == null ) + break; + cache.add(c); + } + return cache.length; + } + return result_get_length(r); + } + + function get_nfields() { + return result_get_nfields(r); + } + + public function hasNext() { + var c = next(); + if( c == null ) + return false; + cache.push(c); + return true; + } + + public function next() : Dynamic { + var c = cache.pop(); + if( c != null ) + return c; + return result_next(r); + } + + public function results() : List { + var l = new List(); + while( true ) { + var c = next(); + if( c == null ) + break; + l.add(c); + } + return l; + } + + public function getResult( n : Int ) { + return new String(result_get(r,n)); + } + + public function getIntResult( n : Int ) : Int { + return result_get_int(r,n); + } + + public function getFloatResult( n : Int ) : Float { + return result_get_float(r,n); + } + + public function getFieldsNames() : Array { + return null; + } + + static var result_next = cpp.Lib.load("sqlite","result_next",1); + static var result_get_length = cpp.Lib.load("sqlite","result_get_length",1); + static var result_get_nfields = cpp.Lib.load("sqlite","result_get_nfields",1); + static var result_get = cpp.Lib.load("sqlite","result_get",2); + static var result_get_int = cpp.Lib.load("sqlite","result_get_int",2); + static var result_get_float = cpp.Lib.load("sqlite","result_get_float",2); + +} + +@:coreApi class Sqlite { + + public static function open( file : String ) : Connection { + return new SqliteConnection(file); + } + +} diff --git a/std/cpp/_std/sys/io/File.hx b/std/cpp/_std/sys/io/File.hx index 07f284cef302fae4513f41021c414462d7dad649..babadf959d3ad72f00ad4de3f94e3d214e6b8cac 100644 --- a/std/cpp/_std/sys/io/File.hx +++ b/std/cpp/_std/sys/io/File.hx @@ -58,9 +58,9 @@ class File { return untyped new FileOutput(file_open(path,(if( binary ) "ab" else "a"))); } - public static function copy( src : String, dst : String ) : Void { - var s = read(src,true); - var d = write(dst,true); + public static function copy( srcPath : String, dstPath : String ) : Void { + var s = read(srcPath,true); + var d = write(dstPath,true); d.writeInput(s); s.close(); d.close(); diff --git a/std/cpp/_std/sys/net/Socket.hx b/std/cpp/_std/sys/net/Socket.hx index 1fde066622bc793b3c143e65276162bcf4be78e9..e6612ef429a202184d6892933958fcdaf0c1419a 100644 --- a/std/cpp/_std/sys/net/Socket.hx +++ b/std/cpp/_std/sys/net/Socket.hx @@ -157,7 +157,7 @@ class Socket { socket_connect(__s, host.ip, port); } catch( s : String ) { if( s == "std@socket_connect" ) - throw "Failed to connect on "+(try host.reverse() catch( e : Dynamic ) host.toString())+":"+port; + throw "Failed to connect on "+host.toString()+":"+port; else cpp.Lib.rethrow(s); } diff --git a/std/cpp/abi/Abi.hx b/std/cpp/abi/Abi.hx new file mode 100644 index 0000000000000000000000000000000000000000..4e65c89e4995bf9f7f464b15c79aec071676d3bf --- /dev/null +++ b/std/cpp/abi/Abi.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +// Base case, for calling conventions - means "use default" +extern class Abi { } diff --git a/std/cpp/abi/CDecl.hx b/std/cpp/abi/CDecl.hx new file mode 100644 index 0000000000000000000000000000000000000000..dd754e4042d0009c78af70b9f8348374028fd39c --- /dev/null +++ b/std/cpp/abi/CDecl.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +@:abi("__cdecl") +extern class CDecl extends Abi { } diff --git a/std/cpp/abi/FastCall.hx b/std/cpp/abi/FastCall.hx new file mode 100644 index 0000000000000000000000000000000000000000..a8802b71cdeeb4fcb702d24d9d51f20024868e4a --- /dev/null +++ b/std/cpp/abi/FastCall.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +@:abi("__fastcall") +extern class FastCall extends Abi { } diff --git a/std/cpp/abi/StdCall.hx b/std/cpp/abi/StdCall.hx new file mode 100644 index 0000000000000000000000000000000000000000..3e0fd8171fc184357d6a5bd3682dfa862c10c0a8 --- /dev/null +++ b/std/cpp/abi/StdCall.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +@:abi("__stdcall") +extern class StdCall extends Abi { } diff --git a/std/cpp/abi/ThisCall.hx b/std/cpp/abi/ThisCall.hx new file mode 100644 index 0000000000000000000000000000000000000000..1e98f0e7f76a93d8c1dc7d445b3a106065b0b0b4 --- /dev/null +++ b/std/cpp/abi/ThisCall.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +@:abi("__thiscall") +extern class ThisCall extends Abi { } diff --git a/std/cpp/abi/Winapi.hx b/std/cpp/abi/Winapi.hx new file mode 100644 index 0000000000000000000000000000000000000000..4a57e31d9ebcc57a9da7b7ac84f457e2a8116c8f --- /dev/null +++ b/std/cpp/abi/Winapi.hx @@ -0,0 +1,4 @@ +package cpp.abi; + +@:abi("__stdcall") +extern class Winapi extends Abi { } diff --git a/std/cpp/cppia/Host.hx b/std/cpp/cppia/Host.hx new file mode 100644 index 0000000000000000000000000000000000000000..dac1e75850215c30cc4fdfc2c9a861e2cc422495 --- /dev/null +++ b/std/cpp/cppia/Host.hx @@ -0,0 +1,28 @@ +package cpp.cppia; + + +@:build(cpp.cppia.HostClasses.include()) +class Host +{ + public static function run(source:String) + { + untyped __global__.__scriptable_load_cppia(source); + } + + public static function main() + { + var script = Sys.args()[0]; + #if (!scriptable && !doc_gen) + #error "Please define scriptable to use cppia" + #end + if (script==null) + { + Sys.println("Usage : Cppia scriptname"); + } + else + { + var source = sys.io.File.getContent(script); + run(source); + } + } +} diff --git a/std/cpp/cppia/HostClasses.hx b/std/cpp/cppia/HostClasses.hx new file mode 100644 index 0000000000000000000000000000000000000000..d2b9c6644f7f55f4c55aefbf8b1b6dfbf2121e24 --- /dev/null +++ b/std/cpp/cppia/HostClasses.hx @@ -0,0 +1,229 @@ +package cpp.cppia; + +import haxe.macro.Compiler; +import haxe.macro.Context; +import haxe.macro.Type; + +#if !macro + #if cppia + @:build(cpp.cppia.HostClasses.exclude()) + #end +class HostClasses { } +#else + +import Sys; +import haxe.Constraints; + +@:noPackageRestrict +class HostClasses +{ + static var classes = [ + "cpp.Lib", + "cpp.NativeArray", + "cpp.NativeString", + "cpp.vm.Debugger", + "cpp.vm.Deque", + "cpp.vm.ExecutionTrace", + "cpp.vm.Gc", + "cpp.vm.Lock", + "cpp.vm.Mutex", + "cpp.vm.Profiler", + "cpp.vm.Thread", + "cpp.vm.Tls", + "cpp.vm.Unsafe", + "cpp.vm.WeakRef", + "cpp.Object", + "cpp.Int64", + "Std", + "StringBuf", + "sys.db.Mysql", + "sys.db.Sqlite", + "sys.db.Object", + "sys.db.Manager", + "sys.db.Connection", + "sys.FileSystem", + "sys.io.File", + "sys.io.FileInput", + "sys.net.Socket", + "Enum", + "EnumValue", + //"Sys", + "Type", + "Xml", + "Date", + "DateTools", + "List", + "Math", + "Reflect", + "StringBuf", + "StringTools", + + "haxe.ds.IntMap", + "haxe.ds.ObjectMap", + "haxe.ds.StringMap", + "haxe.CallStack", + "haxe.Serializer", + "haxe.Unserializer", + "haxe.Resource", + "haxe.Template", + "haxe.Utf8", + "haxe.Log", + "haxe.zip.Uncompress", + + "haxe.crypto.BaseCode", + "haxe.crypto.Sha256", + "haxe.crypto.Hmac", + "haxe.crypto.Crc32", + "haxe.crypto.Base64", + "haxe.crypto.Adler32", + "haxe.crypto.Md5", + "haxe.crypto.Sha1", + + "haxe.io.BufferInput", + "haxe.io.Bytes", + "haxe.io.BytesBuffer", + "haxe.io.BytesData", + "haxe.io.BytesInput", + "haxe.io.BytesOutput", + "haxe.io.Eof", + "haxe.io.Error", + "haxe.io.FPHelper", + "haxe.io.Input", + "haxe.io.Output", + "haxe.io.Path", + "haxe.io.StringInput", + "haxe.xml.Parser", + "haxe.Json", + + "haxe.CallStack", + "haxe.Resource", + "haxe.Utf8", + "haxe.Int64", + "haxe.Int32", + "haxe.Serializer", + "haxe.Unserializer", + + + "haxe.ds.ArraySort", + "haxe.ds.GenericStack", + "haxe.ds.ObjectMap", + "haxe.ds.Vector", + "haxe.ds.BalancedTree", + "haxe.ds.HashMap", + "haxe.ds.Option", + "haxe.ds.WeakMap", + "haxe.ds.EnumValueMap", + "haxe.ds.IntMap", + "haxe.ds.StringMap", + + "StdTypes", + "Array", + "Class", + "Date", + "EReg", + "Enum", + "EnumValue", + "IntIterator", + "List", + "Map", + "String", + + + ]; + + + static function parseClassInfo(externs:Map, filename:String) + { + if (sys.FileSystem.exists(filename)) + { + var file = sys.io.File.read(filename); + try + { + while(true) + { + var line = file.readLine(); + var parts = line.split(" "); + if (parts[0]=="class" || parts[0]=="interface" || parts[0]=="enum") + externs.set(parts[1],true); + } + } catch( e : Dynamic ) { } + if (file!=null) + file.close(); + } + } + + + static function onGenerateCppia(types:Array):Void + { + var externs = new Map(); + externs.set("Sys",true); + externs.set("haxe.IMap",true); + externs.set("haxe.crypto.HashMethod",true); + externs.set("haxe._Int64.Int64_Impl_",true); + externs.set("haxe._Int64.___Int64",true); + externs.set("haxe._Int32.Int32_Impl_",true); + externs.set("haxe._Int32.___Int32",true); + for(e in classes) + externs.set(e,true); + + + var define = Context.defined("dll_import") ? Context.definedValue("dll_import") : "1"; + if (define!="1") + parseClassInfo(externs,define); + else + { + var tried = new Map(); + for(path in Context.getClassPath()) + if (!tried.exists(path)) + { + tried.set(path,true); + parseClassInfo(externs,path + "/export_classes.info"); + } + } + + for(type in types) + { + switch(type) + { + case TInst(classRef, params): + if (externs.exists(classRef.toString())) + classRef.get().exclude(); + case TEnum(enumRef, params): + if (externs.exists(enumRef.toString())) + enumRef.get().exclude(); + default: + } + } + } + + // Exclude the standard classes, and any described in 'export_classes.info' files found in the classpath + public static function exclude() + { + if (Context.defined("cppia")) + Context.onGenerate(onGenerateCppia); + else + Context.error("cpp.cppia.excludeHostFiles is only for cppia code", Context.currentPos()); + return Context.getBuildFields(); + } + + + // Ensure that the standard classes are included in the host + public static function include() + { + Compiler.keep("haxe.IMap"); + Compiler.keep("haxe.crypto.HashMethod"); + Compiler.keep("haxe._Int64.Int64_Impl_"); + Compiler.keep("haxe._Int32.Int32_Impl_"); + Compiler.keep("haxe._Int64.___Int64"); + Compiler.keep("haxe._Int32.___Int32"); + for(cls in classes) + { + Context.getModule(cls); + Compiler.keep(cls); + } + return Context.getBuildFields(); + } +} +#end + + diff --git a/std/cpp/link/StaticMysql.hx b/std/cpp/link/StaticMysql.hx new file mode 100644 index 0000000000000000000000000000000000000000..75d5e4480e9d9c1c0c1c9fecf8749d2c9da0b40b --- /dev/null +++ b/std/cpp/link/StaticMysql.hx @@ -0,0 +1,17 @@ +package cpp.link; + +@:cppFileCode( 'extern "C" int mysql_register_prims();') +@:buildXml(" + + + + +") +@:keep class StaticMysql +{ + static function __init__() + { + untyped __cpp__("mysql_register_prims();"); + } +} + diff --git a/std/cpp/link/StaticRegexp.hx b/std/cpp/link/StaticRegexp.hx new file mode 100644 index 0000000000000000000000000000000000000000..74a8cdfb986932166449de1394e5e7c5b871d137 --- /dev/null +++ b/std/cpp/link/StaticRegexp.hx @@ -0,0 +1,16 @@ +package cpp.link; + +@:cppFileCode( 'extern "C" int regexp_register_prims();') +@:buildXml(" + + + +") +@:keep class StaticRegexp +{ + static function __init__() + { + untyped __cpp__("regexp_register_prims();"); + } +} + diff --git a/std/cpp/link/StaticSqlite.hx b/std/cpp/link/StaticSqlite.hx new file mode 100644 index 0000000000000000000000000000000000000000..1e382f139d2f340127be8e568c604f78ecae69f8 --- /dev/null +++ b/std/cpp/link/StaticSqlite.hx @@ -0,0 +1,17 @@ +package cpp.link; + +@:cppFileCode( 'extern "C" int sqlite_register_prims();') +@:buildXml(" + + + + +") +@:keep class StaticSqlite +{ + static function __init__() + { + untyped __cpp__("sqlite_register_prims();"); + } +} + diff --git a/std/cpp/link/StaticStd.hx b/std/cpp/link/StaticStd.hx new file mode 100644 index 0000000000000000000000000000000000000000..a58166d89ca118d01fac3850938884bf35e6cebc --- /dev/null +++ b/std/cpp/link/StaticStd.hx @@ -0,0 +1,17 @@ +package cpp.link; + +@:cppFileCode( 'extern "C" int std_register_prims();') +@:buildXml(" + + + + +") +@:keep class StaticStd +{ + static function __init__() + { + untyped __cpp__("std_register_prims();"); + } +} + diff --git a/std/cpp/link/StaticZlib.hx b/std/cpp/link/StaticZlib.hx new file mode 100644 index 0000000000000000000000000000000000000000..471000a05ae6ea125e9708597e59c85064054f3f --- /dev/null +++ b/std/cpp/link/StaticZlib.hx @@ -0,0 +1,16 @@ +package cpp.link; + +@:cppFileCode( 'extern "C" int zlib_register_prims();') +@:buildXml(" + + + +") +@:keep class StaticZlib +{ + static function __init__() + { + untyped __cpp__("zlib_register_prims();"); + } +} + diff --git a/std/cpp/net/ThreadServer.hx b/std/cpp/net/ThreadServer.hx new file mode 100644 index 0000000000000000000000000000000000000000..ebc996ae51258cdf331131b9d83dc25c3c822a30 --- /dev/null +++ b/std/cpp/net/ThreadServer.hx @@ -0,0 +1,283 @@ +/* +* Copyright (C)2005-2013 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 cpp.net; + +import cpp.vm.Thread; +import cpp.net.Poll; +import cpp.vm.Lock; + +private typedef ThreadInfos = { + var id : Int; + var t : Thread; + var p : Poll; + var socks : Array; +} + +private typedef ClientInfos = { + var client : Client; + var sock : sys.net.Socket; + var thread : ThreadInfos; + var buf : haxe.io.Bytes; + var bufpos : Int; +} + +class ThreadServer { + + var threads : Array; + var sock : sys.net.Socket; + var worker : Thread; + var timer : Thread; + public var listen : Int; + public var nthreads : Int; + public var connectLag : Float; + public var errorOutput : haxe.io.Output; + public var initialBufferSize : Int; + public var maxBufferSize : Int; + public var messageHeaderSize : Int; + public var updateTime : Float; + public var maxSockPerThread : Int; + + public function new() { + threads = new Array(); + nthreads = if( Sys.systemName() == "Windows" ) 150 else 10; + messageHeaderSize = 1; + listen = 10; + connectLag = 0.5; + errorOutput = Sys.stderr(); + initialBufferSize = (1 << 10); + maxBufferSize = (1 << 16); + maxSockPerThread = 64; + updateTime = 1; + } + + function runThread(t) { + while( true ) { + try { + loopThread(t); + } catch( e : Dynamic ) { + logError(e); + } + } + } + + function readClientData( c : ClientInfos ) { + var available = c.buf.length - c.bufpos; + if( available == 0 ) { + var newsize = c.buf.length * 2; + if( newsize > maxBufferSize ) { + newsize = maxBufferSize; + if( c.buf.length == maxBufferSize ) + throw "Max buffer size reached"; + } + var newbuf = haxe.io.Bytes.alloc(newsize); + newbuf.blit(0,c.buf,0,c.bufpos); + c.buf = newbuf; + available = newsize - c.bufpos; + } + var bytes = c.sock.input.readBytes(c.buf,c.bufpos,available); + var pos = 0; + var len = c.bufpos + bytes; + while( len >= messageHeaderSize ) { + var m = readClientMessage(c.client,c.buf,pos,len); + if( m == null ) + break; + pos += m.bytes; + len -= m.bytes; + work(clientMessage.bind(c.client,m.msg)); + } + if( pos > 0 ) + c.buf.blit(0,c.buf,pos,len); + c.bufpos = len; + } + + function loopThread( t : ThreadInfos ) { + if( t.socks.length > 0 ) + for( s in t.p.poll(t.socks,connectLag) ) { + var infos : ClientInfos = s.custom; + try { + readClientData(infos); + } catch( e : Dynamic ) { + t.socks.remove(s); + if( !Std.is(e,haxe.io.Eof) && !Std.is(e,haxe.io.Error) ) + logError(e); + work(doClientDisconnected.bind(s,infos.client)); + } + } + while( true ) { + var m : { s : sys.net.Socket, cnx : Bool } = Thread.readMessage(t.socks.length == 0); + if( m == null ) + break; + if( m.cnx ) + t.socks.push(m.s); + else if( t.socks.remove(m.s) ) { + var infos : ClientInfos = m.s.custom; + work(doClientDisconnected.bind(m.s,infos.client)); + } + } + } + + function doClientDisconnected(s,c) { + try s.close() catch( e : Dynamic ) {}; + clientDisconnected(c); + } + + function runWorker() { + while( true ) { + var f = Thread.readMessage(true); + try { + f(); + } catch( e : Dynamic ) { + logError(e); + } + try { + afterEvent(); + } catch( e : Dynamic ) { + logError(e); + } + } + } + + public function work( f : Void -> Void ) { + worker.sendMessage(f); + } + + function logError( e : Dynamic ) { + var stack = haxe.CallStack.exceptionStack(); + if( Thread.current() == worker ) + onError(e,stack); + else + work(onError.bind(e,stack)); + } + + function addClient( sock : sys.net.Socket ) { + var start = Std.random(nthreads); + for( i in 0...nthreads ) { + var t = threads[(start + i)%nthreads]; + if( t.socks.length < maxSockPerThread ) { + var infos : ClientInfos = { + thread : t, + client : clientConnected(sock), + sock : sock, + buf : haxe.io.Bytes.alloc(initialBufferSize), + bufpos : 0, + }; + sock.custom = infos; + infos.thread.t.sendMessage({ s : sock, cnx : true }); + return; + } + } + refuseClient(sock); + } + + function refuseClient( sock : sys.net.Socket) { + // we have reached maximum number of active clients + sock.close(); + } + + function runTimer() { + var l = new Lock(); + while( true ) { + l.wait(updateTime); + work(update); + } + } + + function init() { + worker = Thread.create(runWorker); + timer = Thread.create(runTimer); + for( i in 0...nthreads ) { + var t = { + id : i, + t : null, + socks : new Array(), + p : new Poll(maxSockPerThread), + }; + threads.push(t); + t.t = Thread.create(runThread.bind(t)); + } + } + + public function addSocket( s : sys.net.Socket ) { + s.setBlocking(false); + work(addClient.bind(s)); + } + + public function run( host, port ) { + sock = new sys.net.Socket(); + sock.bind(new sys.net.Host(host),port); + sock.listen(listen); + init(); + while( true ) { + try { + addSocket(sock.accept()); + } catch( e : Dynamic ) { + logError(e); + } + } + } + + public function sendData( s : sys.net.Socket, data : String ) { + try { + s.write(data); + } catch( e : Dynamic ) { + stopClient(s); + } + } + + public function stopClient( s : sys.net.Socket ) { + var infos : ClientInfos = s.custom; + try s.shutdown(true,true) catch( e : Dynamic ) { }; + infos.thread.t.sendMessage({ s : s, cnx : false }); + } + + // --- CUSTOMIZABLE API --- + + public dynamic function onError( e : Dynamic, stack ) { + var estr = try Std.string(e) catch( e2 : Dynamic ) "???" + try "["+Std.string(e2)+"]" catch( e : Dynamic ) ""; + errorOutput.writeString( estr + "\n" + haxe.CallStack.toString(stack) ); + errorOutput.flush(); + } + + public dynamic function clientConnected( s : sys.net.Socket ) : Client { + return null; + } + + public dynamic function clientDisconnected( c : Client ) { + } + + public dynamic function readClientMessage( c : Client, buf : haxe.io.Bytes, pos : Int, len : Int ) : { msg : Message, bytes : Int } { + return { + msg : null, + bytes : len, + }; + } + + public dynamic function clientMessage( c : Client, msg : Message ) { + } + + public dynamic function update() { + } + + public dynamic function afterEvent() { + } + +} diff --git a/std/cpp/rtti/FieldIntegerLookup.hx b/std/cpp/rtti/FieldIntegerLookup.hx index 4faf50c2eee03c5a17b700807b1e5d5c4495f4e8..9b9ad7c39b9a7fad931ece6740448d607c91343f 100644 --- a/std/cpp/rtti/FieldIntegerLookup.hx +++ b/std/cpp/rtti/FieldIntegerLookup.hx @@ -1,29 +1,29 @@ -/* - * Copyright (C)2005-2012 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 cpp.rtti; - -/** - If you implement this interface, then the backend will generate code that - allows fast dynamic access to fields by integer id. This should speed up the CFFI. -**/ -interface FieldIntegerLookup { -} +/* + * Copyright (C)2005-2012 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 cpp.rtti; + +/** + If you implement this interface, then the backend will generate code that + allows fast dynamic access to fields by integer id. This should speed up the CFFI. +**/ +interface FieldIntegerLookup { +} diff --git a/std/cpp/rtti/FieldNumericIntegerLookup.hx b/std/cpp/rtti/FieldNumericIntegerLookup.hx index 9ef2c99ba0f044e21492f0264f7ae7256c45214d..baf3d9d36e2f23e1441f2abb34813c548d6a84dc 100644 --- a/std/cpp/rtti/FieldNumericIntegerLookup.hx +++ b/std/cpp/rtti/FieldNumericIntegerLookup.hx @@ -1,29 +1,29 @@ -/* - * Copyright (C)2005-2012 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 cpp.rtti; - -/** - If you implement this interface, then the backend will generate code that - allows fast numeric access to fields by integer id. This should speed up the CFFI. -**/ -interface FieldNumericIntegerLookup { -} +/* + * Copyright (C)2005-2012 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 cpp.rtti; + +/** + If you implement this interface, then the backend will generate code that + allows fast numeric access to fields by integer id. This should speed up the CFFI. +**/ +interface FieldNumericIntegerLookup { +} diff --git a/std/cpp/vm/Debugger.hx b/std/cpp/vm/Debugger.hx index d6a76c49fb98d6f0d8cf52b93a48c7687416dfaa..1dc517bb75ae284638a2d5975ae4673ec94d1ef0 100644 --- a/std/cpp/vm/Debugger.hx +++ b/std/cpp/vm/Debugger.hx @@ -1,110 +1,419 @@ -/* - * Copyright (C)2005-2012 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 cpp.vm; - -import haxe.CallStack; - -class Debugger -{ - public static inline var BRK_THIS = -2; - public static inline var BRK_TERMINATE = -1; - - public static inline var BRK_NONE = 0; - public static inline var BRK_ASAP = 1; - public static inline var BRK_STEP = 2; - public static inline var BRK_ENTER = 3; - public static inline var BRK_LEAVE = 4; - - public static function setHandler(inHandler:Void->Void) - { - untyped __global__.__hxcpp_dbg_set_handler(inHandler); - } - - public static function setThread(?inDebugThread:Thread) - { - untyped __global__.__hxcpp_dbg_set_thread(inDebugThread==null?Thread.current().handle:inDebugThread.handle); - } - - - // Generate a handler callback ASAP - public static function setBreak(inMode:Int) - { - untyped __global__.__hxcpp_dbg_set_break(inMode); - } - - public static function exit() - { - untyped __global__.__hxcpp_dbg_set_break(BRK_TERMINATE); - } - public static function breakBad() - { - untyped __global__.__hxcpp_dbg_set_break(BRK_THIS); - } - - - - // Breakpoint - public static function addBreakpoint(inFileId:Int, inLine:Int) - { - untyped __global__.__hxcpp_breakpoints_add(inFileId, inLine); - } - - public static function getBreakpoints() : Array - { - return untyped __global__.__hxcpp_dbg_breakpoints_get(); - } - - public static function deleteBreakpoint(inI:Int) - { - untyped __global__.__hxcpp_dbg_breakpoints_delete(inI); - } - - // Thread - todo - // public static function suspendAll() - - // Callstack - public static function getStackFrames() : Array - { - return untyped __global__.__hxcpp_dbg_stack_frames_get(); - } - - public static function getStackVars(inFrame:Int) : Array - { - return untyped __global__.__hxcpp_dbg_get_stack_vars(inFrame); - } - - public static function getStackVar(inFrame:Int,inVar:String) : Dynamic - { - return untyped __global__.__hxcpp_dbg_get_stack_var(inFrame,inVar); - } - - public static function setStackVar(inFrame:Int,inVar:String, inValue:Dynamic) - { - untyped __global__.__hxcpp_dbg_set_stack_var(inFrame,inVar,inValue); - } - - public static function getFiles() : Array - { - return untyped __global__.__hxcpp_dbg_get_files(); - } -} - +/* + * Copyright (C)2005-2012 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 cpp.vm; + + +/** + * Parameter describes a function parameter. Instances of this class are + * embedded in stack frame objects to describe the function parameters that + * were used in the invocation of the function that defines that stack frame. + **/ +class Parameter +{ + public var name(default, null) : String; + public var value(default, null) : Dynamic; + + public function new(name : String, value : Dynamic) + { + this.name = name; + this.value = value; + } + } + +/** + * StackFrame describes one call stack frame. + **/ +class StackFrame + { + public var fileName(default, null) : String; + public var lineNumber(default, null) : Int; + public var className(default, null) : String; + public var functionName(default, null) : String; + public var parameters(default, null) : Array; + + public function new(fileName : String, lineNumber : Int, + className : String, functionName : String) + { + this.fileName = fileName; + this.lineNumber = lineNumber; + this.className = className; + this.functionName = functionName; + this.parameters = new Array(); + } + } + +/** + * ThreadInfo describes the state of a single thread. + **/ +class ThreadInfo + { + public static inline var STATUS_RUNNING = 1; + public static inline var STATUS_STOPPED_BREAK_IMMEDIATE = 2; + public static inline var STATUS_STOPPED_BREAKPOINT = 3; + public static inline var STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4; + public static inline var STATUS_STOPPED_CRITICAL_ERROR = 5; + + // 0 is never a valid thread number + public var number(default, null) : Int; + public var status(default, null) : Int; + // If status is "stopped breakpoint", this is the breakpoint number + public var breakpoint(default, null) : Int; + // If status is "critical error", this describes the error + public var criticalErrorDescription(default, null) : String; + // Stack will be listed with the lowest frame first + public var stack(default, null) : Array; + + public function new(number : Int, status : Int, breakpoint : Int = -1, + criticalErrorDescription : String = null) + { + this.number = number; + this.status = status; + this.breakpoint = breakpoint; + this.criticalErrorDescription = criticalErrorDescription; + this.stack = new Array(); + } + } + +/** + * This class wraps the hxcpp C++ implementation to provide a Haxe interface + * to the low level debugging features + **/ +class Debugger + { + public static inline var THREAD_CREATED = 1; + public static inline var THREAD_TERMINATED = 2; + public static inline var THREAD_STARTED = 3; + public static inline var THREAD_STOPPED = 4; + + public static inline var STEP_INTO = 1; + public static inline var STEP_OVER = 2; + public static inline var STEP_OUT = 3; + + // This tagging value is returned by getStackVariableValue() and + // setStackVariableValue if the requested value does not exist at the + // requested stack frame + public static var NONEXISTENT_VALUE = new String("NONEXISTENT_VALUE"); + // This tagging value is returned by getStackVariableValue and + // setStackVariableValue if the stack variable that is being set is on a + // thread that is running, in which case the set does not take place. + public static var THREAD_NOT_STOPPED = new String("THREAD_NOT_STOPPED"); + + /** + * Sets the handler callback to be made when asynchronous events occur, + * specifically, when threads are created, terminated, started, or + * stopped. The calling thread becomes the "debugger" thread, which means + * that it will be discluded from any breakpoints and will not be reported + * on by any thread reporting requests. + * + * Be aware that this callback is made asynchronously and possibly by + * multiple threads simultaneously. + * + * Setting this to null prevents further callbacks. + * + * Throws a string exception if the program does not support debugging + * because it was not compiled with the HXCPP_DEBUGGER flag set. + * + * @param handler is a function that will be called back by asynchronous + * thread events. Note that this function is called directly from + * the thread experiencing the event and the handler should return + * quickly to avoid blocking the calling thread unnecessarily. + * The paramaters to handler are: + * - threadNumber, the thread number of the event + * - event, one of THREAD_CREATED, THREAD_TERMINATED, + * THREAD_STARTED, or THREAD_STOPPED + * - stackFrame, the stack frame number at which the thread is stopped, + * undefined if event is not THREAD_STOPPED + * - className, the class name at which the thread is stopped, + * undefined if event is not THREAD_STOPPED + * - functionName, the function name at which the thread is + * stopped, undefined if event is not THREAD_STOPPED + * - fileName, the file name at which the thread is stopped, + * undefined if event is not THREAD_STOPPED + * - lineNumber, the line number at which the thread is stopped, + * undefined if event is not THREAD_STOPPED + **/ + public static function setEventNotificationHandler( + handler : Int -> Int -> Int -> String -> String -> String -> Int -> Void) + { + untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler); + } + + /** + * This can be called to turn off (and then back on) all stopping of + * debugged threads temporarily. It should only be used by classes that + * actually implement the debugger to hide themselves from the debugger as + * necessary. + **/ + public static function enableCurrentThreadDebugging(enabled : Bool) + { + untyped __global__.__hxcpp_dbg_enableCurrentThreadDebugging(enabled); + } + + /** + * Returns the thread number of the calling thread. + * + * @return the thread number of the calling thread. + **/ + public static function getCurrentThreadNumber() : Int + { + return untyped __global__.__hxcpp_dbg_getCurrentThreadNumber(); + } + + /** + * Returns the set of source files known to the debugger. This is a copy + * of the original array and could be quite large. The caller should + * cache this value to avoid multiple copies needing to be made. + * + * @return the set of source files known to the debugger. + **/ + public static function getFiles() : Array + { + return untyped __global__.__hxcpp_dbg_getFiles(); + } + + + /** + * Returns the full paths of the set of source files known to the debugger. + * This is a copy of the original array and could be quite large. + * It is possible that this set will be empty, in which case the full paths are not known. + * The index of these files matches the index from "getFiles", so the full path for + * a given short path can be calculated. + * + * @return the known full paths of the set of source files + **/ + public static function getFilesFullPath() : Array + { + return untyped __global__.__hxcpp_dbg_getFilesFullPath(); + } + + /** + * Returns the set of class names of all classes known to the debugger. + * This is a copy of the original array and could be quite large. The + * caller should cache this value to avoid multiple copies needing to be + * made. + * + * @return the set of class names of all classes known to the debugger. + **/ + public static function getClasses() : Array + { + return untyped __global__.__hxcpp_dbg_getClasses(); + } + + /** + * Returns a ThreadInfo object describing every thread that existed at the + * moment that the call was made, except for the debugger thread. + **/ + public static function getThreadInfos() : Array + { + return untyped __global__.__hxcpp_dbg_getThreadInfos(); + } + + /** + * Returns a ThreadInfo object describing a single thread, or null if + * there is no such thread or the thread queried about was the debugger + * thread and unsafe was not true. + **/ + public static function getThreadInfo(threadNumber : Int, + unsafe : Bool) : ThreadInfo + { + return untyped __global__.__hxcpp_dbg_getThreadInfo + (threadNumber, unsafe); + } + + /** + * Adds a new file:line breakpoint. The breakpoint number of the newly + * added breakpoint is returned. + **/ + public static function addFileLineBreakpoint(file : String, + line : Int) : Int + { + return untyped __global__.__hxcpp_dbg_addFileLineBreakpoint + (file, line); + } + + /** + * Adds a new class:function breakpoint. The breakpoint number of the + * newly added breakpoint is returned. + **/ + public static function addClassFunctionBreakpoint(className : String, + functionName : String) : Int + { + return untyped __global__.__hxcpp_dbg_addClassFunctionBreakpoint + (className, functionName); + } + + /** + * Deletes a breakpoint, or all breakpoints. + **/ + public static function deleteBreakpoint(number : Null) + { + if (number == null) { + untyped __global__.__hxcpp_dbg_deleteAllBreakpoints(); + } + else { + untyped __global__.__hxcpp_dbg_deleteBreakpoint + (cast (number, Int)); + } + } + + /** + * Breaks all threads except the debugger thread (which should be the same + * as the calling thread!). + * + * If [wait] is true, waits up to 2 seconds for all threads to be broken. + * Threads which are in blocking system calls and cannot break after 2 + * seconds remain running when this function returns. + **/ + public static function breakNow(wait : Bool = true) + { + untyped __global__.__hxcpp_dbg_breakNow(wait); + } + + /** + * Continue execution of all stopped threads. If specialThreadNumber + * is a valid thread number, then it will be continued past + * [continueCount] breakpoints instead of just 1 like all of the other + * threads. + **/ + public static function continueThreads(specialThreadNumber : Int, + continueCount : Int) + { + untyped __global__.__hxcpp_dbg_continueThreads + (specialThreadNumber, continueCount); + } + + /** + * Single steps the given thread. + **/ + public static function stepThread(threadNumber : Int, + stepType : Int, + stepCount : Int = 1) + { + untyped __global__.__hxcpp_dbg_stepThread + (threadNumber, stepType, stepCount); + } + + /** + * Returns the list of local variables (including "this", function + * arguments, and local variables) visible to the given thread at the + * given stack frame. + * + * Returns a list with a single entry, THREAD_NOT_STOPPED, if the + * thread is not stopped and thus variables cannot be fetched and + * unsafe is not true. + * + * @return the list of local variables (including "this", function + * arguments, and local variables) visible to the given thread at + * the given stack frame. + **/ + public static function getStackVariables(threadNumber : Int, + stackFrameNumber : Int, + unsafe : Bool) : Array + { + return untyped __global__.__hxcpp_dbg_getStackVariables + (threadNumber, stackFrameNumber, unsafe, THREAD_NOT_STOPPED); + } + + /** + * Returns the value of a stack variable, or NONEXISTENT_VALUE if the + * requested value does not exist. If the thread is actively running + * and unsafe is not true, returns THREAD_NOT_STOPPED. + **/ + public static function getStackVariableValue(threadNumber : Int, + stackFrameNumber : Int, + name : String, + unsafe : Bool) : Dynamic + { + return untyped __global__.__hxcpp_dbg_getStackVariableValue + (threadNumber, stackFrameNumber, name, unsafe, NONEXISTENT_VALUE, + THREAD_NOT_STOPPED); + } + + /** + * Sets the value of a stack variable and returns that value. If the + * variable does not exist, on the stack, this function returns + * NONEXISTENT_VALUE. If the thread is actively running and unsafe is not + * true, returns THREAD_NOT_STOPPED, and the value is not set. + **/ + public static function setStackVariableValue(threadNumber : Int, + stackFrameNumber : Int, + name : String, + value : Dynamic, + unsafe : Bool) : Dynamic + { + return untyped __global__.__hxcpp_dbg_setStackVariableValue + (threadNumber, stackFrameNumber, name, value, unsafe, + NONEXISTENT_VALUE, THREAD_NOT_STOPPED); + } + + // The hxcpp runtime calls back through these functions to create Haxe + // objects as needed, which allows the C++ implementation code to create + // Haxe objects without having to actually know the structure of those + // objects + private static function __init__() + { + untyped __global__.__hxcpp_dbg_setNewParameterFunction + ( + function (name : String, value : Dynamic) : Dynamic { + return new Parameter(name, value); + } + ); + + untyped __global__.__hxcpp_dbg_setNewStackFrameFunction + ( + function (fileName : String, lineNumber : Int, + className : String, functionName : String) + { + return new StackFrame(fileName, lineNumber, + className, functionName); + } + ); + + untyped __global__.__hxcpp_dbg_setNewThreadInfoFunction + ( + function (number : Int, status : Int, breakpoint : Int, + criticalErrorDescription : String) : Dynamic { + return new ThreadInfo(number, status, breakpoint, + criticalErrorDescription); + } + ); + + untyped __global__.__hxcpp_dbg_setAddParameterToStackFrameFunction + ( + function(inStackFrame : Dynamic, inParameter : Dynamic) { + var stackFrame : StackFrame = cast inStackFrame; + var parameter : Parameter = cast inParameter; + stackFrame.parameters.push(parameter); + } + ); + + untyped __global__.__hxcpp_dbg_setAddStackFrameToThreadInfoFunction + ( + function(inThreadInfo : Dynamic, inStackFrame : Dynamic) { + var threadInfo : ThreadInfo = cast inThreadInfo; + var stackFrame : StackFrame = cast inStackFrame; + threadInfo.stack.push(stackFrame); + } + ); + } +} + diff --git a/std/cpp/vm/Deque.hx b/std/cpp/vm/Deque.hx index 0d219d22a8609631b76ad22cf7db2aca82cc96cb..999afe521bff26f9e64d1203cbabe43aecc776b6 100644 --- a/std/cpp/vm/Deque.hx +++ b/std/cpp/vm/Deque.hx @@ -33,7 +33,7 @@ class Deque { public function push( i : T ) { untyped __global__.__hxcpp_deque_push(q,i); } - public function pop( block : Bool ) : T { + public function pop( block : Bool ) : Null { return untyped __global__.__hxcpp_deque_pop(q,block); } } diff --git a/std/cpp/vm/ExecutionTrace.hx b/std/cpp/vm/ExecutionTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..773bcf168c68b010affd5726e90a8e2b78d282b1 --- /dev/null +++ b/std/cpp/vm/ExecutionTrace.hx @@ -0,0 +1,17 @@ +package cpp.vm; + +class ExecutionTrace +{ + public static function traceOff() + { + untyped __hxcpp_execution_trace(0); + } + public static function traceFunctions() + { + untyped __hxcpp_execution_trace(1); + } + public static function traceLines() + { + untyped __hxcpp_execution_trace(2); + } +} diff --git a/std/cpp/vm/Gc.hx b/std/cpp/vm/Gc.hx index e603c28b40d3253ba1480b43d79e050f109fbf69..be6b593ec71c11228b0a67cf6c0c793138a46a30 100644 --- a/std/cpp/vm/Gc.hx +++ b/std/cpp/vm/Gc.hx @@ -23,6 +23,11 @@ package cpp.vm; class Gc { + public static inline var MEM_INFO_USAGE = 0; + public static inline var MEM_INFO_RESERVED = 1; + public static inline var MEM_INFO_CURRENT = 2; + public static inline var MEM_INFO_LARGE = 3; + static public function enable(inEnable:Bool) : Void { untyped __global__.__hxcpp_enable(inEnable); @@ -38,9 +43,21 @@ class Gc untyped __global__.__hxcpp_gc_compact(); } + // Introduced hxcpp_api_level 310 + // Returns stats on memory usage: + // MEM_INFO_USAGE - estimate of how much is needed by program (at last collect) + // MEM_INFO_RESERVED - memory allocated for possible use + // MEM_INFO_CURRENT - memory in use, includes uncollected garbage. + // This will generally saw-tooth between USAGE and RESERVED + // MEM_INFO_LARGE - Size of separate pool used for large allocs. Included in all the above. + static public function memInfo(inWhatInfo:Int) : Int + { + return untyped __global__.__hxcpp_gc_mem_info(inWhatInfo); + } + static public function memUsage() : Int { - return untyped __global__.__hxcpp_gc_used_bytes(); + return untyped __global__.__hxcpp_gc_mem_info(MEM_INFO_USAGE); } static public function trace(sought:Class,printInstances:Bool=true) : Int @@ -74,4 +91,11 @@ class Gc { untyped __global__.__hxcpp_exit_gc_free_zone(); } + + @:unreflective + inline static public function setFinalizer(inObject:T, inFinalizer:cpp.CallableVoid> ) : Void + { + untyped __global__.__hxcpp_set_finalizer(inObject, inFinalizer); + } } + diff --git a/std/cpp/vm/Thread.hx b/std/cpp/vm/Thread.hx index 348c57cefba9c5802526f8b953e2cb058750ed3a..db7fec68e326aebe31a3594b873be3ddde595a44 100644 --- a/std/cpp/vm/Thread.hx +++ b/std/cpp/vm/Thread.hx @@ -62,7 +62,7 @@ class Thread { return untyped __global__.__hxcpp_thread_read_message(block); } - function __compare(t) : Int { + @:keep function __compare(t) : Int { return handle == t.handle ? 0 : 1; } diff --git a/std/cpp/vm/Unsafe.hx b/std/cpp/vm/Unsafe.hx new file mode 100644 index 0000000000000000000000000000000000000000..f7291145e85ba5324f76826e4dd7213f27ca9a7c --- /dev/null +++ b/std/cpp/vm/Unsafe.hx @@ -0,0 +1,10 @@ +package cpp.vm; + +class Unsafe +{ + public static inline function unsafeSet(outForced:Dynamic,inValue:Dynamic) : Void + { + untyped __global__.__hxcpp_unsafe_set(outForced,inValue); + } +} + diff --git a/std/cpp/vm/WeakRef.hx b/std/cpp/vm/WeakRef.hx index de07d9d4c97b127eb83f3a1a45b3d492468cd84b..5e52bf68ca456e04276aa1eb168926e6eb0c0ca6 100644 --- a/std/cpp/vm/WeakRef.hx +++ b/std/cpp/vm/WeakRef.hx @@ -36,16 +36,16 @@ class WeakRef else ref = untyped __global__.__hxcpp_weak_ref_create(inObject); } - - + + public function get():T { if (hardRef) return ref; - + return untyped __global__.__hxcpp_weak_ref_get(ref); } - + public function set(inObject:T):T { if (hardRef) @@ -54,7 +54,7 @@ class WeakRef ref = untyped __global__.__hxcpp_weak_ref_create(inObject); return inObject; } - + public function toString():String { return "WeakRef(" + get() + ")"; diff --git a/std/cpp/zip/Compress.hx b/std/cpp/zip/Compress.hx index 4d520a782e8a0020bacaf0eb4af0b1c2834a61b7..aebaf300ffd1b68189ca87d0d3d26614ab6b3d60 100644 --- a/std/cpp/zip/Compress.hx +++ b/std/cpp/zip/Compress.hx @@ -1,61 +1,5 @@ -/* - * Copyright (C)2005-2012 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 cpp.zip; - -class Compress { - - var s : Dynamic; - - public function new( level : Int ) { - s = _deflate_init(level); - } - - public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { - return _deflate_buffer(s,src.getData(),srcPos,dst.getData(),dstPos); - } - - public function setFlushMode( f : Flush ) { - _set_flush_mode(s,Std.string(f)); - } - - public function close() { - _deflate_end(s); - } - - public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes { - var c = new Compress(level); - c.setFlushMode(Flush.FINISH); - var out = haxe.io.Bytes.alloc(_deflate_bound(c.s,s.length)); - var r = c.execute(s,0,out,0); - c.close(); - if( !r.done || r.read != s.length ) - throw "Compression failed"; - return out.sub(0,r.write); - } - - static var _deflate_init = cpp.Lib.load("zlib","deflate_init",1); - static var _deflate_bound = cpp.Lib.load("zlib","deflate_bound",2); - static var _deflate_buffer = cpp.Lib.load("zlib","deflate_buffer",5); - static var _deflate_end = cpp.Lib.load("zlib","deflate_end",1); - static var _set_flush_mode = cpp.Lib.load("zlib","set_flush_mode",2); - -} +package cpp.zip; + +#if (haxe_ver < 3.4) +typedef Compress = haxe.zip.Compress; +#end \ No newline at end of file diff --git a/std/cpp/zip/Flush.hx b/std/cpp/zip/Flush.hx index 8c907969a7ca8b13729d582f1ec1a2674af4cd98..1af7536284cc675ac33fbc6fefb2700cdd766465 100644 --- a/std/cpp/zip/Flush.hx +++ b/std/cpp/zip/Flush.hx @@ -1,30 +1,5 @@ -/* - * Copyright (C)2005-2012 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 cpp.zip; -enum Flush { - NO; - SYNC; - FULL; - FINISH; - BLOCK; -} +#if (haxe_ver < 3.4) +typedef Flush = haxe.zip.FlushMode; +#end \ No newline at end of file diff --git a/std/cpp/zip/Uncompress.hx b/std/cpp/zip/Uncompress.hx index 671c64ceb76156aeae8170c758726d7bec860757..6313aca6b7ea7ba78c9c2541e0a345f7c7945e35 100644 --- a/std/cpp/zip/Uncompress.hx +++ b/std/cpp/zip/Uncompress.hx @@ -1,66 +1,5 @@ -/* - * Copyright (C)2005-2012 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 cpp.zip; -class Uncompress { - var s : Dynamic; - - public function new( windowBits : Null ) { - s = _inflate_init(windowBits); - } - - public function this_run( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { - return _inflate_buffer(s,src.getData(),srcPos,dst.getData(),dstPos); - } - - public function setFlushMode( f : Flush ) { - _set_flush_mode(s,untyped f.__Tag()); - } - - public function close() { - _inflate_end(s); - } - - public static function run( src : haxe.io.Bytes, ?bufsize ) : haxe.io.Bytes { - var u = new Uncompress(null); - if( bufsize == null ) bufsize = 1 << 16; // 64K - var tmp = haxe.io.Bytes.alloc(bufsize); - var b = new haxe.io.BytesBuffer(); - var pos = 0; - u.setFlushMode(Flush.SYNC); - while( true ) { - var r = u.this_run(src,pos,tmp,0); - b.addBytes(tmp,0,r.write); - pos += r.read; - if( r.done ) - break; - } - u.close(); - return b.getBytes(); - } - - static var _inflate_init = cpp.Lib.load("zlib","inflate_init",1); - static var _inflate_buffer = cpp.Lib.load("zlib","inflate_buffer",5); - static var _inflate_end = cpp.Lib.load("zlib","inflate_end",1); - static var _set_flush_mode = cpp.Lib.load("zlib","set_flush_mode",2); - -} +#if (haxe_ver < 3.4) +typedef Uncompress = haxe.zip.Uncompress; +#end \ No newline at end of file diff --git a/std/cs/Boot.hx b/std/cs/Boot.hx index 22273f37f25d7049da40f7c2deedeb32dfcc93ef..9a3d6bf462ced8fe9c1807e9f6d3d2248630d607 100644 --- a/std/cs/Boot.hx +++ b/std/cs/Boot.hx @@ -1,43 +1,48 @@ -/* - * Copyright (C)2005-2012 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 cs; -import cs.internal.Exceptions; -import cs.internal.FieldLookup; -import cs.internal.Function; -import cs.internal.HxObject; -import cs.internal.Runtime; -import cs.internal.Iterator; -import cs.internal.Null; -import cs.internal.StringExt; -import cs.StdTypes; -import haxe.ds.StringMap; -import Reflect; - -class Boot -{ - - @:keep public static function init():Void - { - cs.Lib.applyCultureChanges(); - } - -} +/* + * Copyright (C)2005-2012 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 cs; +import cs.internal.Exceptions; +import cs.internal.FieldLookup; +import cs.internal.Function; +import cs.internal.HxObject; +import cs.internal.Runtime; +import cs.internal.Iterator; +#if !erase_generics +import cs.internal.Null; +#end +import cs.internal.StringExt; +#if unsafe +import cs.internal.BoxedPointer; +#end +import cs.StdTypes; +import haxe.ds.StringMap; +import Reflect; + +class Boot +{ + + @:keep public static function init():Void + { + cs.Lib.applyCultureChanges(); + } + +} diff --git a/std/cs/Flags.hx b/std/cs/Flags.hx new file mode 100644 index 0000000000000000000000000000000000000000..f9204ba359ce996d39df29eb439bb0a13a16ee86 --- /dev/null +++ b/std/cs/Flags.hx @@ -0,0 +1,100 @@ +package cs; + +/** + Use this type to have access to the bitwise operators of C# enums that have a `cs.system.FlagsAttribute` attribute. + + Usage example: + ```haxe + import cs.system.reflection.BindingFlags; + + var binding = new Flags(BindingFlags.Public) | BindingFlags.Static | BindingFlags.NonPublic; + ``` + **/ +abstract Flags(T) from T to T +{ + + /** + Creates a new `Flags` type with an optional initial value. If no initial value was specified, + the default enum value for an empty flags attribute is specified + **/ + @:extern inline public function new(?initial:T) + this = initial; + + /** + Accessible through the bitwise OR operator (`|`). Returns a new `Flags` type with the flags + passed at `flags` added to it. + **/ + @:op(A|B) @:extern inline public function add(flags:Flags):Flags + { + return new Flags(underlying() | flags.underlying()); + } + + /** + Accessible through the bitwise AND operator (`&`). Returns a new `Flags` type with + the flags that are set on both `this` and `flags` + **/ + @:op(A&B) @:extern inline public function bitAnd(flags:Flags):Flags + { + return new Flags(underlying() & flags.underlying()); + } + + /** + Accessible through the bitwise XOR operator (`^`). + **/ + @:op(A^B) @:extern inline public function bitXor(flags:Flags):Flags + { + return new Flags(underlying() & flags.underlying()); + } + + /** + Accesible through the bitwise negation operator (`~`). Returns a new `Flags` type + with all unset flags as set - but the ones that are set already. + **/ + @:op(~A) @:extern inline public function bitNeg():Flags + { + return new Flags(~underlying()); + } + + /** + Returns a new `Flags` type with all flags set by `flags` unset + **/ + @:extern inline public function remove(flags:Flags):Flags + { + return new Flags(underlying() & ~flags.underlying()); + } + + /** + Returns whether `flag` is present on `this` type + **/ + @:extern inline public function has(flag:T):Bool + { + return underlying() & new Flags(flag).underlying() != null; + } + + /** + Returns whether `this` type has any flag set by `flags` also set + **/ + @:extern inline public function hasAny(flags:Flags):Bool + { + return underlying() & flags.underlying() != null; + } + + /** + Returns whether `this` type has all flags set by `flags` also set + **/ + @:extern inline public function hasAll(flags:Flags):Bool + { + return underlying() & flags.underlying() == flags.underlying(); + } + + @:extern inline private function underlying():EnumUnderlying + return this; +} + +@:coreType private abstract EnumUnderlying from T to T +{ + @:op(A|B) public static function or(lhs:EnumUnderlying, rhs:EnumUnderlying):T; + @:op(A^B) public static function xor(lhs:EnumUnderlying, rhs:EnumUnderlying):T; + @:op(A&B) public static function and(lhs:EnumUnderlying, rhs:EnumUnderlying):T; + @:op(~A) public static function bneg(t:EnumUnderlying):T; +} diff --git a/std/cs/Lib.hx b/std/cs/Lib.hx index a8d4c49a981d980d10e2941437a837da669432b0..b884dfe2b3a7ae7a4f1efdd078ad6dc7d7cb878e 100644 --- a/std/cs/Lib.hx +++ b/std/cs/Lib.hx @@ -1,274 +1,315 @@ -/* - * Copyright (C)2005-2012 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 cs; -import cs.system.Type; - -/** - Platform-specific C# Library. Provides some platform-specific functions for the C# target, - such as conversion from haxe types to native types and vice-versa. -**/ -class Lib -{ - @:keep private static var decimalSeparator:String; - - /** - Changes the current culture settings to allow a consistent cross-target behavior. - Currently the only change made is in regard to the decimal separator, which is always set to "." - **/ - @:functionCode(' - System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.Name, true); - decimalSeparator = ci.NumberFormat.NumberDecimalSeparator; - ci.NumberFormat.NumberDecimalSeparator = "."; - System.Threading.Thread.CurrentThread.CurrentCulture = ci; - ') - @:keep public static function applyCultureChanges():Void - { - - } - - /** - Reverts the culture changes to the default settings. - **/ - @:functionCode(' - System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.Name, true); - System.Threading.Thread.CurrentThread.CurrentCulture = ci; - ') - public static function revertDefaultCulture():Void - { - - } - - /** - Returns a native array from the supplied Array. This native array is unsafe to be written on, - as it may or may not be linked to the actual Array implementation. - - If equalLengthRequired is true, the result might be a copy of an array with the correct size. - **/ - public static function nativeArray(arr:Array, equalLengthRequired:Bool):NativeArray - { - var native:NativeArray = untyped arr.__a; - var len = arr.length; - if (!equalLengthRequired || native.Length == len) - { - return native; - } else { - var ret = new NativeArray(len); - cs.system.Array.Copy(native, 0, ret, 0, len); - return ret; - } - } - - /** - Provides support for the "as" keyword in C#. - If the object is not of the supplied type "T", it will return null instead of rasing an exception. - - This function will not work with Value Types (such as Int, Float, Bool...) - **/ - @:functionCode(' - throw new haxe.lang.HaxeException("This function cannot be accessed at runtime"); - ') - @:extern public static inline function as(obj:Dynamic, cl:Class):T - { - return untyped __as__(obj, cl); - } - - /** - Returns a Class<> equivalent to the native System.Type type. - - Currently Haxe's Class<> is equivalent to System.Type, but this is an implementation detail. - This may change in the future, so use this function whenever you need to perform such conversion. - **/ - public static inline function fromNativeType(t:cs.system.Type):Class - { - return untyped t; - } - - /** - Returns a System.Type equivalent to the Haxe Class<> type. - - Currently Haxe's Class<> is equivalent to System.Type, but this is an implementation detail. - This may change in the future, so use this function whenever you need to perform such conversion. - **/ - public static inline function toNativeType(cl:Class):Type - { - return untyped cl; - } - - /** - Gets the native System.Type from the supplied object. Will throw an exception in case of null being passed. - **/ - public static function nativeType(obj:Dynamic):Type - { - return untyped obj.GetType(); - } - - /** - Returns a Haxe Array of a native Array. - It won't copy the contents of the native array, so unless any operation triggers an array resize, - all changes made to the Haxe array will affect the native array argument. - **/ - public static function array(native:cs.NativeArray):Array - { - return untyped Array.ofNative(native); - } - - /** - Allocates a new Haxe Array with a predetermined size - **/ - public static function arrayAlloc(size:Int):Array - { - return untyped Array.alloc(size); - } - - /** - Creates a "checked" block, which throws exceptions for overflows. - - Usage: - cs.Lib.checked({ - var x = 1000; - while(true) - { - x *= x; - } - }); - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function checked(block:V):Void - { - untyped __checked__(block); - } - - /** - Ensures that one thread does not enter a critical section of code while another thread - is in the critical section. If another thread attempts to enter a locked code, it - will wait, block, until the object is released. - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function lock(obj:O, block:V):Void - { - untyped __lock__(obj, block); - } - - //Unsafe code manipulation - #if unsafe - /** - Marks its parameters as fixed objects inside the defined block. - The first variable declarations that use cs.Lib.pointerOfArray() will be the fixed definitions. - Usage: - cs.Lib.fixed({ - var obj1 = cs.Lib.pointerOfArray(someArray); - var obj2 = cs.Lib.pointerOfArray(someArray2); - var obj3 = cs.Lib.pointerOfArray(someArray3); - //from now on, obj1, obj2 and obj3 are fixed - //we cannot change obj1, obj2 or obj3 variables like this: - //obj1++; - }); - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function fixed(block:V):Void - { - untyped __fixed__(block); - } - - /** - Marks the contained block as an unsafe block, meaning that it can contain unsafe code. - Usage: - cs.Lib.unsafe({ - //unsafe code is allowed inside here - }); - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function unsafe(block:V):Void - { - untyped __unsafe__(block); - } - - /** - Gets the pointer to the address of current local. Equivalent to the "&" operator in C# - Usage: - var x:Int = 0; - cs.Lib.unsafe({ - var addr = cs.Lib.addressOf(x); - x[0] = 42; - }); - trace(x); //42 - - This method only exists at compile-time, so it can't be called via reflection. - Warning: This method will only work if a local variable is passed as an argument. - **/ - @:extern public static inline function addressOf(variable:T):cs.Pointer - { - return untyped __addressOf__(variable); - } - - /** - Gets the value of the pointer address. - Usage: - var x:Int = 0; - cs.Lib.unsafe({ - var addr = cs.Lib.addressOf(x); - trace(cs.Lib.valueOf(addr)); //0 - addr[0] = 42; - trace(cs.Lib.valueOf(addr)); //42 - }); - trace(x); //42 - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function valueOf(pointer:cs.Pointer):T - { - return untyped __valueOf__(pointer); - } - - /** - Transforms a managed native array into a Pointer. Must be inside a fixed statement - Usage: - var x:cs.NativeArray = new cs.NativeArray(1); - cs.Lib.unsafe({ - cs.Lib.fixed({ - var addr = cs.Lib.pointerOfArray(x); - trace(cs.Lib.valueOf(addr)); //0 - addr[0] = 42; - trace(cs.Lib.valueOf(addr)); //42 - }); - }); - trace(x[0]); //42 - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function pointerOfArray(array:cs.NativeArray):cs.Pointer - { - return cast array; - } - - /** - Returns the byte size of the given struct. Only works with structs and basic types. - **/ - @:extern public static inline function sizeof(struct:Class):Int - { - return untyped __sizeof__(struct); - } - #end -} +/* + * Copyright (C)2005-2012 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 cs; +import cs.system.Type; + +/** + Platform-specific C# Library. Provides some platform-specific functions for the C# target, + such as conversion from haxe types to native types and vice-versa. +**/ +class Lib +{ + @:keep private static var decimalSeparator:String; + + /** + Changes the current culture settings to allow a consistent cross-target behavior. + Currently the only change made is in regard to the decimal separator, which is always set to "." + **/ + @:keep public static function applyCultureChanges():Void + { + var ci = new cs.system.globalization.CultureInfo(cs.system.threading.Thread.CurrentThread.CurrentCulture.Name, true); + decimalSeparator = ci.NumberFormat.NumberDecimalSeparator; + ci.NumberFormat.NumberDecimalSeparator = "."; + cs.system.threading.Thread.CurrentThread.CurrentCulture = ci; + } + + /** + Reverts the culture changes to the default settings. + **/ + public static function revertDefaultCulture():Void + { + var ci = new cs.system.globalization.CultureInfo(cs.system.threading.Thread.CurrentThread.CurrentCulture.Name, true); + cs.system.threading.Thread.CurrentThread.CurrentCulture = ci; + } + + /** + Returns a native array from the supplied Array. This native array is unsafe to be written on, + as it may or may not be linked to the actual Array implementation. + + If equalLengthRequired is true, the result might be a copy of an array with the correct size. + **/ + @:extern inline public static function nativeArray(arr:Array, equalLengthRequired:Bool):NativeArray + { + var ret = new cs.NativeArray(arr.length); +#if erase_generics + for (i in 0...arr.length) + ret[i] = arr[i]; +#else + p_nativeArray(arr,ret); +#end + return ret; + } + +#if !erase_generics + static function p_nativeArray(arr:Array, ret:cs.system.Array):Void + { + var native:NativeArray = untyped arr.__a; + var len = arr.length; + cs.system.Array.Copy(native, 0, ret, 0, len); + } +#end + + /** + Provides support for the "as" keyword in C#. + If the object is not of the supplied type "T", it will return null instead of rasing an exception. + + This function will not work with Value Types (such as Int, Float, Bool...) + **/ + @:extern public static inline function as(obj:Dynamic, cl:Class):T + { + return untyped __as__(obj); + } + + /** + Returns a Class<> equivalent to the native System.Type type. + + Currently Haxe's Class<> is equivalent to System.Type, but this is an implementation detail. + This may change in the future, so use this function whenever you need to perform such conversion. + **/ + public static inline function fromNativeType(t:cs.system.Type):Class + { + return untyped t; + } + + /** + Returns a System.Type equivalent to the Haxe Class<> type. + + Currently Haxe's Class<> is equivalent to System.Type, but this is an implementation detail. + This may change in the future, so use this function whenever you need to perform such conversion. + **/ + public static inline function toNativeType(cl:Class):Type + { + return untyped cl; + } + + /** + Returns a System.Type equivalent to the Haxe Enum<> type. + **/ + public static inline function toNativeEnum(cl:Enum):Type + { + return untyped cl; + } + + /** + Gets the native System.Type from the supplied object. Will throw an exception in case of null being passed. + [deprecated] - use `getNativeType` instead + **/ + @:deprecated('The function `nativeType` is deprecated and will be removed in later versions. Please use `getNativeType` instead') + public static function nativeType(obj:Dynamic):Type + { + return untyped obj.GetType(); + } + + /** + Gets the native System.Type from the supplied object. Will throw an exception in case of null being passed. + **/ + public static function getNativeType(obj:Dynamic):Type + { + return untyped obj.GetType(); + } + +#if erase_generics + inline private static function mkDynamic(native:NativeArray):NativeArray + { + var ret = new cs.NativeArray(native.Length); + for (i in 0...native.Length) + ret[i] = native[i]; + return ret; + } +#end + + /** + Returns a Haxe Array of a native Array. + Unless `erase_generics` is defined, it won't copy the contents of the native array, + so unless any operation triggers an array resize, all changes made to the Haxe array + will affect the native array argument. + **/ + inline public static function array(native:cs.NativeArray):Array + { +#if erase_generics + var dyn:NativeArray = mkDynamic(native); + return @:privateAccess Array.ofNative(dyn); +#else + return @:privateAccess Array.ofNative(native); +#end + } + + /** + Allocates a new Haxe Array with a predetermined size + **/ + inline public static function arrayAlloc(size:Int):Array + { + return @:privateAccess Array.alloc(size); + } + + /** + Rethrow an exception. This is useful when manually filtering an exception in order + to keep the previous exception stack. + **/ + @:extern inline public static function rethrow(e:Dynamic):Void + { + untyped __rethrow__(); + } + + /** + Creates a "checked" block, which throws exceptions for overflows. + + Usage: + cs.Lib.checked({ + var x = 1000; + while(true) + { + x *= x; + } + }); + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function checked(block:V):Void + { + untyped __checked__(block); + } + + /** + Ensures that one thread does not enter a critical section of code while another thread + is in the critical section. If another thread attempts to enter a locked code, it + will wait, block, until the object is released. + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function lock(obj:O, block:V):Void + { + untyped __lock__(obj, block); + } + + //Unsafe code manipulation + #if unsafe + /** + Marks its parameters as fixed objects inside the defined block. + The first variable declarations that use cs.Lib.pointerOfArray() will be the fixed definitions. + Usage: + cs.Lib.fixed({ + var obj1 = cs.Lib.pointerOfArray(someArray); + var obj2 = cs.Lib.pointerOfArray(someArray2); + var obj3 = cs.Lib.pointerOfArray(someArray3); + //from now on, obj1, obj2 and obj3 are fixed + //we cannot change obj1, obj2 or obj3 variables like this: + //obj1++; + }); + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function fixed(block:V):Void + { + untyped __fixed__(block); + } + + /** + Marks the contained block as an unsafe block, meaning that it can contain unsafe code. + Usage: + cs.Lib.unsafe({ + //unsafe code is allowed inside here + }); + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function unsafe(block:V):Void + { + untyped __unsafe__(block); + } + + /** + Gets the pointer to the address of current local. Equivalent to the "&" operator in C# + Usage: + var x:Int = 0; + cs.Lib.unsafe({ + var addr = cs.Lib.addressOf(x); + x[0] = 42; + }); + trace(x); //42 + + This method only exists at compile-time, so it can't be called via reflection. + Warning: This method will only work if a local variable is passed as an argument. + **/ + @:extern public static inline function addressOf(variable:T):cs.Pointer + { + return untyped __addressOf__(variable); + } + + /** + Gets the value of the pointer address. + Usage: + var x:Int = 0; + cs.Lib.unsafe({ + var addr = cs.Lib.addressOf(x); + trace(cs.Lib.valueOf(addr)); //0 + addr[0] = 42; + trace(cs.Lib.valueOf(addr)); //42 + }); + trace(x); //42 + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function valueOf(pointer:cs.Pointer):T + { + return untyped __valueOf__(pointer); + } + + /** + Transforms a managed native array into a Pointer. Must be inside a fixed statement + Usage: + var x:cs.NativeArray = new cs.NativeArray(1); + cs.Lib.unsafe({ + cs.Lib.fixed({ + var addr = cs.Lib.pointerOfArray(x); + trace(cs.Lib.valueOf(addr)); //0 + addr[0] = 42; + trace(cs.Lib.valueOf(addr)); //42 + }); + }); + trace(x[0]); //42 + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function pointerOfArray(array:cs.NativeArray):cs.Pointer + { + return untyped __ptr__(array); + } + + /** + Returns the byte size of the given struct. Only works with structs and basic types. + **/ + @:extern public static inline function sizeof(struct:Class):Int + { + return untyped __sizeof__(struct); + } + #end +} diff --git a/std/cs/NativeArray.hx b/std/cs/NativeArray.hx index 9c3a55d400c539d3f5b9431da7dee3eec8b0f9e8..2435dd3cb2efcf5b6a5423d6d208ff4dc9f7880e 100644 --- a/std/cs/NativeArray.hx +++ b/std/cs/NativeArray.hx @@ -1,34 +1,80 @@ -/* - * Copyright (C)2005-2012 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 cs; - -extern class NativeArray extends cs.system.Array implements ArrayAccess -{ - public var Length(default, null):Int; - - public function new(len:Int):Void; - - @:overload(function(arr:cs.system.Array, destIndex:haxe.Int64):Void {} ) - public function CopyTo(arr:cs.system.Array, destIndex:Int):Void; - - static function Reverse(arr:cs.system.Array):Void; -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs; + +import haxe.extern.Rest; + +/** + Represents a C# fixed-size Array (`T[]`) +**/ +extern class NativeArray extends cs.system.Array implements ArrayAccess +{ + /** + Creates a new array with the specified elements. + + Usage: + ```haxe + var elements = NativeArray.make(1,2,3,4,5,6); + ``` + **/ + public static function make(elements:Rest):NativeArray; + + /** + Allocates a new array with size `len` + **/ + public function new(len:Int):Void; + + /** + Alias to array's `Length` property. Returns the size of the array + **/ + public var length(get,never):Int; + + @:extern inline private function get_length():Int return this.Length; + + static function Reverse(arr:cs.system.Array):Void; + + /** + Returns an iterator so it's possible to use `for` with C#'s `NativeArray` + **/ + @:extern inline public function iterator():NativeArrayIterator + return new NativeArrayIterator(this); +} + +@:dce private class NativeArrayIterator +{ + public var arr(default,null):NativeArray; + public var idx(default,null):UInt; + + inline public function new(arr) + { + this.arr = arr; + this.idx = 0; + } + + inline public function hasNext():Bool + return this.idx < this.arr.Length; + + inline public function next():T + { + return this.arr[this.idx++]; + } +} diff --git a/std/cs/Out.hx b/std/cs/Out.hx index a6205c05a8cea9ed46f13082fe2ba6347be539fd..df8c0d850365ca109705db4436da98c188f81761 100644 --- a/std/cs/Out.hx +++ b/std/cs/Out.hx @@ -1,30 +1,32 @@ -/* - * Copyright (C)2005-2012 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 cs; - -/** - This type represents "out" types for C# function parameters. - It only has effect on function parameters, and conversion to/from the referenced type is automatic. - - Note: Using this type should be considered a bad practice unless overriding a native function is needed. -**/ +/* + * Copyright (C)2005-2012 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 cs; + +/** + This type represents "out" types for C# function parameters. + It only has effect on function parameters, and conversion to/from the referenced type is automatic. + + Note: Using this type should be considered a bad practice unless overriding a native function is needed. +**/ +@:analyzer(no_simplification) +@:analyzer(no_local_dce) typedef Out = T; \ No newline at end of file diff --git a/std/cs/Pointer.hx b/std/cs/Pointer.hx index 5b8533cb5bd182ee56b5797679ffdb7fc2796875..16dc0474c7b6410a77bcd74acf53570d3db58cb5 100644 --- a/std/cs/Pointer.hx +++ b/std/cs/Pointer.hx @@ -1,53 +1,105 @@ -/* - * Copyright (C)2005-2012 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 cs; - -/** - This type represents pointer types for C# function parameters. It should only - be used inside an unsafe context (not checked by the Haxe compiler) - - C# code: - int[] src; - fixed (int* pSrc = src) - { - ... - } - Haxe code: - var pSrc:cs.Pointer; - cs.Lib.fixed(pSrc = cast src, - { - ... - }); - -**/ -#if !unsafe -#error "You need to define 'unsafe' to be able to use unsafe code in hxcs" -#else -extern class Pointer /*extends Int,*/ implements ArrayAccess -{ - static function op_Addition(p:Pointer, i:Int):Pointer; - public inline function add(i:Int):Pointer - { - return op_Addition(this,i); - } -} -#end +/* + * Copyright (C)2005-2012 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 cs; +import cs.StdTypes.Int64; + +/** + This type represents pointer types for C# function parameters. It should only + be used inside an unsafe context (not checked by the Haxe compiler) + + C# code: + int[] src; + fixed (int* pSrc = src) + { + ... + } + Haxe code: + var src:NativeArray; + cs.Lib.fixed({ + var pSrc:cs.Pointer = cs.Lib.pointerOfArray(src); + ... + }); + +**/ +#if !unsafe +#error "You need to define 'unsafe' to be able to use unsafe code in hxcs" +#else +@:runtimeValue @:coreType abstract Pointer from Int64 from PointerAccess to PointerAccess +{ + @:op(A+B) public static function addIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A+B) public static function addp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A*B) public static function mulIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A*B) public static function mulp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A%B) public static function modIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A%B) public static function modp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A-B) public static function subIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A-B) public static function subp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A/B) public static function divIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A/B) public static function divp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A|B) public static function orIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A|B) public static function orp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A^B) public static function xorIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A^B) public static function xorp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A&B) public static function andIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A&B) public static function andp(lhs:Pointer, rhs:Int64):Pointer; + @:op(A<(lhs:Pointer, rhs:Int):Pointer; + @:op(A<(lhs:Pointer, rhs:Int64):Pointer; + @:op(A>>B) public static function shrIp(lhs:Pointer, rhs:Int):Pointer; + @:op(A>>B) public static function shrp(lhs:Pointer, rhs:Int64):Pointer; + + @:op(A>B) public static function gtp(lhs:Pointer, rhs:Pointer):Bool; + @:op(A>=B) public static function gtep(lhs:Pointer, rhs:Pointer):Bool; + @:op(A(lhs:Pointer, rhs:Pointer):Bool; + @:op(A<=B) public static function ltep(lhs:Pointer, rhs:Pointer):Bool; + + @:op(~A) public static function bnegp(t:Pointer):Pointer; + @:op(A++) public static function prepp(t:Pointer):Pointer; + @:op(A--) public static function prenn(t:Pointer):Pointer; + @:op(++A) public static function postpp(t:Pointer):Pointer; + @:op(--A) public static function postnn(t:Pointer):Pointer; + + /** + Returns a `cs.PointerAccess` type, which in turn allows the underlying Pointer's + fields to be accessed. + **/ + // @:analyzer(no_simplification) + public var acc(get,never):PointerAccess; + + // @:analyzer(no_simplification) + @:extern inline private function get_acc():PointerAccess return (cast this : PointerAccess); + + // backwards compatibility + inline public function add(i:Int):Pointer + { + return this + i; + } + + @:arrayAccess public static function getIp(p:Pointer, at:Int):T; + @:arrayAccess public static function setIp(p:Pointer, at:Int, val:T):T; + @:arrayAccess public static function getp(p:Pointer, at:Int64):T; + @:arrayAccess public static function setp(p:Pointer, at:Int64, val:T):T; +} + +@:forward abstract PointerAccess(T) +{ +} +#end diff --git a/std/cs/Ref.hx b/std/cs/Ref.hx index d4c25dc1f19c480374fbeef74b295f6fd936eaf8..aeec15adeca1553f1ba0aa923684674bc6641434 100644 --- a/std/cs/Ref.hx +++ b/std/cs/Ref.hx @@ -1,30 +1,31 @@ -/* - * Copyright (C)2005-2012 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 cs; - -/** - This type represents "ref" types for C# function parameters. - It only has effect on function parameters, and conversion to/from the referenced type is automatic. - - Note: Using this type should be considered a bad practice unless overriding a native function is needed. -**/ +/* + * Copyright (C)2005-2012 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 cs; + +/** + This type represents "ref" types for C# function parameters. + It only has effect on function parameters, and conversion to/from the referenced type is automatic. + + Note: Using this type should be considered a bad practice unless overriding a native function is needed. +**/ +@:analyzer(no_simplification) typedef Ref = T; \ No newline at end of file diff --git a/std/cs/StdTypes.hx b/std/cs/StdTypes.hx index 5fd01192488f523e3768b4aab512dbeda0f53e2b..bcf746dbce4ac68527b824ed318c7df4dcd7f231 100644 --- a/std/cs/StdTypes.hx +++ b/std/cs/StdTypes.hx @@ -1,30 +1,100 @@ -/* - * Copyright (C)2005-2012 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 cs; - -typedef Int8 = Int; -typedef UInt8 = Int; -typedef Int16 = Int; -typedef UInt16 = Int; -//UInt is top-level -typedef UInt64 = haxe.Int64; -typedef Char16 = Int; \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs; + +@:notNull @:runtimeValue @:coreType abstract Int8 to Int {} +@:notNull @:runtimeValue @:coreType abstract Int16 to Int {} +@:notNull @:runtimeValue @:coreType abstract Char16 from Int {} +@:notNull @:runtimeValue @:coreType abstract UInt8 to Int from Int {} +@:notNull @:runtimeValue @:coreType abstract UInt16 to Int {} +@:notNull @:runtimeValue @:coreType abstract Int64 from Int from Float +{ + @:op(A+B) public static function addI(lhs:Int64, rhs:Int):Int64; + @:op(A+B) public static function add(lhs:Int64, rhs:Int64):Int64; + @:op(A*B) public static function mulI(lhs:Int64, rhs:Int):Int64; + @:op(A*B) public static function mul(lhs:Int64, rhs:Int64):Int64; + @:op(A%B) public static function modI(lhs:Int64, rhs:Int):Int64; + @:op(A%B) public static function mod(lhs:Int64, rhs:Int64):Int64; + @:op(A-B) public static function subI(lhs:Int64, rhs:Int):Int64; + @:op(A-B) public static function sub(lhs:Int64, rhs:Int64):Int64; + @:op(A/B) public static function divI(lhs:Int64, rhs:Int):Int64; + @:op(A/B) public static function div(lhs:Int64, rhs:Int64):Int64; + @:op(A|B) public static function orI(lhs:Int64, rhs:Int):Int64; + @:op(A|B) public static function or(lhs:Int64, rhs:Int64):Int64; + @:op(A^B) public static function xorI(lhs:Int64, rhs:Int):Int64; + @:op(A^B) public static function xor(lhs:Int64, rhs:Int64):Int64; + @:op(A&B) public static function andI(lhs:Int64, rhs:Int):Int64; + @:op(A&B) public static function and(lhs:Int64, rhs:Int64):Int64; + @:op(A<>B) public static function shrI(lhs:Int64, rhs:Int):Int64; + @:op(A>>B) public static function shr(lhs:Int64, rhs:Int64):Int64; + + @:op(A>B) public static function gt(lhs:Int64, rhs:Int64):Bool; + @:op(A>=B) public static function gte(lhs:Int64, rhs:Int64):Bool; + @:op(A>B) public static function shrI(lhs:UInt64, rhs:Int):UInt64; + @:op(A>>B) public static function shr(lhs:UInt64, rhs:UInt64):UInt64; + + @:op(A>B) public static function gt(lhs:UInt64, rhs:UInt64):Bool; + @:op(A>=B) public static function gte(lhs:UInt64, rhs:UInt64):Bool; + @:op(A implements ArrayAccess { +#if core_api_serialize +@:meta(System.Serializable) +#end +@:final class Array implements ArrayAccess { - /** - The length of the Array - **/ public var length(default,null) : Int; private var __a:NativeArray; - @:functionCode(' - return new Array(native); - ') - private static function ofNative(native:NativeArray):Array +#if erase_generics + inline private static function ofNative(native:NativeArray):Array + { + return new Array(native); + } +#else + inline private static function ofNative(native:NativeArray):Array { - return null; + return new Array(native); } +#end - @:functionCode(' - return new Array(new Y[size]); - ') - private static function alloc(size:Int):Array + inline private static function alloc(size:Int):Array { - return null; + return new Array(new NativeArray(size)); } - /** - Creates a new Array. - **/ - public function new() : Void + @:overload public function new() : Void { this.length = 0; this.__a = new NativeArray(0); } - /** - Returns a new Array by appending [a] to [this]. - **/ +#if erase_generics + @:overload private function new(native:NativeArray) + { + this.length = native.Length; + this.__a = untyped native; + } +#else + @:overload private function new(native:NativeArray) + { + this.length = native.Length; + this.__a = native; + } +#end + public function concat( a : Array ) : Array { var len = length + a.length; @@ -98,9 +95,36 @@ import cs.NativeArray; this.length = len; } - /** - Returns a representation of an array with [sep] for separating each element. - **/ + public function indexOf( x : T, ?fromIndex:Int ) : Int + { + var len = length, i:Int = (fromIndex == null) ? 0 : fromIndex; + if (i < 0) + { + i += len; + if (i < 0) i = 0; + } + else if (i >= len) + { + return -1; + } + return cs.system.Array.IndexOf(__a, x, i, len - i); + } + + public function lastIndexOf( x : T, ?fromIndex:Int ) : Int + { + var len = length, i:Int = (fromIndex == null) ? len - 1 : fromIndex; + if (i >= len) + { + i = len - 1; + } + else if (i < 0) + { + i += len; + if (i < 0) return -1; + } + return cs.system.Array.LastIndexOf(__a, x, i, i + 1); + } + public function join( sep : String ) : String { var buf = new StringBuf(); @@ -120,9 +144,6 @@ import cs.NativeArray; return buf.toString(); } - /** - Removes the last element of the array and returns it. - **/ public function pop() : Null { var __a = __a; @@ -139,9 +160,6 @@ import cs.NativeArray; } } - /** - Adds the element [x] at the end of the array. - **/ public function push(x : T) : Int { if (length >= __a.Length) @@ -157,9 +175,6 @@ import cs.NativeArray; return ++length; } - /** - Reverse the order of elements of the Array. - **/ public function reverse() : Void { var i = 0; @@ -176,9 +191,6 @@ import cs.NativeArray; } } - /** - Removes the first element and returns it. - **/ public function shift() : Null { var l = this.length; @@ -195,12 +207,6 @@ import cs.NativeArray; return x; } - /** - Copies the range of the array starting at [pos] up to, - but not including, [end]. Both [pos] and [end] can be - negative to count from the end: -1 is the last item in - the array. - **/ public function slice( pos : Int, ?end : Int ) : Array { if( pos < 0 ){ @@ -223,11 +229,6 @@ import cs.NativeArray; return ofNative(newarr); } - /** - Sort the Array according to the comparison public function [f]. - [f(x,y)] should return [0] if [x == y], [>0] if [x > y] - and [<0] if [x < y]. - **/ public function sort( f : T -> T -> Int ) : Void { if (length == 0) @@ -235,34 +236,27 @@ import cs.NativeArray; quicksort(0, length - 1, f); } - /** - quicksort author: tong disktree - http://blog.disktree.net/2008/10/26/array-sort-performance.html - */ private function quicksort( lo : Int, hi : Int, f : T -> T -> Int ) : Void { - var buf = __a; + var buf = __a; var i = lo, j = hi; - var p = buf[(i + j) >> 1]; + var p = buf[(i + j) >> 1]; while ( i <= j ) { - while ( f(buf[i], p) < 0 ) i++; - while ( f(buf[j], p) > 0 ) j--; + while ( i < hi && f(buf[i], p) < 0 ) i++; + while ( j > lo && f(buf[j], p) > 0 ) j--; if ( i <= j ) { - var t = buf[i]; - buf[i++] = buf[j]; - buf[j--] = t; - } + var t = buf[i]; + buf[i++] = buf[j]; + buf[j--] = t; + } } if( lo < j ) quicksort( lo, j, f ); - if( i < hi ) quicksort( i, hi, f ); + if( i < hi ) quicksort( i, hi, f ); } - /** - Removes [len] elements starting from [pos] an returns them. - **/ public function splice( pos : Int, len : Int ) : Array { if( len < 0 ) return new Array(); @@ -314,9 +308,6 @@ import cs.NativeArray; a[this.length + len] = null; } - /** - Returns a displayable representation of the Array content. - **/ public function toString() : String { var ret = new StringBuf(); @@ -336,9 +327,6 @@ import cs.NativeArray; return ret.toString(); } - /** - Adds the element [x] at the start of the array. - **/ public function unshift( x : T ) : Void { var __a = __a; @@ -358,10 +346,6 @@ import cs.NativeArray; ++this.length; } - /** - Inserts the element [x] at the position [pos]. - All elements after [pos] are moved one index ahead. - **/ public function insert( pos : Int, x : T ) : Void { var l = this.length; @@ -396,11 +380,6 @@ import cs.NativeArray; } } - /** - Removes the first occurence of [x]. - Returns false if [x] was not present. - Elements are compared by using standard equality. - **/ public function remove( x : T ) : Bool { var __a = __a; @@ -435,10 +414,6 @@ import cs.NativeArray; return ret; } - /** - Returns a copy of the Array. The values are not - copied, only the Array structure. - **/ public function copy() : Array { var len = length; @@ -448,28 +423,14 @@ import cs.NativeArray; return ofNative(newarr); } - /** - Returns an iterator of the Array values. - **/ - public function iterator() : Iterator + public inline function iterator() : Iterator { - var i = 0; - var len = length; - return - { - hasNext:function() return i < len, - next:function() return __a[i++] - }; + return new ArrayIterator(this); } private function __get(idx:Int):T { - var __a = __a; - var idx:UInt = idx; - if (idx >= length) - return null; - - return __a[idx]; + return if ((cast idx : UInt) >= length) null else __a[idx]; } private function __set(idx:Int, v:T):T @@ -502,3 +463,21 @@ import cs.NativeArray; return __a[idx] = val; } } + +@:final +private 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/Date.hx b/std/cs/_std/Date.hx index 2c23ea4223aa4760849010a3a69f00c2dd11b5a9..afe45e877a68674c3664886c355c88f1fdb6e910 100644 --- a/std/cs/_std/Date.hx +++ b/std/cs/_std/Date.hx @@ -1,180 +1,137 @@ -/* - * Copyright (C)2005-2012 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; -import cs.system.DateTime; -import haxe.Int64; - -@:coreApi class Date -{ - private var date:DateTime; - - /** - Creates a new date object. - **/ - public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void - { - if (day <= 0) day = 1; - if (year <= 0) year = 1; - date = new DateTime(year, month + 1, day, hour, min, sec); - } - - /** - Returns the timestamp of the date. It's the number of milliseconds - elapsed since 1st January 1970. It might only have a per-second precision - depending on the platforms. - **/ - public inline function getTime() : Float - { - return (cast(date.Ticks, Float) / TimeSpan.TicksPerMillisecond); - } - - /** - Returns the hours value of the date (0-23 range). - **/ - public inline function getHours() : Int - { - return date.Hour; - } - - /** - Returns the minutes value of the date (0-59 range). - **/ - public inline function getMinutes() : Int - { - return date.Minute; - } - - /** - Returns the seconds of the date (0-59 range). - **/ - public inline function getSeconds() : Int - { - return date.Second; - } - - /** - Returns the full year of the date. - **/ - public inline function getFullYear() : Int - { - return date.Year; - } - - /** - Returns the month of the date (0-11 range). - **/ - public inline function getMonth() : Int - { - return date.Month - 1; - } - - /** - Returns the day of the date (1-31 range). - **/ - public inline function getDate() : Int - { - return date.Day; - } - - /** - Returns the week day of the date (0-6 range). - **/ - public inline function getDay() : Int - { - return cast(date.DayOfWeek, Int); - } - - /** - Returns a string representation for the Date, by using the - standard format [YYYY-MM-DD HH:MM:SS]. See [DateTools.format] for - other formating rules. - **/ - public function toString():String - { - var m = getMonth() + 1; - var d = getDate(); - var h = getHours(); - var mi = getMinutes(); - var s = getSeconds(); - return (getFullYear()) - +"-"+(if( m < 10 ) "0"+m else ""+m) - +"-"+(if( d < 10 ) "0"+d else ""+d) - +" "+(if( h < 10 ) "0"+h else ""+h) - +":"+(if( mi < 10 ) "0"+mi else ""+mi) - +":"+(if( s < 10 ) "0"+s else ""+s); - } - - /** - Returns a Date representing the current local time. - **/ - static public function now() : Date - { - var d = new Date(0, 0, 0, 0, 0, 0); - d.date = DateTime.Now; - return d; - } - - /** - Returns a Date from a timestamp [t] which is the number of - milliseconds elapsed since 1st January 1970. - **/ - static public function fromTime( t : Float ) : Date - { - var d = new Date(0, 0, 0, 0, 0, 0); - d.date = new DateTime(cast(t * TimeSpan.TicksPerMillisecond, Int64)); - return d; - } - - - /** - Returns a Date from a formated string of one of the following formats : - [YYYY-MM-DD hh:mm:ss] or [YYYY-MM-DD] or [hh:mm:ss]. The first two formats - are expressed in local time, the third in UTC Epoch. - **/ - static public function fromString( s : String ) : Date - { - switch( s.length ) - { - case 8: // hh:mm:ss - var k = s.split(":"); - var d : Date = new Date(1, 1, 1, Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2])); - return d; - case 10: // YYYY-MM-DD - var k = s.split("-"); - return new Date(Std.parseInt(k[0]),Std.parseInt(k[1]) - 1,Std.parseInt(k[2]),0,0,0); - case 19: // YYYY-MM-DD hh:mm:ss - var k = s.split(" "); - var y = k[0].split("-"); - var t = k[1].split(":"); - return new Date(Std.parseInt(y[0]),Std.parseInt(y[1]) - 1,Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2])); - default: - throw "Invalid date format : " + s; - } - } - - private static function fromNative( d : cs.system.DateTime ) : Date - { - var date = new Date(0, 0, 0, 0, 0, 0); - date.date = d; - return date; - } -} +/* + * Copyright (C)2005-2012 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; +import cs.system.DateTime; +import cs.system.TimeSpan; +import haxe.Int64; + +#if core_api_serialize +@:meta(System.Serializable) +#end +@:coreApi class Date +{ + private var date:DateTime; + + public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void + { + if (day <= 0) day = 1; + if (year <= 0) year = 1; + date = new DateTime(year, month + 1, day, hour, min, sec); + } + + public inline function getTime() : Float + { + return (cast(date.Ticks, Float) / cast(TimeSpan.TicksPerMillisecond, Float)); + } + + public inline function getHours() : Int + { + return date.Hour; + } + + public inline function getMinutes() : Int + { + return date.Minute; + } + + public inline function getSeconds() : Int + { + return date.Second; + } + + public inline function getFullYear() : Int + { + return date.Year; + } + + public inline function getMonth() : Int + { + return date.Month - 1; + } + + public inline function getDate() : Int + { + return date.Day; + } + + public inline function getDay() : Int + { + return cast(date.DayOfWeek, Int); + } + + public function toString():String + { + var m = getMonth() + 1; + var d = getDate(); + var h = getHours(); + var mi = getMinutes(); + var s = getSeconds(); + return (getFullYear()) + +"-"+(if( m < 10 ) "0"+m else ""+m) + +"-"+(if( d < 10 ) "0"+d else ""+d) + +" "+(if( h < 10 ) "0"+h else ""+h) + +":"+(if( mi < 10 ) "0"+mi else ""+mi) + +":"+(if( s < 10 ) "0"+s else ""+s); + } + + static public function now() : Date + { + var d = new Date(0, 0, 0, 0, 0, 0); + d.date = DateTime.Now; + return d; + } + + static public function fromTime( t : Float ) : Date + { + var d = new Date(0, 0, 0, 0, 0, 0); + d.date = new DateTime(cast(t * cast(TimeSpan.TicksPerMillisecond, Float), Int64)); + return d; + } + + static public function fromString( s : String ) : Date + { + switch( s.length ) + { + case 8: // hh:mm:ss + var k = s.split(":"); + var d : Date = new Date(1, 1, 1, Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2])); + return d; + case 10: // YYYY-MM-DD + var k = s.split("-"); + return new Date(Std.parseInt(k[0]),Std.parseInt(k[1]) - 1,Std.parseInt(k[2]),0,0,0); + case 19: // YYYY-MM-DD hh:mm:ss + var k = s.split(" "); + var y = k[0].split("-"); + var t = k[1].split(":"); + return new Date(Std.parseInt(y[0]),Std.parseInt(y[1]) - 1,Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2])); + default: + throw "Invalid date format : " + s; + } + } + + private static function fromNative( d : cs.system.DateTime ) : Date + { + var date = new Date(0, 0, 0, 0, 0, 0); + date.date = d; + return date; + } +} diff --git a/std/cs/_std/EReg.hx b/std/cs/_std/EReg.hx index bffd9b4455f62ca92cba449748cf73446d6378bd..262407a42f06b17d236ca8b88c9daa847b6e994c 100644 --- a/std/cs/_std/EReg.hx +++ b/std/cs/_std/EReg.hx @@ -19,9 +19,12 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -import cs.system.text.regularExpressions.Regex; +import cs.system.text.regularexpressions.Regex; +import cs.system.text.regularexpressions.Match; +import cs.system.text.regularexpressions.RegexOptions; +import cs.system.text.regularexpressions.*; -class EReg { +@:coreApi @:final class EReg { private var regex : Regex; private var m : Match; @@ -39,8 +42,10 @@ class EReg { isGlobal = true; case 'm'.code: opts |= cast(Multiline, Int); +#if (!unity && !unity_std_target) case 'c'.code: opts |= cast(Compiled, Int); +#end } } @@ -86,12 +91,12 @@ class EReg { return untyped [s.Substring(0, m.Index), s.Substring(m.Index + m.Length)]; } - inline function start(group:Int) + inline function start(group:Int) : Int { return m.Groups[group].Index; } - inline function len(group:Int) + inline function len(group:Int) : Int { return m.Groups[group].Length; } diff --git a/std/cs/_std/FieldLookup.hx b/std/cs/_std/FieldLookup.hx deleted file mode 100644 index ceed065a8e1513368bb670d94d72a9513eb6c50d..0000000000000000000000000000000000000000 --- a/std/cs/_std/FieldLookup.hx +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -@:native('haxe.lang.FieldLookup') -@:static private class FieldLookup -{ - - @:private private static var fieldIds:Array; - @:private private static var fields:Array; - - //s cannot be null here - private static inline function doHash(s:String):Int - { - var acc = 0; //alloc_int - for (i in 0...s.length) - { - acc = (( 223 * (acc >> 1) + s.charCodeAt(i) ) << 1); - } - - return acc >>> 1; //always positive - } - - public static function lookupHash(key:Int):String - { - //start of binary search algorithm - var ids = fieldIds; - var min = 0; - var max = ids.length; - - while (min < max) - { - var mid = Std.int(min + (max - min) / 2); //overflow safe - var imid = ids[mid]; - if (key < imid) - { - max = mid; - } else if (key > imid) { - min = mid + 1; - } else { - return fields[mid]; - } - } - //if not found, it's definately an error - throw "Field not found for hash " + key; - } - - public static function hash(s:String):Int - { - if (s == null) return 0; - - var key = doHash(s); - - //start of binary search algorithm - var ids = fieldIds; - var min = 0; - var max = ids.length; - - while (min < max) - { - var mid = Std.int(min + (max - min) / 2); //overflow safe - var imid = ids[mid]; - if (key < imid) - { - max = mid; - } else if (key > imid) { - min = mid + 1; - } else { - var field = fields[mid]; - if (field != s) - return -(key + 1); //special case - return key; - } - } - //if not found, min holds the value where we should insert the key - ids.insert(min, key); - fields.insert(min, s); - return key; - } - - public static function findHash(hash:Int, hashs:Array):Int - { - var min = 0; - var max = hashs.length; - - while (min < max) - { - var mid = Std.int((max + min) / 2); //overflow safe - var imid = hashs[mid]; - if (hash < imid) - { - max = mid; - } else if (hash > imid) { - min = mid + 1; - } else { - return min; - } - } - //if not found, return a negative value of where it should be inserted - return ~min; - } - -} \ No newline at end of file diff --git a/std/cs/_std/Math.hx b/std/cs/_std/Math.hx index c76a32570765da86f5629a1566fec774fee38b18..b06b4d11bc3fa41a9ba98fdbcdaf3ce6bc009b35 100644 --- a/std/cs/_std/Math.hx +++ b/std/cs/_std/Math.hx @@ -1,165 +1,158 @@ -/* - * Copyright (C)2005-2012 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; -import cs.system.Random; - -@:coreApi @:nativeGen class Math -{ - public static inline function __init__():Void - { - PI = cs.system.Math.PI; - NaN = untyped __cs__("double.NaN"); - NEGATIVE_INFINITY = untyped __cs__("double.NegativeInfinity"); - POSITIVE_INFINITY = untyped __cs__("double.PositiveInfinity"); - rand = new Random(); - - } - - private static var rand:Random; - public static var PI(default, null) : Float; - public static var NaN(default,null) : Float; - public static var NEGATIVE_INFINITY(default,null) : Float; - public static var POSITIVE_INFINITY(default,null) : Float; - - public static inline function abs(v:Float):Float - { - return cs.system.Math.Abs(v); - } - - public static inline function min(a:Float, b:Float):Float - { - return cs.system.Math.Min(a,b); - } - - public static inline function max(a:Float, b:Float):Float - { - return cs.system.Math.Max(a,b); - } - - public static inline function sin(v:Float):Float - { - return cs.system.Math.Sin(v); - } - - public static inline function cos(v:Float):Float - { - return cs.system.Math.Cos(v); - } - - public static inline function atan2(y:Float, x:Float):Float - { - return cs.system.Math.Atan2(y, x); - } - - public static inline function tan(v:Float):Float - { - return cs.system.Math.Tan(v); - } - - public static inline function exp(v:Float):Float - { - return cs.system.Math.Exp(v); - } - - public static inline function log(v:Float):Float - { - return cs.system.Math.Log(v); - } - - public static inline function sqrt(v:Float):Float - { - return cs.system.Math.Sqrt(v); - } - - public static inline function fround(v:Float):Float - { - return cs.system.Math.Round(v); - } - - public static inline function ffloor(v:Float):Float - { - return cs.system.Math.Floor(v); - } - - public static inline function fceil(v:Float):Float - { - return cs.system.Math.Ceiling(v); - } - - public static function round(v:Float):Int - { - var vint = Std.int(v); - var dec = v - vint; - if (dec >= 1 || dec <= -1) - return vint; //overflow - if (dec >= .5) - return vint + 1; - if (dec < -.5) - return vint - 1; - return vint; - } - - public static inline function floor(v:Float):Int - { - return Std.int(cs.system.Math.Floor(v)); - } - - public static inline function ceil(v:Float):Int - { - return Std.int(cs.system.Math.Ceiling(v)); - } - - public static inline function atan(v:Float):Float - { - return cs.system.Math.Atan(v); - } - - public static inline function asin(v:Float):Float - { - return cs.system.Math.Asin(v); - } - - public static inline function acos(v:Float):Float - { - return cs.system.Math.Acos(v); - } - - public static inline function pow(v:Float, exp:Float):Float - { - return cs.system.Math.Pow(v, exp); - } - - public static inline function random() : Float - { - return rand.NextDouble(); - } - - public static function isFinite( f : Float ) : Bool - { - return untyped __cs__("!double.IsInfinity(f) && !double.IsNaN(f)"); - } - - public static function isNaN( f : Float ) : Bool - { - return untyped __cs__("double.IsNaN(f)"); - } -} +/* + * Copyright (C)2005-2012 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 @:nativeGen class Math +{ + @:readOnly + private static var rand = new cs.system.Random(); + + @:readOnly + public static var PI(default,null) = cs.system.Math.PI; + @:readOnly + public static var NaN(default,null) = cs.system.Double.NaN; + @:readOnly + public static var NEGATIVE_INFINITY(default,null) = cs.system.Double.NegativeInfinity; + @:readOnly + public static var POSITIVE_INFINITY(default,null) = cs.system.Double.PositiveInfinity; + + public static inline function abs(v:Float):Float + { + return cs.system.Math.Abs(v); + } + + public static inline function min(a:Float, b:Float):Float + { + return cs.system.Math.Min(a,b); + } + + public static inline function max(a:Float, b:Float):Float + { + return cs.system.Math.Max(a,b); + } + + public static inline function sin(v:Float):Float + { + return cs.system.Math.Sin(v); + } + + public static inline function cos(v:Float):Float + { + return cs.system.Math.Cos(v); + } + + public static inline function atan2(y:Float, x:Float):Float + { + return cs.system.Math.Atan2(y, x); + } + + public static inline function tan(v:Float):Float + { + return cs.system.Math.Tan(v); + } + + public static inline function exp(v:Float):Float + { + return cs.system.Math.Exp(v); + } + + public static inline function log(v:Float):Float + { + return cs.system.Math.Log(v); + } + + public static inline function sqrt(v:Float):Float + { + return cs.system.Math.Sqrt(v); + } + + public static inline function fround(v:Float):Float + { + return cs.system.Math.Floor(v + 0.5); + } + + public static inline function ffloor(v:Float):Float + { + return cs.system.Math.Floor(v); + } + + public static inline function fceil(v:Float):Float + { + return cs.system.Math.Ceiling(v); + } + + public static function round(v:Float):Int + { + var vint = Std.int(v); + var dec = v - vint; + if (dec >= 1 || dec <= -1) + return vint; //overflow + if (dec >= .5) + return vint + 1; + if (dec < -.5) + return vint - 1; + return vint; + } + + public static inline function floor(v:Float):Int + { + return Std.int(cs.system.Math.Floor(v)); + } + + public static inline function ceil(v:Float):Int + { + return Std.int(cs.system.Math.Ceiling(v)); + } + + public static inline function atan(v:Float):Float + { + return cs.system.Math.Atan(v); + } + + public static inline function asin(v:Float):Float + { + return cs.system.Math.Asin(v); + } + + public static inline function acos(v:Float):Float + { + return cs.system.Math.Acos(v); + } + + public static inline function pow(v:Float, exp:Float):Float + { + return cs.system.Math.Pow(v, exp); + } + + public static inline function random() : Float + { + return rand.NextDouble(); + } + + public static inline function isFinite( f : Float ) : Bool + { + return !cs.system.Double.IsInfinity(f) && !cs.system.Double.IsNaN(f); + } + + public static inline function isNaN( f : Float ) : Bool + { + return cs.system.Double.IsNaN(f); + } +} diff --git a/std/cs/_std/Reflect.hx b/std/cs/_std/Reflect.hx index 782b4f0d65382573b0f4a5dc0df5066afbc5ceae..b4b2164aafe421b591d0ed97105769998aa69a15 100644 --- a/std/cs/_std/Reflect.hx +++ b/std/cs/_std/Reflect.hx @@ -1,259 +1,173 @@ -/* - * Copyright (C)2005-2012 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. - */ -import cs.internal.Function; -/* - * Copyright (c) 2005, The haXe Project Contributors - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/** - The Reflect API is a way to manipulate values dynamicly through an - abstract interface in an untyped manner. Use with care. -**/ -@:keep @:coreApi class Reflect { - - /** - Tells if an object has a field set. This doesn't take into account the object prototype (class methods). - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, haxe.lang.FieldLookup.hash(field), false, true, false) != haxe.lang.Runtime.undefined; - - return haxe.lang.Runtime.slowHasField(o, field); - ') - public static function hasField( o : Dynamic, field : String ) : Bool - { - return false; - } - - /** - Returns the field of an object, or null if [o] is not an object or doesn't have this field. - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, haxe.lang.FieldLookup.hash(field), false, false, false); - - return haxe.lang.Runtime.slowGetField(o, field, false); - ') - public static function field( o : Dynamic, field : String ) : Dynamic - { - return null; - } - - - /** - Set an object field value. - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - ((haxe.lang.IHxObject) o).__hx_setField(field, haxe.lang.FieldLookup.hash(field), value, false); - else - haxe.lang.Runtime.slowSetField(o, field, value); - ') - public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void - { - - } - - /** - Similar to field but also supports property (might be slower). - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, haxe.lang.FieldLookup.hash(field), false, false, true); - - if (haxe.lang.Runtime.slowHasField(o, "get_" + field)) - return haxe.lang.Runtime.slowCallField(o, "get_" + field, null); - - return haxe.lang.Runtime.slowGetField(o, field, false); - ') - public static function getProperty( o : Dynamic, field : String ) : Dynamic - { - return null; - } - - /** - Similar to setField but also supports property (might be slower). - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - ((haxe.lang.IHxObject) o).__hx_setField(field, haxe.lang.FieldLookup.hash(field), value, true); - else if (haxe.lang.Runtime.slowHasField(o, "set_" + field)) - haxe.lang.Runtime.slowCallField(o, "set_" + field, new Array(new object[]{value})); - else - haxe.lang.Runtime.slowSetField(o, field, value); - ') - public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void - { - - } - - /** - Call a method with the given object and arguments. - **/ - @:functionCode(' - return ((haxe.lang.Function) func).__hx_invokeDynamic(args); - ') - public static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic - { - return null; - } - - /** - Returns the list of fields of an object, excluding its prototype (class methods). - **/ - @:functionCode(' - if (o is haxe.lang.IHxObject) - { - Array ret = new Array(); - ((haxe.lang.IHxObject) o).__hx_getFields(ret); - return ret; - } else if (o is System.Type) { - return Type.getClassFields( (System.Type) o); - } else { - return new Array(); - } - ') - public static function fields( o : Dynamic ) : Array - { - return null; - } - - /** - Tells if a value is a function or not. - **/ - @:functionCode(' - return f is haxe.lang.Function; - ') - public static function isFunction( f : Dynamic ) : Bool - { - return false; - } - - /** - Generic comparison function, does not work for methods, see [compareMethods] - **/ - @:functionCode(' - return haxe.lang.Runtime.compare(a, b); - ') - public static function compare( a : T, b : T ) : Int - { - return 0; - } - - /** - Compare two methods closures. Returns true if it's the same method of the same instance. - **/ - @:functionCode(' - if (f1 == f2) - return true; - - if (f1 is haxe.lang.Closure && f2 is haxe.lang.Closure) - { - haxe.lang.Closure f1c = (haxe.lang.Closure) f1; - haxe.lang.Closure f2c = (haxe.lang.Closure) f2; - - return haxe.lang.Runtime.refEq(f1c.obj, f2c.obj) && f1c.field.Equals(f2c.field); - } - - return false; - ') - public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool - { - return false; - } - - /** - Tells if a value is an object or not. - - **/ - @:functionCode(' - return v != null && !(v is haxe.lang.Enum || v is haxe.lang.Function || v is System.ValueType); - ') - public static function isObject( v : Dynamic ) : Bool - { - return false; - } - - @:functionCode(' - return v != null && (v is haxe.lang.Enum || v is System.Enum); - ') - public static function isEnumValue( v : Dynamic ) : Bool { - return switch(Type.typeof(v)) { - case TEnum(_): true; - case _: false; - } - } - - /** - Delete an object field. - **/ - @:functionCode(' - return (o is haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(field, haxe.lang.FieldLookup.hash(field))); - ') - public static function deleteField( o : Dynamic, field : String ) : Bool - { - return false; - } - - /** - Make a copy of the fields of an object. - **/ - public static function copy( o : T ) : T - { - var o2 : Dynamic = {}; - for( f in Reflect.fields(o) ) - Reflect.setField(o2,f,Reflect.field(o,f)); - return cast o2; - } - - /** - 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 - { - return new VarArgsFunction(f); - } - -} +/* + * Copyright (C)2005-2015 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. + */ +import cs.internal.Function; +import cs.system.reflection.*; + +import cs.internal.*; +import cs.internal.HxObject; +import cs.internal.Runtime; +import cs.Flags; +import cs.Lib; +import cs.system.Object; +import cs.system.reflection.*; + +@:keep @:coreApi class Reflect { + + public static function hasField( o : Dynamic, field : String ) : Bool + { + var ihx:IHxObject = Lib.as(o,IHxObject); + if (ihx != null) return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, true, false) != Runtime.undefined; + + return Runtime.slowHasField(o,field); + } + + public static function field( o : Dynamic, field : String ) : Dynamic + { + var ihx:IHxObject = Lib.as(o,IHxObject); + if (ihx != null) return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, false, false); + + return Runtime.slowGetField(o,field,false); + } + + public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void + { + var ihx:IHxObject = Lib.as(o,IHxObject); + if (ihx != null) + untyped ihx.__hx_setField(field, FieldLookup.hash(field), value, false); + else + Runtime.slowSetField(o,field,value); + } + + public static function getProperty( o : Dynamic, field : String ) : Dynamic + { + var ihx:IHxObject = Lib.as(o,IHxObject); + if (ihx != null) return untyped ihx.__hx_getField(field, FieldLookup.hash(field), false, false, true); + + if (Runtime.slowHasField(o, "get_" + field)) + return Runtime.slowCallField(o, "get_" + field, null); + + return Runtime.slowGetField(o, field, false); + } + + public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void + { + var ihx:IHxObject = Lib.as(o,IHxObject); + if (ihx != null) + untyped ihx.__hx_setField(field, FieldLookup.hash(field), value, true); + else if (Runtime.slowHasField(o, 'set_$field')) + Runtime.slowCallField(o, 'set_$field', [value]); + else + Runtime.slowSetField(o,field,value); + } + + public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic + { + return untyped cast(func, Function).__hx_invokeDynamic(args); + } + + public static function fields( o : Dynamic ) : Array + { + var ihx = Lib.as(o,IHxObject); + if (o != null) + { + var ret = []; + untyped ihx.__hx_getFields(ret); + return ret; + } else if (Std.is(o, cs.system.Type)) { + return Type.getClassFields(o); + } else { + return instanceFields( untyped o.GetType() ); + } + } + + private static function instanceFields( c : Class ) : Array + { + var c = cs.Lib.toNativeType(c); + var ret = []; + var mis = c.GetFields(new cs.Flags(BindingFlags.Public) | BindingFlags.Instance | BindingFlags.FlattenHierarchy); + for (i in 0...mis.Length) + { + var i = mis[i]; + ret.push(i.Name); + } + return ret; + } + + inline public static function isFunction( f : Dynamic ) : Bool + { + return Std.is(f, Function); + } + + public static function compare( a : T, b : T ) : Int + { + return cs.internal.Runtime.compare(a, b); + } + + @:access(cs.internal.Closure) + public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool + { + if (f1 == f2) + return true; + + if (Std.is(f1, Closure) && Std.is(f2, Closure)) + { + var f1c:Closure = cast f1; + var f2c:Closure = cast f2; + + return Runtime.refEq(f1c.obj, f2c.obj) && f1c.field == f2c.field; + } + + return false; + } + + public static function isObject( v : Dynamic ) : Bool + { + return v != null && !(Std.is(v, HxEnum) || Std.is(v, Function) || Std.is(v, cs.system.ValueType)); + } + + public static function isEnumValue( v : Dynamic ) : Bool { + return v != null && (Std.is(v, HxEnum) || Std.is(v, cs.system.Enum)); + } + + public static function deleteField( o : Dynamic, field : String ) : Bool + { + var ihx = Lib.as(o,DynamicObject); + if (ihx != null) + return untyped ihx.__hx_deleteField(field, FieldLookup.hash(field)); + return false; + } + + public static function copy( o : T ) : T + { + var o2 : Dynamic = {}; + for( f in Reflect.fields(o) ) + Reflect.setField(o2,f,Reflect.field(o,f)); + return cast o2; + } + + @:overload(function( f : Array -> Void ) : Dynamic {}) + public static function makeVarArgs( f : Array -> Dynamic ) : Dynamic + { + return new VarArgsFunction(f); + } + +} diff --git a/std/cs/_std/Std.hx b/std/cs/_std/Std.hx index 496069f31d7c58d6bf981d94701a18defd0e9804..d67b0f806f95b03439df742ed2f45533c574956e 100644 --- a/std/cs/_std/Std.hx +++ b/std/cs/_std/Std.hx @@ -30,7 +30,7 @@ import cs.internal.Exceptions; return t == Dynamic; if (t == null) return false; - var clt:Class = cast t; + var clt:cs.system.Type = cast t; if (clt == null) return false; var name:String = cast clt; @@ -47,9 +47,7 @@ import cs.internal.Exceptions; return true; } - var clv:Class = untyped __cs__('v.GetType()'); - - return untyped clt.IsAssignableFrom(clv); + return clt.IsAssignableFrom(cs.Lib.getNativeType(v)); } public static function string( s : Dynamic ) : String { @@ -83,7 +81,7 @@ import cs.internal.Exceptions; } } - var foundAny = false; + var foundAny = i != -1; var isNeg = false; while (++i < len) { @@ -95,7 +93,7 @@ import cs.internal.Exceptions; case '-'.code: isNeg = true; continue; - case ' '.code, '\t'.code, '\n'.code, '\r'.code: + case ' '.code, '\t'.code, '\n'.code, '\r'.code, '+'.code: if (isNeg) return null; continue; @@ -136,102 +134,52 @@ import cs.internal.Exceptions; public static function parseFloat( x : String ) : Float { if (x == null) return Math.NaN; x = StringTools.ltrim(x); - - var ret = 0.0; - var div = 0.0; - var e = 0.0; - - var len = x.length; - var foundAny = false; - var isNeg = false; + var found = false, hasDot = false, hasSign = false, + hasE = false, hasESign = false, hasEData = false; var i = -1; - while (++i < len) + inline function getch(i:Int):Int return cast ((untyped x : cs.system.String)[i]); + + while (++i < x.length) { - var c = cast(untyped x[i], Int); //fastCodeAt - if (!foundAny) + var chr = getch(i); + if (chr >= '0'.code && chr <= '9'.code) { - switch(c) + if (hasE) { - case '-'.code: - isNeg = true; - continue; - case ' '.code, '\t'.code, '\n'.code, '\r'.code: - if (isNeg) - return Math.NaN; - continue; + hasEData = true; } - } - - if (c == '.'.code) - { - if (div != 0.0) + 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; - div = 1.0; - - continue; - } - - if (c >= '0'.code && c <= '9'.code) - { - if (!foundAny && c == '0'.code) - { - foundAny = true; - continue; - } - - ret *= 10; foundAny = true; div *= 10; - - ret += c - '0'.code; - } else if (foundAny && (c == 'e'.code || c == 'E'.code)) { - var eNeg = false; - var eFoundAny = false; - if (i + 1 < len) - { - var next = untyped cast(x[i + 1], Int); - if (next == '-'.code) - { - eNeg = true; - i++; - } else if (next == '+'.code) { - i++; - } - } - - while (++i < len) - { - c = untyped cast(x[i], Int); - if (c >= '0'.code && c <= '9'.code) - { - if (!eFoundAny && c == '0'.code) - continue; - eFoundAny = true; - e *= 10; - e += c - '0'.code; - } else { - break; - } - } - - if (eNeg) e = -e; - } else { - break; } } - - if (div == 0.0) div = 1.0; - - if (foundAny) + if (hasE && !hasEData) { - ret = isNeg ? -(ret / div) : (ret / div); - if (e != 0.0) - { - return ret * Math.pow(10.0, e); - } else { - return ret; - } - } else { - return Math.NaN; + i--; + if (hasESign) + i--; + } + if (i != x.length) + { + x = x.substr(0,i); } + return try + cs.system.Double.Parse(x, (null : cs.system.IFormatProvider)) + catch(e:Dynamic) + Math.NaN; + } + + @:extern inline public static function instance( value : T, c : Class ) : S { + return cs.Lib.as(value,c); } public static function random( x : Int ) : Int { diff --git a/std/cs/_std/String.hx b/std/cs/_std/String.hx index 1b1e4dbb1d2d06af39d252b174be486956168ee1..7c7d984f3b79ecce261318c64713e3a1893f031d 100644 --- a/std/cs/_std/String.hx +++ b/std/cs/_std/String.hx @@ -1,64 +1,66 @@ -/* - * Copyright (C)2005-2012 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. - */ -import cs.StdTypes; - -@:coreType extern class String implements ArrayAccess { - - private static function Compare(s1:String, s2:String):Int; - - var length(default,null) : Int; - - function new(string:String) : Void; - - function toUpperCase() : String; - - function toLowerCase() : String; - - function charAt( index : Int) : String; - - function charCodeAt( index : Int) : Null; - - function indexOf( str : String, ?startIndex : Int ) : Int; - - function lastIndexOf( str : String, ?startIndex : Int ) : Int; - - function split( delimiter : String ) : Array; - - function substr( pos : Int, ?len : Int ) : String; - - function substring( startIndex : Int, ?endIndex : Int ) : String; - - function toString() : String; - - static function fromCharCode( code : Int ) : String; - - private function Replace(oldValue:String, newValue:String):String; - private function StartsWith(value:String):Bool; - private function EndsWith(value:String):Bool; - private function TrimStart():String; - private function TrimEnd():String; - private function Trim():String; - private function CompareTo(obj:Dynamic):Int; - @:overload(function(startIndex:Int):String {}) - private function Substring(startIndex:Int, length:Int):String; - -} +/* + * Copyright (C)2005-2012 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. + */ +import cs.StdTypes; + +@:coreApi extern class String implements ArrayAccess { + + @:overload private static function Compare(s1:String, s2:String):Int; + @:overload private static function Compare(s1:String, s2:String, kind:cs.system.StringComparison):Int; + + var length(default,null) : Int; + + function new(string:String) : Void; + + function toUpperCase() : String; + + function toLowerCase() : String; + + function charAt( index : Int) : String; + + function charCodeAt( index : Int) : Null; + + function indexOf( str : String, ?startIndex : Int ) : Int; + + function lastIndexOf( str : String, ?startIndex : Int ) : Int; + + function split( delimiter : String ) : Array; + + function substr( pos : Int, ?len : Int ) : String; + + function substring( startIndex : Int, ?endIndex : Int ) : String; + + function toString() : String; + + static function fromCharCode( code : Int ) : String; + + private function IndexOf(value:String, startIndex:Int, comparisonType:cs.system.StringComparison):Int; + private function Replace(oldValue:String, newValue:String):String; + private function StartsWith(value:String):Bool; + private function EndsWith(value:String):Bool; + private function TrimStart():String; + private function TrimEnd():String; + private function Trim():String; + private function CompareTo(obj:Dynamic):Int; + @:overload(function(startIndex:Int):String {}) + private function Substring(startIndex:Int, length:Int):String; + +} diff --git a/std/cs/_std/StringBuf.hx b/std/cs/_std/StringBuf.hx index 1568f0ad5b66ab08257fac06b6ca1e7c2d6f8d0a..2dfe944c8fa9f16cb0d10bb5c6d4dd41fdae6b38 100644 --- a/std/cs/_std/StringBuf.hx +++ b/std/cs/_std/StringBuf.hx @@ -1,48 +1,55 @@ -/* - * Copyright (C)2005-2012 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 : cs.StringBuilder; - - public function new() : Void { - b = new cs.StringBuilder(); - } - - public inline function add( x : Dynamic ) : Void { - b.Append(Std.string(x)); - } - - public function addSub( s : String, pos : Int, ?len : Int ) : Void { - var l:Int = (len == null) ? (s.length - pos) : len; - b.Append(s, pos, l); - } - - public inline function addChar( c : Int ) : Void untyped { - b.Append(cast(c, cs.StdTypes.Char16)); - } - - public function toString() : String { - return b.ToString(); - } - +/* + * Copyright (C)2005-2012 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. + */ +import cs.system.text.StringBuilder; + +@:coreApi +class StringBuf { + + private var b : StringBuilder; + + public var length(get,never) : Int; + + public inline function new() : Void { + b = new StringBuilder(); + } + + inline function get_length() : Int { + return b.Length; + } + + public inline function add( x : T ) : Void { + b.Append(Std.string(x)); + } + + public inline function addSub( s : String, pos : Int, ?len : Int ) : Void { + b.Append(s, pos, (len == null) ? (s.length - pos) : len); + } + + public inline function addChar( c : Int ) : Void untyped { + b.Append(cast(c, cs.StdTypes.Char16)); + } + + public inline function toString() : String { + return b.ToString(); + } + } \ No newline at end of file diff --git a/std/cs/_std/Sys.hx b/std/cs/_std/Sys.hx index 6815a1345db59e2a473870e227e846dbadaf6880..3acc1c1dc6bafe1f283666aa8199df0ef6c3a542 100644 --- a/std/cs/_std/Sys.hx +++ b/std/cs/_std/Sys.hx @@ -1,273 +1,181 @@ -/* - * Copyright (C)2005-2012 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. - */ -import sys.io.Process; -import cs.system.Environment; -import cs.system.threading.Thread; -/* - * Copyright (c) 2005-2012, The haXe Project Contributors - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/** - This class gives you access to many base functionalities of system platforms. Looks in [sys] sub packages for more system APIs. -**/ -@:coreApi -class Sys { - private static var _env:haxe.ds.StringMap; - private static var _args:Array; - - /** - Print any value on the standard output. - **/ - public static function print( v : Dynamic ) : Void - { - cs.system.Console.Write(v); - } - - /** - Print any value on the standard output, followed by a newline - **/ - public static function println( v : Dynamic ) : Void - { - cs.system.Console.WriteLine(v); - } - - /** - Returns all the arguments that were passed by the commandline. - **/ - public static function args() : Array - { - if (_args == null) - { - var ret = cs.Lib.array(Environment.GetCommandLineArgs()); - ret.shift(); - _args = ret; - } - return _args.copy(); - } - - /** - Returns the value of the given environment variable. - **/ - public static function getEnv( s : String ) : String - { - return Environment.GetEnvironmentVariable(s); - } - - /** - Set the value of the given environment variable. - **/ - public static function putEnv( s : String, v : String ) : Void - { - Environment.SetEnvironmentVariable(s, v); - if (_env != null) - _env.set(s, v); - } - - /** - Returns the whole environement variables. - **/ - public static function environment() : haxe.ds.StringMap - { - if (_env == null) - { - var e = _env = new haxe.ds.StringMap(); - var nenv = Environment.GetEnvironmentVariables().GetEnumerator(); - while (nenv.MoveNext()) - { - e.set(nenv.Key, nenv.Value); - } - } - - return _env; - } - - /** - Suspend the current execution for the given time (in seconds). - **/ - public static function sleep( seconds : Float ) : Void - { - Thread.Sleep( Std.int(seconds * 1000) ); - } - - /** - Change the current time locale, which will affect [DateTools.format] date formating. - Returns true if the locale was successfully changed - **/ - public static function setTimeLocale( loc : String ) : Bool - { - //TODO C# - return false; - } - - /** - Get the current working directory (usually the one in which the program was started) - **/ - public static function getCwd() : String - { - return cs.system.io.Directory.GetCurrentDirectory(); - } - - /** - Change the current working directory. - **/ - public static function setCwd( s : String ) : Void - { - cs.system.io.Directory.SetCurrentDirectory(s); - } - - /** - Returns the name of the system you are running on. For instance : - "Windows", "Linux", "BSD" and "Mac" depending on your desktop OS. - **/ - public static function systemName() : String - { - //doing a switch with strings since MacOS might not be available - switch(Environment.OSVersion.Platform + "") - { - case "Unix": return "Linux"; - case "Xbox": return "Xbox"; - case "MacOSX": return "Mac"; - default: - var ver = cast(Environment.OSVersion.Platform, Int); - if (ver == 4 || ver == 6 || ver == 128) - return "Linux"; - return "Windows"; - } - } - - /** - Run the given command with the list of arguments. The command output will be printed on the same output as the current process. - The current process will block until the command terminates and it will return the command result (0 if there was no error). - Read the [sys.io.Process] api for a more complete way to start background processes. - **/ - public static function command( cmd : String, ?args : Array ) : Int - { - var proc:Process = new Process(cmd, args == null ? [] : args); - var ret = proc.exitCode(); - proc.close(); - - return ret; - } - - /** - Exit the current process with the given error code. - **/ - public static function exit( code : Int ) : Void - { - Environment.Exit(code); - } - - /** - Gives the most precise timestamp value (in seconds). - **/ - public static function time() : Float - { - return Date.now().getTime() / 1000; - } - - /** - Gives the most precise timestamp value (in seconds) but only account for the actual time spent running on the CPU for the current thread/process. - **/ - public static function cpuTime() : Float - { - return Environment.TickCount / 1000; - } - - /** - Returns the path to the current executable that we are running. - **/ - public static function executablePath() : String - { - //TODO: add extern references - return untyped __cs__('System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase'); - } - - /** - Read a single input character from the standard input (without blocking) and returns it. Setting [echo] to true will also display it on the output. - **/ - public static function getChar( echo : Bool ) : Int - { - #if !(Xbox || CF || MF) //Xbox, Compact Framework, Micro Framework - return untyped __cs__('((int) System.Console.ReadKey(!echo).KeyChar)'); - #else - return -1; - #end - } - - /** - Returns the process standard input, from which you can read what user enters. Usually it will block until the user send a full input line. See [getChar] for an alternative. - **/ - public static function stdin() : haxe.io.Input - { -#if !(Xbox || CF || MF) - return new cs.io.NativeInput(cs.system.Console.OpenStandardInput()); -#else - return null; -#end - } - - /** - Returns the process standard output on which you can write. - **/ - public static function stdout() : haxe.io.Output - { -#if !(Xbox || CF || MF) - return new cs.io.NativeOutput(cs.system.Console.OpenStandardOutput()); -#else - return null; -#end - } - - /** - Returns the process standard error on which you can write. - **/ - public static function stderr() : haxe.io.Output - { -#if !(Xbox || CF || MF) - return new cs.io.NativeOutput(cs.system.Console.OpenStandardError()); -#else - return null; -#end - } - -} +/* + * Copyright (C)2005-2015 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. + */ +import sys.io.Process; +import cs.system.Environment; +import cs.system.threading.Thread; + +@:coreApi +class Sys { + private static var _env:haxe.ds.StringMap; + private static var _args:Array; + + public static function print( v : Dynamic ) : Void + { + cs.system.Console.Write(v); + } + + public static function println( v : Dynamic ) : Void + { + cs.system.Console.WriteLine(v); + } + + public static function args() : Array + { + if (_args == null) + { + var ret = cs.Lib.array(Environment.GetCommandLineArgs()); + ret.shift(); + _args = ret; + } + return _args.copy(); + } + + public static function getEnv( s : String ) : String + { + return Environment.GetEnvironmentVariable(s); + } + + public static function putEnv( s : String, v : String ) : Void + { + Environment.SetEnvironmentVariable(s, v); + if (_env != null) + _env.set(s, v); + } + + public static function environment() : Map + { + if (_env == null) + { + var e = _env = new haxe.ds.StringMap(); + var nenv = Environment.GetEnvironmentVariables().GetEnumerator(); + while (nenv.MoveNext()) + { + e.set(nenv.Key, nenv.Value); + } + } + + return _env; + } + + public static function sleep( seconds : Float ) : Void + { + Thread.Sleep( Std.int(seconds * 1000) ); + } + + public static function setTimeLocale( loc : String ) : Bool + { + //TODO C# + return false; + } + + public static function getCwd() : String + { + return cs.system.io.Directory.GetCurrentDirectory(); + } + + public static function setCwd( s : String ) : Void + { + cs.system.io.Directory.SetCurrentDirectory(s); + } + + public static function systemName() : String + { + //doing a switch with strings since MacOS might not be available + switch(Environment.OSVersion.Platform + "") + { + case "Unix": return "Linux"; + case "Xbox": return "Xbox"; + case "MacOSX": return "Mac"; + default: + var ver = cast(Environment.OSVersion.Platform, Int); + if (ver == 4 || ver == 6 || ver == 128) + return "Linux"; + return "Windows"; + } + } + + public static function command( cmd : String, ?args : Array ) : Int + { + var proc:Process = new Process(cmd, args == null ? [] : args); + var ret = proc.exitCode(); + proc.close(); + + return ret; + } + + public static function exit( code : Int ) : Void + { + Environment.Exit(code); + } + + public static function time() : Float + { + return Date.now().getTime() / 1000; + } + + public static function cpuTime() : Float + { + return Environment.TickCount / 1000; + } + + public static inline function executablePath() : String + { + return cs.system.reflection.Assembly.GetExecutingAssembly().GetName().CodeBase; + } + + public static function getChar( echo : Bool ) : Int + { + #if !(Xbox || CF || MF) //Xbox, Compact Framework, Micro Framework + return cast(cs.system.Console.ReadKey(!echo).KeyChar, Int); + #else + return -1; + #end + } + + public static function stdin() : haxe.io.Input + { +#if !(Xbox || CF || MF) + return new cs.io.NativeInput(cs.system.Console.OpenStandardInput()); +#else + return null; +#end + } + + public static function stdout() : haxe.io.Output + { +#if !(Xbox || CF || MF) + return new cs.io.NativeOutput(cs.system.Console.OpenStandardOutput()); +#else + return null; +#end + } + + public static function stderr() : haxe.io.Output + { +#if !(Xbox || CF || MF) + return new cs.io.NativeOutput(cs.system.Console.OpenStandardError()); +#else + return null; +#end + } + +} diff --git a/std/cs/_std/Type.hx b/std/cs/_std/Type.hx index 84dc7eec265439ccae5055e9a4b1cce2bc56572e..5df3b9cc8e88e91a7718d582bc6add64387c257a 100644 --- a/std/cs/_std/Type.hx +++ b/std/cs/_std/Type.hx @@ -1,388 +1,361 @@ -/* - * Copyright (C)2005-2012 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. - */ -import cs.Lib; -import cs.internal.HxObject; -import cs.internal.Runtime; -/* - * Copyright (c) 2005, The haXe Project Contributors - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -@:keep enum ValueType { - TNull; - TInt; - TFloat; - TBool; - TObject; - TFunction; - TClass( c : Class ); - TEnum( e : Enum ); - TUnknown; -} - -@:keep @:coreApi class Type { - - @:functionCode(' - if (o == null || o is haxe.lang.DynamicObject || o is System.Type) - return null; - - return o.GetType(); - ') - public static function getClass( o : T ) : Class untyped - { - return null; - } - - @:functionCode(' - if (o is System.Enum || o is haxe.lang.Enum) - return o.GetType(); - return null; - ') - public static function getEnum( o : EnumValue ) : Enum untyped - { - return null; - } - - public static function getSuperClass( c : Class ) : Class - { - var t:cs.system.Type = Lib.toNativeType(c); - var base = t.BaseType; - if (base == null || (base + "") == ("haxe.lang.HxObject") || (base + "") == ("System.Object")) - { - return null; - } - - return Lib.fromNativeType(base); - } - - public static function getClassName( c : Class ) : String { - var ret:String = cast Lib.toNativeType(c); -#if no_root - if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root.")) - ret = ret.substr(10); -#end - - return switch(ret) - { - case "System.Int32": "Int"; - case "System.Double": "Float"; - case "System.String": "String"; - case "System.Object": "Dynamic"; - case "System.Type": "Class"; - default: ret.split("`")[0]; - } - } - - public static function getEnumName( e : Enum ) : String - { - var ret:String = cast Lib.toNativeType(untyped e); -#if no_root - if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root.")) - ret = ret.substr(10); -#end - if (ret.length == 14 && ret == "System.Boolean") - return "Bool"; - return ret; - } - - public static function resolveClass( name : String ) : Class - { -#if no_root - if (name.indexOf(".") == -1) - name = "haxe.root." + name; -#end - var t:cs.system.Type = cs.system.Type.GetType(name); - if (t == null) - { - switch(name) - { - case #if no_root "haxe.root.Int" #else "Int" #end: return cast Int; - case #if no_root "haxe.root.Float" #else "Float" #end: return cast Float; - case #if no_root "haxe.root.Class" #else "Class" #end: return cast Class; - case #if no_root "haxe.root.Dynamic" #else "Dynamic" #end: return cast Dynamic; - case #if no_root "haxe.root.String" #else "String" #end: return cast String; - default: return null; - } - } else if (t.IsInterface && cast(untyped __typeof__(IGenericObject), cs.system.Type).IsAssignableFrom(t)) { - t = null; - var i = 0; - var ts = ""; - while (t == null && i < 18) - { - i++; - ts += (i == 1 ? "" : ",") + "System.Object"; - t = cs.system.Type.GetType(name + "`" + i + "[" + ts + "]"); - } - - return Lib.fromNativeType(t); - } else { - return Lib.fromNativeType(t); - } - } - - @:functionCode(' - if (name == "Bool") return typeof(bool); - System.Type t = resolveClass(name); - if (t != null && (t.BaseType.Equals(typeof(System.Enum)) || t.BaseType.Equals(typeof(haxe.lang.Enum)))) - return t; - return null; - ') - public static function resolveEnum( name : String ) : Enum untyped - { - if (name == "Bool") return Bool; - return cast resolveClass(name); - } - - public static function createInstance( cl : Class, args : Array ) : T - { - if (untyped cl == String) - return args[0]; - var t:cs.system.Type = Lib.toNativeType(cl); - if (t.IsInterface) - { - //may be generic - t = Lib.toNativeType(resolveClass(getClassName(cl))); - } - var ctors = t.GetConstructors(); - return Runtime.callMethod(null, cast ctors, ctors.Length, args); - } - - public static function createEmptyInstance( cl : Class ) : T - { - var t:cs.system.Type = Lib.toNativeType(cl); - if (t.IsInterface) - { - //may be generic - t = Lib.toNativeType(resolveClass(getClassName(cl))); - } - - if (Reflect.hasField(cl, "__hx_createEmpty")) - return untyped cl.__hx_createEmpty(); - return createInstance(cl, []); - } - - @:functionCode(' - if (@params == null || @params[0] == null) - { - object ret = haxe.lang.Runtime.slowGetField(e, constr, true); - if (ret is haxe.lang.Function) - throw haxe.lang.HaxeException.wrap("Constructor " + constr + " needs parameters"); - return (T) ret; - } else { - return (T) haxe.lang.Runtime.slowCallField(e, constr, @params); - } - ') - public static function createEnum( e : Enum, constr : String, ?params : Array ) : T - { - return null; - } - - public static function createEnumIndex( e : Enum, index : Int, ?params : Array ) : T { - var constr = getEnumConstructs(e); - return createEnum(e, constr[index], params); - } - - @:functionCode(' - if (c == typeof(string)) - { - return haxe.lang.StringRefl.fields; - } - - Array ret = new Array(); - - System.Reflection.MemberInfo[] mis = c.GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy); - for (int i = 0; i < mis.Length; i++) - { - if (mis[i] is System.Reflection.PropertyInfo) - continue; - string n = mis[i].Name; - if (!n.StartsWith("__hx_") && n[0] != \'.\' && !n.Equals("Equals") && !n.Equals("ToString") && !n.Equals("GetHashCode") && !n.Equals("GetType")) - ret.push(mis[i].Name); - } - - return ret; - ') - public static function getInstanceFields( c : Class ) : Array { - return null; - } - - @:functionCode(' - Array ret = new Array(); - - if (c == typeof(string)) - { - ret.push("fromCharCode"); - return ret; - } - - System.Reflection.MemberInfo[] mis = c.GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); - for (int i = 0; i < mis.Length; i++) - { - string n = mis[i].Name; - if (!n.StartsWith("__hx_")) - ret.push(mis[i].Name); - } - - return ret; - ') - public static function getClassFields( c : Class ) : Array { - return null; - } - - public static function getEnumConstructs( e : Enum ) : Array { - if (Reflect.hasField(e, "constructs")) - return untyped e.constructs.copy(); - return untyped __cs__("new Array(System.Enum.GetNames(e))"); - } - - @:functionCode(' - if (v == null) return ValueType.TNull; - - System.Type t = v as System.Type; - if (t != null) - { - //class type - return ValueType.TObject; - } - - t = v.GetType(); - if (t.IsEnum) - return ValueType.TEnum(t); - if (t.IsValueType) - { - System.IConvertible vc = v as System.IConvertible; - if (vc != null) - { - switch (vc.GetTypeCode()) - { - case System.TypeCode.Boolean: return ValueType.TBool; - case System.TypeCode.Double: - double d = vc.ToDouble(null); - if (d >= int.MinValue && d <= int.MaxValue && d == vc.ToInt32(null)) - return ValueType.TInt; - else - return ValueType.TFloat; - case System.TypeCode.Int32: - return ValueType.TInt; - default: - return ValueType.TClass(t); - } - } else { - return ValueType.TClass(t); - } - } - - if (v is haxe.lang.IHxObject) - { - if (v is haxe.lang.DynamicObject) - return ValueType.TObject; - else if (v is haxe.lang.Enum) - return ValueType.TEnum(t); - return ValueType.TClass(t); - } else if (v is haxe.lang.Function) { - return ValueType.TFunction; - } else { - return ValueType.TClass(t); - } - ') - public static function typeof( v : Dynamic ) : ValueType - { - return null; - } - - @:functionCode(' - if (a is haxe.lang.Enum) - return a.Equals(b); - else - return haxe.lang.Runtime.eq(a, b); - ') - public static function enumEq( a : T, b : T ) : Bool - { - return untyped a.Equals(b); - } - - @:functionCode(' - if (e is System.Enum) - return e + ""; - else - return ((haxe.lang.Enum) e).getTag(); - ') - public static function enumConstructor( e : EnumValue ) : String untyped - { - return e.tag; - } - - @:functionCode(' - return ( e is System.Enum ) ? new Array() : ((haxe.lang.Enum) e).@params; - ') - public static function enumParameters( e : EnumValue ) : Array untyped - { - return null; - } - - @:functionCode(' - if (e is System.Enum) - return ((System.IConvertible) e).ToInt32(null); - else - return ((haxe.lang.Enum) e).index; - ') - public static function enumIndex( e : EnumValue ) : Int untyped - { - return e.index; - } - - public static function allEnums( e : Enum ) : Array - { - var ctors = getEnumConstructs(e); - var ret = []; - for (ctor in ctors) - { - var v = Reflect.field(e, ctor); - if (Std.is(v, e)) - ret.push(v); - } - - return ret; - } - -} - +/* + * Copyright (C)2005-2015 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. + */ +import cs.Lib; +import cs.internal.HxObject; +import cs.internal.Runtime; +import cs.internal.Function; +import cs.Flags; +import cs.system.Object; +import cs.system.reflection.*; +using StringTools; + +@:keep enum ValueType { + TNull; + TInt; + TFloat; + TBool; + TObject; + TFunction; + TClass( c : Class ); + TEnum( e : Enum ); + TUnknown; +} + +@:keep @:coreApi class Type { + + public static function getClass( o : T ) : Class untyped + { + if (Object.ReferenceEquals(o,null) || Std.is(o,DynamicObject) || Std.is(o,cs.system.Type)) + return null; + + return untyped o.GetType(); + } + + public static function getEnum( o : EnumValue ) : Enum untyped + { + if (Std.is(o, cs.system.Enum) || Std.is(o,HxEnum)) + return untyped o.GetType(); + return null; + } + + public static function getSuperClass( c : Class ) : Class + { + var t:cs.system.Type = Lib.toNativeType(c); + var base = t.BaseType; + if (base == null || base.ToString() == "haxe.lang.HxObject" || base.ToString() == "System.Object") + return null; + return Lib.fromNativeType(base); + } + + public static function getClassName( c : Class ) : String { + var ret:String = cast Lib.toNativeType(c); +#if no_root + if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root.")) + ret = ret.substr(10); +#end + + return switch(ret) + { + case "System.Int32": "Int"; + case "System.Double": "Float"; + case "System.String": "String"; + case "System.Object": "Dynamic"; + case "System.Type": "Class"; + default: ret.split("`")[0]; + } + } + + public static function getEnumName( e : Enum ) : String + { + var ret:String = cast Lib.toNativeType(untyped e); +#if no_root + if (ret.length > 10 && StringTools.startsWith(ret, "haxe.root.")) + ret = ret.substr(10); +#end + if (ret.length == 14 && ret == "System.Boolean") + return "Bool"; + return ret; + } + + public static function resolveClass( name : String ) : Class + { +#if no_root + if (name.indexOf(".") == -1) + name = "haxe.root." + name; +#end + var t:cs.system.Type = cs.system.Type._GetType(name); +#if !CF + if (t == null) + { + var all = cs.system.AppDomain.CurrentDomain.GetAssemblies().GetEnumerator(); + while (all.MoveNext()) + { + var t2:cs.system.reflection.Assembly = all.Current; + t = t2.GetType(name); + if (t != null) + break; + } + } +#end + if (t == null) + { + switch(name) + { + case #if no_root "haxe.root.Int" #else "Int" #end: return cast Int; + case #if no_root "haxe.root.Float" #else "Float" #end: return cast Float; + case #if no_root "haxe.root.Class" #else "Class" #end: return cast Class; + case #if no_root "haxe.root.Dynamic" #else "Dynamic" #end: return cast Dynamic; + case #if no_root "haxe.root.String" #else "String" #end: return cast String; + default: return null; + } +#if !erase_generics + } else if (t.IsInterface && cast(untyped __typeof__(IGenericObject), cs.system.Type).IsAssignableFrom(t)) { + for (attr in t.GetCustomAttributes(true)) + { + var g = cs.Lib.as(attr, cs.internal.HxObject.GenericInterface); + if (g != null) + return Lib.fromNativeType(g.generic); + } + + return Lib.fromNativeType(t); +#end + } else { + return Lib.fromNativeType(t); + } + } + + public static function resolveEnum( name : String ) : Enum untyped + { + if (name == "Bool") return Bool; + var t = Lib.toNativeType(resolveClass(name)); + if (t != null && t.BaseType.Equals( Lib.toNativeType(cs.system.Enum) ) || Lib.toNativeType(HxEnum).IsAssignableFrom(t)) + return t; + return null; + } + + public static function createInstance( cl : Class, args : Array ) : T + { + if (untyped cl == String) + return args[0]; + var t:cs.system.Type = Lib.toNativeType(cl); + if (t.IsInterface) + { + //may be generic + t = Lib.toNativeType(resolveClass(getClassName(cl))); + } + var ctors = t.GetConstructors(); + return Runtime.callMethod(null, cast ctors, ctors.Length, args); + } + + public static function createEmptyInstance( cl : Class ) : T + { + var t:cs.system.Type = Lib.toNativeType(cl); + if (t.IsInterface) + { + //may be generic + t = Lib.toNativeType(resolveClass(getClassName(cl))); + } + + if (Reflect.hasField(cl, "__hx_createEmpty")) + return untyped cl.__hx_createEmpty(); + if (untyped cl == String) + return cast ""; + var t:cs.system.Type = Lib.toNativeType(cl); + + var ctors = t.GetConstructors(); + for (c in 0...ctors.Length) + { + if (ctors[c].GetParameters().Length == 0) + { + var arr = new cs.NativeArray(1); + arr[0] = ctors[c]; + return Runtime.callMethod(null, cast arr, arr.Length, []); + } + } + return cs.system.Activator.CreateInstance(t); + } + + public static function createEnum( e : Enum, constr : String, ?params : Array ) : T + { + if (params == null || params[0] == null) + { + var ret = cs.internal.Runtime.slowGetField(e, constr, true); + if (Reflect.isFunction(ret)) + throw 'Constructor $constr needs parameters'; + return ret; + } else { + return cs.internal.Runtime.slowCallField(e,constr,params); + } + } + + public static function createEnumIndex( e : Enum, index : Int, ?params : Array ) : T { + var constr = getEnumConstructs(e); + return createEnum(e, constr[index], params); + } + + public static function getInstanceFields( c : Class ) : Array + { + if (c == String) + return cs.internal.StringExt.StringRefl.fields; + + var c = cs.Lib.toNativeType(c); + var ret = []; + 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)) + continue; + var n = i.Name; + if (!n.startsWith('__hx_') && n.fastCodeAt(0) != '.'.code) + { + switch(n) + { + case 'Equals' | 'ToString' | 'GetHashCode' | 'GetType': + case _: + ret.push(n); + } + } + } + return ret; + } + + public static function getClassFields( c : Class ) : Array { + if (Object.ReferenceEquals(c, String)) + { + return ['fromCharCode']; + } + + var ret = []; + var infos = Lib.toNativeType(c).GetMembers(new Flags(BindingFlags.Public) | BindingFlags.Static); + for (i in 0...infos.Length) + { + var name = infos[i].Name; + if (!name.startsWith('__hx_')) + { + ret.push(name); + } + } + return ret; + } + + public static function getEnumConstructs( e : Enum ) : Array { + if (Reflect.hasField(e, "__hx_constructs")) { + var ret:Array = cs.Lib.array(untyped e.__hx_constructs); + return ret.copy(); + } + return cs.Lib.array(cs.system.Enum.GetNames(untyped e)); + } + + public static function typeof( v : Dynamic ) : ValueType { + if (v == null) return ValueType.TNull; + + var t:cs.system.Type = cs.Lib.as(v, cs.system.Type); + if (t != null) { + //class type + return ValueType.TObject; + } + + t = v.GetType(); + if (t.IsEnum || Std.is(v, HxEnum)) + return ValueType.TEnum(cast t); + if (t.IsValueType) { + var vc:cs.system.IConvertible = cast v; + if (vc != null) { + switch (vc.GetTypeCode()) { + case cs.system.TypeCode.Boolean: return ValueType.TBool; + case cs.system.TypeCode.Double: + var d:Float = vc.ToDouble(null); + if (d >= cs.system.Int32.MinValue && d <= cs.system.Int32.MaxValue && d == vc.ToInt32(null)) + return ValueType.TInt; + else + return ValueType.TFloat; + case cs.system.TypeCode.Int32: + return ValueType.TInt; + default: + return ValueType.TClass(cast t); + } + } else { + return ValueType.TClass(cast t); + } + } + + if (Std.is(v, IHxObject)) { + if (Std.is(v, DynamicObject)) + return ValueType.TObject; + else if (Std.is(v, HxEnum)) + return ValueType.TEnum(cast t); + return ValueType.TClass(cast t); + } else if (Std.is(v, Function)) { + return ValueType.TFunction; + } else { + return ValueType.TClass(cast t); + } + } + + public static function enumEq( a : T, b : T ) : Bool + { + if (a == null) + return b == null; + else if (b == null) + return false; + else + return untyped a.Equals(b); + } + + public static function enumConstructor( e : EnumValue ) : String untyped + { + return Std.is(e, cs.system.Enum) ? e+'' : cast(e,HxEnum).getTag(); + } + + public static function enumParameters( e : EnumValue ) : Array untyped + { + return Std.is(e, cs.system.Enum) ? [] : cast(e,HxEnum).getParams(); + } + + public static function enumIndex( e : EnumValue ) : Int untyped + { + if (Std.is(e, cs.system.Enum)) + { + var values = cs.system.Enum.GetValues(Lib.getNativeType(e)); + return cs.system.Array.IndexOf(values, e); + } else { + return cast(e, HxEnum).index; + } + } + + public static function allEnums( e : Enum ) : Array + { + var ctors = getEnumConstructs(e); + var ret = []; + for (ctor in ctors) + { + var v = Reflect.field(e, ctor); + if (Std.is(v, e)) + ret.push(v); + } + + return ret; + } + +} + diff --git a/std/cs/_std/Xml.hx b/std/cs/_std/Xml.hx deleted file mode 100644 index 9e512f6df25dcfa5ce55fa84d1ce13deeafba1bf..0000000000000000000000000000000000000000 --- a/std/cs/_std/Xml.hx +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -@:native("_Xml.RealXmlType") -extern enum XmlType { -} - -private enum RealXmlType { - Element; - PCData; - CData; - Comment; - DocType; - ProcessingInstruction; - Document; -} - -@:coreApi class Xml { - - public static var Element(default,null) : XmlType; - public static var PCData(default,null) : XmlType; - public static var CData(default,null) : XmlType; - public static var Comment(default,null) : XmlType; - public static var DocType(default,null) : XmlType; - public static var ProcessingInstruction(default,null) : XmlType; - public static var Document(default,null) : XmlType; - - public var nodeType(default,null) : XmlType; - public var nodeName(get,set) : String; - public var nodeValue(get,set) : String; - public var parent(get,null) : Xml; - - var _nodeName : String; - var _nodeValue : String; - var _attributes : haxe.ds.StringMap; - var _children : Array; - var _parent : Xml; - - public static function parse( str : String ) : Xml { - return haxe.xml.Parser.parse(str); - } - - private function new() : Void { - } - - public static function createElement( name : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Element; - r._children = new Array(); - r._attributes = new haxe.ds.StringMap(); - r.set_nodeName( name ); - return r; - } - - public static function createPCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.PCData; - r.set_nodeValue( data ); - return r; - } - - public static function createCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.CData; - r.set_nodeValue( data ); - return r; - } - - public static function createComment( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Comment; - r.set_nodeValue( data ); - return r; - } - - public static function createDocType( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.DocType; - r.set_nodeValue( data ); - return r; - } - - public static function createProcessingInstruction( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.ProcessingInstruction; - r.set_nodeValue( data ); - return r; - } - - public static function createDocument() : Xml { - var r = new Xml(); - r.nodeType = Xml.Document; - r._children = new Array(); - return r; - } - - private function get_nodeName() : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName; - } - - private function set_nodeName( n : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName = n; - } - - private function get_nodeValue() : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue; - } - - private function set_nodeValue( v : String ) : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue = v; - } - - private function get_parent() : Xml { - return _parent; - } - - public function get( att : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.get( att ); - } - - public function set( att : String, value : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.set( att, value ); - } - - public function remove( att : String ) : Void{ - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.remove( att ); - } - - public function exists( att : String ) : Bool { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.exists( att ); - } - - public function attributes() : Iterator { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.keys(); - } - - public function iterator() : Iterator { - if ( _children == null ) throw "bad nodetype"; - var cur = 0; - var x = this._children; - return { - hasNext : function(){ - return cur < x.length; - }, - next : function(){ - return x[cur++]; - } - } - } - - public function elements() : Iterator { - if ( _children == null ) throw "bad nodetype"; - var cur = 0; - var x = _children; - return untyped { - hasNext : function() { - var k = cur; - var l = x.length; - while( k < l ) { - if( x[k].nodeType == Xml.Element ) - break; - k += 1; - } - cur = k; - return k < l; - }, - next : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - k += 1; - if( n.nodeType == Xml.Element ) { - cur = k; - return n; - } - } - return null; - } - } - } - - public function elementsNamed( name : String ) : Iterator { - if ( _children == null ) throw "bad nodetype"; - var x = _children; - var cur = 0; - return untyped { - cur: 0, - x: this._children, - hasNext : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - if( n.nodeType == Xml.Element && n._nodeName == name ) - break; - k++; - } - cur = k; - return k < l; - }, - next : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - k++; - if( n.nodeType == Xml.Element && n._nodeName == name ) { - cur = k; - return n; - } - } - return null; - } - } - } - - public function firstChild() : Xml { - if( _children == null ) throw "bad nodetype"; - return _children[0]; - } - - public function firstElement() : Xml { - if( _children == null ) throw "bad nodetype"; - var cur = 0; - var l = _children.length; - while( cur < l ) { - var n = _children[cur]; - if( n.nodeType == Xml.Element ) - return n; - cur++; - } - return null; - } - - public function addChild( x : Xml ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.push( x ); - } - - public function removeChild( x : Xml ) : Bool { - if( _children == null ) throw "bad nodetype"; - var b = _children.remove( x ); - if( b ) - x._parent = null; - return b; - } - - public function insertChild( x : Xml, pos : Int ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.insert( pos, x ); - } - - public function toString() : String { - if( nodeType == Xml.PCData ) - return StringTools.htmlEscape(_nodeValue); - if( nodeType == Xml.CData ) - return ""; - if( nodeType == Xml.Comment ) - return ""; - if( nodeType == Xml.DocType ) - return ""; - if( nodeType == Xml.ProcessingInstruction ) - return ""; - var s = new StringBuf(); - - if( nodeType == Xml.Element ) { - s.add("<"); - s.add(_nodeName); - for( k in _attributes.keys() ){ - s.add(" "); - s.add(k); - s.add("=\""); - s.add(_attributes.get(k)); - s.add("\""); - } - if( _children.length == 0 ) { - s.add("/>"); - return s.toString(); - } - s.add(">"); - } - - for( x in iterator() ) - s.add(x.toString()); - - if( nodeType == Xml.Element ) { - s.add(""); - } - return s.toString(); - } - - static function __init__() : Void untyped { - Xml.Element = cast RealXmlType.Element; - Xml.PCData = cast RealXmlType.PCData; - Xml.CData = cast RealXmlType.CData; - Xml.Comment = cast RealXmlType.Comment; - Xml.DocType = cast RealXmlType.DocType; - Xml.ProcessingInstruction = cast RealXmlType.ProcessingInstruction; - Xml.Document = cast RealXmlType.Document; - } - -} diff --git a/std/cs/_std/haxe/Int64.hx b/std/cs/_std/haxe/Int64.hx index e5adc8449c9b67f7e717ae34c6649717dfbf5459..79e51e7c01735a9ea375817577b2ccaf37314143 100644 --- a/std/cs/_std/haxe/Int64.hx +++ b/std/cs/_std/haxe/Int64.hx @@ -1,146 +1,218 @@ -/* - * Copyright (C)2005-2012 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; -using haxe.Int64; -@:coreType @:notNull @:runtimeValue private abstract NativeInt64 from Int to Int {} -@:coreType @:notNull @:runtimeValue private abstract NativeUInt64 from Int to Int {} - -@:coreApi -@:nativeGen class Int64 -{ - @:extern private static inline function asNative(i:Int64):NativeInt64 return untyped i; - @:extern private static inline function ofNative(i:NativeInt64):Int64 return untyped i; - @:extern private static inline function mkNative(i:Dynamic):NativeInt64 return i; - - public static inline function make( high : Int, low : Int ) : Int64 - { - return ((cast(high, NativeInt64) << 32 ) | (low & untyped __cs__('0xffffffffL'))).ofNative(); - } - - public static inline function getLow( x : Int64 ) : Int - { - return cast (x.asNative() & (untyped __cs__("0xFFFFFFFFL")), Int); - } - - public static inline function getHigh( x : Int64 ) : Int { - return cast(cast(x,NativeUInt64) >> 32, Int); - } - - public static inline function ofInt( x : Int ) : Int64 { - return cast x; - } - - public static inline function toInt( x : Int64 ) : Int - { - return cast x; - } - - public static inline function add( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() + b.asNative()).ofNative(); - } - - public static inline function sub( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() - b.asNative()).ofNative(); - } - - public static inline function mul( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() * b.asNative()).ofNative(); - } - - static function divMod( modulus : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } - { - var q:Int64 = (modulus.asNative() / divisor.asNative()).mkNative().ofNative(); - var m:Int64 = (modulus.asNative() % divisor.asNative()).mkNative().ofNative(); - return { quotient : q, modulus : m }; - } - - public static inline function div( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() / b.asNative()).mkNative().ofNative(); - } - - public static inline function mod( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() % b.asNative()).mkNative().ofNative(); - } - - public static inline function shl( a : Int64, b : Int ) : Int64 { - return (a.asNative() << b).ofNative(); - } - - public static inline function shr( a : Int64, b : Int ) : Int64 { - return (a.asNative() >> b).ofNative(); - } - - public static inline function ushr( a : Int64, b : Int ) : Int64 { - return ( cast(a, NativeUInt64) >> b).ofNative(); - } - - public static inline function and( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() & b.asNative()).ofNative(); - } - - public static inline function or( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() | b.asNative()).ofNative(); - } - - public static inline function xor( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() ^ b.asNative()).ofNative(); - } - - public static inline function neg( a : Int64 ) : Int64 - { - return (~a.asNative()).ofNative(); - } - - public static inline function isNeg( a : Int64 ) : Bool - { - return (a.asNative() < 0.mkNative()); - } - - public static inline function isZero( a : Int64 ) : Bool - { - return (a.asNative() == 0.mkNative()); - } - - public static inline function compare( a : Int64, b : Int64 ) : Int - { - return cast (a.asNative() - b.asNative()); - } - - /** - Compare two Int64 in unsigned mode. - **/ - public static function ucompare( a : Int64, b : Int64 ) : Int - { - if (a.asNative() < 0.mkNative()) - return (b.asNative() < 0.mkNative()) ? compare( (~a.asNative()).ofNative(), (~b.asNative()).ofNative()) : 1; - return (b.asNative() < 0.mkNative()) ? -1 : compare(a, b); - } - - public static inline function toStr( a : Int64 ) : String { - return a + ""; - } -} +/* + * Copyright (C)2005-2012 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; +using haxe.Int64; + +private typedef __Int64 = cs.StdTypes.Int64; + +@:coreApi +abstract Int64(__Int64) from __Int64 to __Int64 +{ + + public static inline function make( high : Int32, low : Int32 ) : Int64 + return new Int64( (cast(high, __Int64) << 32) | (cast(low, __Int64)& untyped __cs__('0xffffffffL')) ); + + private inline function new(x : __Int64) + this = x; + + private var val( get, set ) : __Int64; + inline function get_val() : __Int64 return this; + inline function set_val( x : __Int64 ) : __Int64 return this = x; + + public var high( get, never ):Int32; + public inline function get_high():Int32 return cast(this >> 32); + + public var low( get, never ):Int32; + public inline function get_low():Int32 return cast this; + + public inline function copy():Int64 + return new Int64( this ); + + @:from public static inline function ofInt( x : Int ) : Int64 + return cast x; + + public static inline function toInt( x : Int64 ) : Int { + if( x.val < 0x80000000 || x.val > 0x7FFFFFFF ) + throw "Overflow"; + return cast x.val; + } + + inline public static function is( val : Dynamic ) : Bool + return Std.is(val,cs.system.Int64); + + public static inline function getHigh( x : Int64 ) : Int32 + return cast( x.val >> 32 ); + + public static inline function getLow( x : Int64 ) : Int32 + return cast( x.val ); + + public static inline function isNeg( x : Int64 ) : Bool + return x.val < 0; + + public static inline function isZero( x : Int64 ) : Bool + return x.val == 0; + + public static inline function compare( a : Int64, b : Int64 ) : Int + { + if( a.val < b.val ) return -1; + if( a.val > b.val ) return 1; + return 0; + } + + public static inline function ucompare( a : Int64, b : Int64 ) : Int { + if( a.val < 0 ) + return ( b.val < 0 ) ? compare( a, b ) : 1; + return ( b.val < 0 ) ? -1 : compare( a, b ); + } + + public static inline function toStr( x : Int64 ) : String + return '${x.val}'; + + public static inline function divMod( dividend : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } + return { quotient: dividend / divisor, modulus: dividend % divisor }; + + private inline function toString() : String + return '$this'; + + @:op(-A) public static function neg( x : Int64 ) : Int64 + return -x.val; + + @:op(++A) private inline function preIncrement() : Int64 + return ++this; + + @:op(A++) private inline function postIncrement() : Int64 + return this++; + + @:op(--A) private inline function preDecrement() : Int64 + return --this; + + @:op(A--) private inline function postDecrement() : Int64 + return this--; + + @:op(A + B) public static inline function add( a : Int64, b : Int64 ) : Int64 + return a.val + b.val; + + @:op(A + B) @:commutative private static inline function addInt( a : Int64, b : Int ) : Int64 + return a.val + b; + + @:op(A - B) public static inline function sub( a : Int64, b : Int64 ) : Int64 + return a.val - b.val; + + @:op(A - B) private static inline function subInt( a : Int64, b : Int ) : Int64 + return a.val - b; + + @:op(A - B) private static inline function intSub( a : Int, b : Int64 ) : Int64 + return a - b.val; + + @:op(A * B) public static inline function mul( a : Int64, b : Int64 ) : Int64 + return a.val * b.val; + + @:op(A * B) @:commutative private static inline function mulInt( a : Int64, b : Int ) : Int64 + return a.val * b; + + @:op(A / B) public static inline function div( a : Int64, b : Int64 ) : Int64 + return a.val / b.val; + + @:op(A / B) private static inline function divInt( a : Int64, b : Int ) : Int64 + return a.val / b; + + @:op(A / B) private static inline function intDiv( a : Int, b : Int64 ) : Int64 + return a / b.val; + + @:op(A % B) public static inline function mod( a : Int64, b : Int64 ) : Int64 + return a.val % b.val; + + @:op(A % B) private static inline function modInt( a : Int64, b : Int ) : Int64 + return a.val % b; + + @:op(A % B) private static inline function intMod( a : Int, b : Int64 ) : Int64 + return a % b.val; + + @:op(A == B) public static inline function eq( a : Int64, b : Int64 ) : Bool + return a.val == b.val; + + @:op(A == B) @:commutative private static inline function eqInt( a : Int64, b : Int ) : Bool + return a.val == b; + + @:op(A != B) public static inline function neq( a : Int64, b : Int64 ) : Bool + return a.val != b.val; + + @:op(A != B) @:commutative private static inline function neqInt( a : Int64, b : Int ) : Bool + return a.val != b; + + @:op(A < B) private static inline function lt( a : Int64, b : Int64 ) : Bool + return a.val < b.val; + + @:op(A < B) private static inline function ltInt( a : Int64, b : Int ) : Bool + return a.val < b; + + @:op(A < B) private static inline function intLt( a : Int, b : Int64 ) : Bool + return a < b.val; + + @:op(A <= B) private static inline function lte( a : Int64, b : Int64 ) : Bool + return a.val <= b.val; + + @:op(A <= B) private static inline function lteInt( a : Int64, b : Int ) : Bool + return a.val <= b; + + @:op(A <= B) private static inline function intLte( a : Int, b : Int64 ) : Bool + return a <= b.val; + + @:op(A > B) private static inline function gt( a : Int64, b : Int64 ) : Bool + return a.val > b.val; + + @:op(A > B) private static inline function gtInt( a : Int64, b : Int ) : Bool + return a.val > b; + + @:op(A > B) private static inline function intGt( a : Int, b : Int64 ) : Bool + return a > b.val; + + @:op(A >= B) private static inline function gte( a : Int64, b : Int64 ) : Bool + return a.val >= b.val; + + @:op(A >= B) private static inline function gteInt( a : Int64, b : Int ) : Bool + return a.val >= b; + + @:op(A >= B) private static inline function intGte( a : Int, b : Int64 ) : Bool + return a >= b.val; + + @:op(~A) private static inline function complement( x : Int64 ) : Int64 + return ~x.val; + + @:op(A & B) public static inline function and( a : Int64, b : Int64 ) : Int64 + return a.val & b.val; + + @:op(A | B) public static inline function or( a : Int64, b : Int64 ) : Int64 + return a.val | b.val; + + @:op(A ^ B) public static inline function xor( a : Int64, b : Int64 ) : Int64 + return a.val ^ b.val; + + @:op(A << B) public static inline function shl( a : Int64, b : Int ) : Int64 + return a.val << b; + + @:op(A >> B) public static inline function shr( a : Int64, b : Int ) : Int64 + return a.val >> b; + + @:op(A >>> B) public static inline function ushr( a : Int64, b : Int ) : Int64 + return cast ( (a.val : cs.StdTypes.UInt64) >> b ); +} diff --git a/std/cs/_std/haxe/Resource.hx b/std/cs/_std/haxe/Resource.hx new file mode 100644 index 0000000000000000000000000000000000000000..5c326e4c2d92e8c2959ec70e94328ee7160b14a5 --- /dev/null +++ b/std/cs/_std/haxe/Resource.hx @@ -0,0 +1,66 @@ +/* + * Copyright (C)2005-2014 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 { + + @:keep static var content : Array; + static var paths : Map; + + @:keep static function getPaths():Map { + if (paths != null) + return paths; + + var p = new Map(); + var all = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceNames(); + for (i in 0...all.Length) { + var path = all[i]; + var name = path.substr(path.indexOf("Resources.") + 10); + p.set(name, path); + } + return paths = p; + } + + public static inline function listNames() : Array { + return content.copy(); + } + + @:access(haxe.io.Path.escape) + public static function getString( name : String ) : String { + name = haxe.io.Path.escape(name, true); + var path = getPaths().get(name); + var str = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceStream(path); + if (str != null) + return new cs.io.NativeInput(str).readAll().toString(); + return null; + } + + @:access(haxe.io.Path.escape) + public static function getBytes( name : String ) : haxe.io.Bytes { + name = haxe.io.Path.escape(name, true); + var path = getPaths().get(name); + var str = cs.Lib.toNativeType(haxe.Resource).Assembly.GetManifestResourceStream(path); + if (str != null) + return new cs.io.NativeInput(str).readAll(); + return null; + } +} diff --git a/std/cs/_std/haxe/ds/IntMap.hx b/std/cs/_std/haxe/ds/IntMap.hx index 680ff984d4544758169d9dbc1463b37507d5a2ec..eea2791c978553d2b1b2b26239419464586d1149 100644 --- a/std/cs/_std/haxe/ds/IntMap.hx +++ b/std/cs/_std/haxe/ds/IntMap.hx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, The haXe Project Contributors + * Copyright (c) 2005, The Haxe Project Contributors * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -33,7 +33,7 @@ import cs.NativeArray; * Thanks also to Jonas Malaco Filho for his Haxe-written IntMap code inspired by Python tables. * (https://jonasmalaco.com/fossil/test/jonas-haxe/artifact/887b53126e237d6c68951111d594033403889304) */ -@:coreApi class IntMap implements Map.IMap +@:coreApi class IntMap implements haxe.Constraints.IMap { private static inline var HASH_UPPER = 0.7; @@ -46,12 +46,16 @@ import cs.NativeArray; private var nOccupied:Int; private var upperBound:Int; +#if !no_map_cache private var cachedKey:Int; private var cachedIndex:Int; +#end public function new() : Void { +#if !no_map_cache cachedIndex = -1; +#end } public function set( key : Int, value : T ) : Void @@ -72,14 +76,17 @@ import cs.NativeArray; var k = hash(key); var i = k & mask; + var delKey = -1; //for speed up if (flagIsEmpty(flags, i)) { x = i; } else { var inc = getInc(k, mask); var last = i; - while (! (isEither(flags, i) || _keys[i] == key) ) + while (! (flagIsEmpty(flags, i) || _keys[i] == key) ) { + if (delKey == -1 && flagIsDel(flags,i)) + delKey = i; i = (i + inc) & mask; #if DEBUG_HASHTBL if (i == last) @@ -88,7 +95,11 @@ import cs.NativeArray; } #end } - x = i; + + if (flagIsEmpty(flags,i) && delKey != -1) + x = delKey; + else + x = i; } } @@ -135,17 +146,20 @@ import cs.NativeArray; public function get( key : Int ) : Null { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; - +#end return vals[idx]; } @@ -155,17 +169,20 @@ import cs.NativeArray; private function getDefault( key : Int, def : T ) : T { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; - +#end return vals[idx]; } @@ -175,16 +192,20 @@ import cs.NativeArray; public function exists( key : Int ) : Bool { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return true; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; +#end return true; } @@ -195,7 +216,9 @@ import cs.NativeArray; public function remove( key : Int ) : Bool { var idx = -1; +#if !no_map_cache if (! (cachedKey == key && ( (idx = cachedIndex) != -1 ))) +#end { idx = lookup(key); } @@ -204,9 +227,10 @@ import cs.NativeArray; { return false; } else { +#if !no_map_cache if (cachedKey == key) cachedIndex = -1; - +#end if (!isEither(flags, idx)) { setIsDelTrue(flags, idx); @@ -253,9 +277,11 @@ import cs.NativeArray; if (j != 0) { //rehashing is required +#if !no_map_cache //resetting cache cachedKey = 0; cachedIndex = -1; +#end j = -1; var nBuckets = nBuckets, _keys = _keys, vals = vals, flags = flags; @@ -326,59 +352,18 @@ import cs.NativeArray; Returns an iterator of all keys in the hashtable. Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration **/ - public function keys() : Iterator + public inline function keys() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(flags, j)) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = _keys[i]; - cachedIndex = i; - cachedKey = ret; - - i = i + 1; - return ret; - } - }; + return new IntMapKeyIterator(this); } /** Returns an iterator of all values in the hashtable. Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration **/ - public function iterator() : Iterator + public inline function iterator() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(flags, j)) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = vals[i]; - i = i + 1; - return ret; - } - }; + return new IntMapValueIterator(this); } /** @@ -453,3 +438,65 @@ import cs.NativeArray; private static inline function flagsSize(m:Int):Int return ((m) < 16? 1 : (m) >> 4); } + +@:access(haxe.ds.IntMap) +@:final +private class IntMapKeyIterator { + var m:IntMap; + var i:Int; + var len:Int; + + public function new(m:IntMap) { + this.i = 0; + this.m = m; + this.len = m.nBuckets; + } + + public function hasNext():Bool { + for (j in i...len) { + if (!IntMap.isEither(m.flags, j)) { + i = j; + return true; + } + } + return false; + } + + public function next():Int { + var ret = m._keys[i]; +#if !no_map_cache + m.cachedIndex = i; + m.cachedKey = ret; +#end + i++; + return ret; + } +} + +@:access(haxe.ds.IntMap) +@:final +private class IntMapValueIterator { + var m:IntMap; + var i:Int; + var len:Int; + + public function new(m:IntMap) { + this.i = 0; + this.m = m; + this.len = m.nBuckets; + } + + public function hasNext():Bool { + for (j in i...len) { + if (!IntMap.isEither(m.flags, j)) { + i = j; + return true; + } + } + return false; + } + + public inline function next():T { + return m.vals[i++]; + } +} diff --git a/std/cs/_std/haxe/ds/ObjectMap.hx b/std/cs/_std/haxe/ds/ObjectMap.hx index b517bf84ac25f1dc4292d1c6e1ef60951af416bc..4f1315feb827575580384ccdb23b5d1d54d52d00 100644 --- a/std/cs/_std/haxe/ds/ObjectMap.hx +++ b/std/cs/_std/haxe/ds/ObjectMap.hx @@ -23,7 +23,7 @@ package haxe.ds; import cs.NativeArray; -@:coreApi class ObjectMap implements Map.IMap +@:coreApi class ObjectMap implements haxe.Constraints.IMap { @:extern private static inline var HASH_UPPER = 0.77; @:extern private static inline var FLAG_EMPTY = 0; @@ -46,8 +46,10 @@ import cs.NativeArray; private var nOccupied:Int; private var upperBound:Int; +#if !no_map_cache private var cachedKey:K; private var cachedIndex:Int; +#end #if DEBUG_HASHTBL private var totalProbes:Int; @@ -58,7 +60,9 @@ import cs.NativeArray; public function new() : Void { +#if !no_map_cache cachedIndex = -1; +#end } public function set( key : K, value : V ) : Void @@ -79,14 +83,17 @@ import cs.NativeArray; k = hash(key); var i = k & mask, nProbes = 0; + var delKey = -1; //for speed up - if (isEither(hashes[i])) { + if (isEmpty(hashes[i])) { x = i; } else { //var inc = getInc(k, mask); var last = i, flag; - while(! (isEither(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) + while(! (isEmpty(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) { + if (isDel(flag) && delKey == -1) + delKey = i; i = (i + ++nProbes) & mask; #if DEBUG_HASHTBL probeTimes++; @@ -94,7 +101,11 @@ import cs.NativeArray; throw "assert"; #end } - x = i; + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; } #if DEBUG_HASHTBL @@ -122,8 +133,10 @@ import cs.NativeArray; vals[x] = value; } +#if !no_map_cache cachedIndex = x; cachedKey = key; +#end } @:final private function lookup( key : K ) : Int @@ -188,9 +201,11 @@ import cs.NativeArray; if (j != 0) { //rehashing is required +#if !no_map_cache //resetting cache cachedKey = null; cachedIndex = -1; +#end j = -1; var nBuckets = nBuckets, _keys = _keys, vals = vals, hashes = hashes; @@ -263,16 +278,20 @@ import cs.NativeArray; public function get( key : K ) : Null { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; +#end return vals[idx]; } @@ -283,16 +302,20 @@ import cs.NativeArray; private function getDefault( key : K, def : V ) : V { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; +#end return vals[idx]; } @@ -303,16 +326,20 @@ import cs.NativeArray; public function exists( key : K ) : Bool { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return true; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; +#end return true; } @@ -323,7 +350,9 @@ import cs.NativeArray; public function remove( key : K ) : Bool { var idx = -1; +#if !no_map_cache if (! (cachedKey == key && ( (idx = cachedIndex) != -1 ))) +#end { idx = lookup(key); } @@ -332,8 +361,10 @@ import cs.NativeArray; { return false; } else { +#if !no_map_cache if (cachedKey == key) cachedIndex = -1; +#end hashes[idx] = FLAG_DEL; _keys[idx] = null; @@ -350,29 +381,7 @@ import cs.NativeArray; **/ public function keys() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(hashes[j])) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = _keys[i]; - cachedIndex = i; - cachedKey = ret; - - i = i + 1; - return ret; - } - }; + return new ObjectMapKeyIterator(this); } /** @@ -381,26 +390,7 @@ import cs.NativeArray; **/ public function iterator() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(hashes[j])) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = vals[i]; - i = i + 1; - return ret; - } - }; + return new ObjectMapValueIterator(this); } /** @@ -485,4 +475,75 @@ import cs.NativeArray; } } +@:access(haxe.ds.ObjectMap) +@:final @:keep +private class ObjectMapKeyIterator { + var m:ObjectMap; + var i:Int; + var len:Int; + + public function new(m:ObjectMap) { + this.i = 0; + this.m = m; + this.len = m.nBuckets; + } + + public function hasNext():Bool { + for (j in i...len) + { + if (!ObjectMap.isEither(m.hashes[j])) + { + i = j; + return true; + } + } + return false; + } + + public function next() : T { + var ret = m._keys[i]; + +#if !no_map_cache + m.cachedIndex = i; + m.cachedKey = ret; +#end + + i = i + 1; + return ret; + } +} + +@:access(haxe.ds.ObjectMap) +@:final @:keep +private class ObjectMapValueIterator { + var m:ObjectMap; + var i:Int; + var len:Int; + + public function new(m:ObjectMap) + { + this.i = 0; + this.m = m; + this.len = m.nBuckets; + } + + public function hasNext() : Bool { + for (j in i...len) + { + if (!ObjectMap.isEither(m.hashes[j])) + { + i = j; + return true; + } + } + return false; + } + + public inline function next():T { + var ret = m.vals[i]; + i = i + 1; + return ret; + } +} + private typedef HashType = Int; diff --git a/std/cs/_std/haxe/ds/StringMap.hx b/std/cs/_std/haxe/ds/StringMap.hx index 79971a16af21dd3df6f51df2181d3c0c871dc470..9a53bff679bffaa1a5611adf2234df5c7b5bb1e9 100644 --- a/std/cs/_std/haxe/ds/StringMap.hx +++ b/std/cs/_std/haxe/ds/StringMap.hx @@ -23,7 +23,7 @@ package haxe.ds; import cs.NativeArray; -@:coreApi class StringMap implements Map.IMap +@:coreApi class StringMap implements haxe.Constraints.IMap { @:extern private static inline var HASH_UPPER = 0.77; @:extern private static inline var FLAG_EMPTY = 0; @@ -46,8 +46,10 @@ import cs.NativeArray; private var nOccupied:Int; private var upperBound:Int; +#if !no_map_cache private var cachedKey:String; private var cachedIndex:Int; +#end #if DEBUG_HASHTBL private var totalProbes:Int; @@ -58,7 +60,9 @@ import cs.NativeArray; public function new() : Void { +#if !no_map_cache cachedIndex = -1; +#end } public function set( key : String, value : T ) : Void @@ -79,14 +83,16 @@ import cs.NativeArray; k = hash(key); var i = k & mask, nProbes = 0; + var delKey = -1; //for speed up - if (isEither(hashes[i])) { + if (isEmpty(hashes[i])) { x = i; } else { - //var inc = getInc(k, mask); var last = i, flag; - while(! (isEither(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) + while(! (isEmpty(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) { + if (isDel(flag) && delKey == -1) + delKey = i; i = (i + ++nProbes) & mask; #if DEBUG_HASHTBL probeTimes++; @@ -94,7 +100,11 @@ import cs.NativeArray; throw "assert"; #end } - x = i; + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; } #if DEBUG_HASHTBL @@ -122,8 +132,10 @@ import cs.NativeArray; vals[x] = value; } +#if !no_map_cache cachedIndex = x; cachedKey = key; +#end } @:final private function lookup( key : String ) : Int @@ -189,8 +201,10 @@ import cs.NativeArray; if (j != 0) { //rehashing is required //resetting cache +#if !no_map_cache cachedKey = null; cachedIndex = -1; +#end j = -1; var nBuckets = nBuckets, _keys = _keys, vals = vals, hashes = hashes; @@ -263,17 +277,19 @@ import cs.NativeArray; public function get( key : String ) : Null { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } - +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; - +#end return vals[idx]; } @@ -283,16 +299,20 @@ import cs.NativeArray; private function getDefault( key : String, def : T ) : T { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return vals[idx]; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; +#end return vals[idx]; } @@ -303,17 +323,20 @@ import cs.NativeArray; public function exists( key : String ) : Bool { var idx = -1; +#if !no_map_cache if (cachedKey == key && ( (idx = cachedIndex) != -1 )) { return true; } +#end idx = lookup(key); if (idx != -1) { +#if !no_map_cache cachedKey = key; cachedIndex = idx; - +#end return true; } @@ -323,7 +346,9 @@ import cs.NativeArray; public function remove( key : String ) : Bool { var idx = -1; +#if !no_map_cache if (! (cachedKey == key && ( (idx = cachedIndex) != -1 ))) +#end { idx = lookup(key); } @@ -332,9 +357,10 @@ import cs.NativeArray; { return false; } else { +#if !no_map_cache if (cachedKey == key) cachedIndex = -1; - +#end hashes[idx] = FLAG_DEL; _keys[idx] = null; vals[idx] = null; @@ -348,59 +374,18 @@ import cs.NativeArray; Returns an iterator of all keys in the hashtable. Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration **/ - public function keys() : Iterator + public inline function keys() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(hashes[j])) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = _keys[i]; - cachedIndex = i; - cachedKey = ret; - - i = i + 1; - return ret; - } - }; + return new StringMapKeyIterator(this); } /** Returns an iterator of all values in the hashtable. Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration **/ - public function iterator() : Iterator + public inline function iterator() : Iterator { - var i = 0; - var len = nBuckets; - return { - hasNext: function() { - for (j in i...len) - { - if (!isEither(hashes[j])) - { - i = j; - return true; - } - } - return false; - }, - next: function() { - var ret = vals[i]; - i = i + 1; - return ret; - } - }; + return new StringMapValueIterator(this); } /** @@ -486,3 +471,65 @@ import cs.NativeArray; } private typedef HashType = Int; + +@:final +@:access(haxe.ds.StringMap) +private class StringMapKeyIterator { + var m:StringMap; + var i:Int; + var len:Int; + + public function new(m:StringMap) { + this.m = m; + this.i = 0; + this.len = m.nBuckets; + } + + public function hasNext():Bool { + for (j in i...len) { + if (!StringMap.isEither(m.hashes[j])) { + i = j; + return true; + } + } + return false; + } + + public function next():String { + var ret = m._keys[i]; +#if !no_map_cache + m.cachedIndex = i; + m.cachedKey = ret; +#end + i++; + return ret; + } +} + +@:final +@:access(haxe.ds.StringMap) +private class StringMapValueIterator { + var m:StringMap; + var i:Int; + var len:Int; + + public function new(m:StringMap) { + this.m = m; + this.i = 0; + this.len = m.nBuckets; + } + + public function hasNext():Bool { + for (j in i...len) { + if (!StringMap.isEither(m.hashes[j])) { + i = j; + return true; + } + } + return false; + } + + public inline function next():T { + return m.vals[i++]; + } +} diff --git a/std/cs/_std/haxe/ds/WeakMap.hx2 b/std/cs/_std/haxe/ds/WeakMap.hx2 new file mode 100644 index 0000000000000000000000000000000000000000..53f00172d4191b72aa42c1b86ebd2cdfdcd0a545 --- /dev/null +++ b/std/cs/_std/haxe/ds/WeakMap.hx2 @@ -0,0 +1,569 @@ +/* + * Copyright (C)2005-2012 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; + +import cs.NativeArray; +import cs.system.WeakReference; + +// This implementation works by lazily evaluating the weak references, and only cleaning them up when needed. +@:coreApi class WeakMap implements haxe.Constraints.IMap +{ + @:extern private static inline var HASH_UPPER = 0.77; + @:extern private static inline var FLAG_EMPTY = 0; + @:extern private static inline var FLAG_DEL = 1; + + /** + * This is the most important structure here and the reason why it's so fast. + * It's an array of all the hashes contained in the table. These hashes cannot be 0 nor 1, + * which stand for "empty" and "deleted" states. + * + * The lookup algorithm will keep looking until a 0 or the key wanted is found; + * The insertion algorithm will do the same but will also break when FLAG_DEL is found; + */ + private var hashes:NativeArray; + private var entries:NativeArray>; + + private var nBuckets:Int; + private var size:Int; + private var nOccupied:Int; + private var upperBound:Int; + + private var cachedEntry:Entry; + private var cachedIndex:Int; + +#if DEBUG_HASHTBL + private var totalProbes:Int; + private var probeTimes:Int; + private var sameHash:Int; + private var maxProbe:Int; +#end + + public function new() : Void + { + cachedIndex = -1; + } + + @:final private function checkSize():Void + { + //iterate over the hashes and remove dead references + var size = size, entries = entries, hashes = hashes; + if (entries == null) + return; + for (i in 0...entries.Length) + { + var e = entries[i]; + if (e != null && e.Target == null) + { + --size; + hashes[i] = FLAG_DEL; + entries[i] = null; + } + } + this.size = size; + } + + public function set( key : K, value : V ) : Void + { + var x:Int, k:Int; + + if (nOccupied >= upperBound) + { + if (nBuckets > (size << 1)) + resize(nBuckets - 1); //clear "deleted" elements + else + resize(nBuckets + 2); + } + + k = hash(key); + var hashes = hashes, entries = entries; + { + var mask = (nBuckets == 0) ? 0 : nBuckets - 1; + var site = x = nBuckets; + var i = k & mask, nProbes = 0; + + //for speed up + var delKey = -1; + if (isEmpty(hashes[i])) { + x = i; + } else { + //var inc = getInc(k, mask); + var last = i, flag; + while(! (isEmpty(flag = hashes[i]) || (flag == k && entries[i].keyEquals(key) )) ) + { + if (delKey == -1 && isDel(flag)) + delKey = i; + + var entry = entries[i]; + if (entry.Target == null) + { + hashes[i] = FLAG_DEL; + entries[i] = null; + --size; + if (delKey == -1) + delKey = i; + } + + i = (i + ++nProbes) & mask; +#if DEBUG_HASHTBL + probeTimes++; + if (i == last) + throw "assert"; +#end + } + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; + } + +#if DEBUG_HASHTBL + if (nProbes > maxProbe) + maxProbe = nProbes; + totalProbes++; +#end + } + + var flag = hashes[x], entry = new Entry(key,value,k); + if (isEmpty(flag)) + { + entries[x] = entry; + hashes[x] = k; + size++; + nOccupied++; + } else if (isDel(flag)) { + entries[x] = entry; + hashes[x] = k; + size++; + } else { + assert(entries[x].keyEquals(key)); + entries[x] = entry; + } + + cachedIndex = x; + cachedEntry = entry; + } + + @:final private function lookup( key : K ) : Int + { + if (nBuckets != 0) + { + var hashes = hashes, entries = entries; + + var mask = nBuckets - 1, hash = hash(key), k = hash, nProbes = 0; + var i = k & mask; + var last = i, flag; + //var inc = getInc(k, mask); + while (!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != k || !entries[i].keyEquals(key))) + { + if (!isDel(flag)) + { + var entry = entries[i]; + if (entry.Target == null) + { + entries[i] = null; + hashes[i] = FLAG_DEL; + --size; + } + } + i = (i + ++nProbes) & mask; +#if DEBUG_HASHTBL + probeTimes++; + if (i == last) + throw "assert"; +#end + } + +#if DEBUG_HASHTBL + if (nProbes > maxProbe) + maxProbe = nProbes; + totalProbes++; +#end + return isEither(flag) ? -1 : i; + } + + return -1; + } + + @:final @:private function resize(newNBuckets:Int) : Void + { + //This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. + var newHash = null; + var j = 1; + { + newNBuckets = roundUp(newNBuckets); + if (newNBuckets < 4) newNBuckets = 4; + if (size >= (newNBuckets * HASH_UPPER + 0.5)) /* requested size is too small */ + { + j = 0; + } else { /* hash table size to be changed (shrink or expand); rehash */ + var nfSize = newNBuckets; + newHash = new NativeArray( nfSize ); + if (nBuckets < newNBuckets) //expand + { + var e = new NativeArray(newNBuckets); + if (entries != null) + arrayCopy(entries, 0, e, 0, nBuckets); + entries = e; + } //otherwise shrink + } + } + + if (j != 0) + { //rehashing is required + //resetting cache + cachedEntry = null; + cachedIndex = -1; + + j = -1; + var nBuckets = nBuckets, entries = entries, hashes = hashes; + + var newMask = newNBuckets - 1; + while (++j < nBuckets) + { + var k; + if (!isEither(k = hashes[j])) + { + var entry = entries[j]; + if (entry.Target != null) + { + hashes[j] = FLAG_DEL; + while (true) /* kick-out process; sort of like in Cuckoo hashing */ + { + var nProbes = 0; + var i = k & newMask; + + while (!isEmpty(newHash[i])) + i = (i + ++nProbes) & newMask; + + newHash[i] = k; + + if (i < nBuckets && !isEither(k = hashes[i])) /* kick out the existing element */ + { + { + var tmp = entries[i]; + entries[i] = entry; + entry = tmp; + } + + hashes[i] = FLAG_DEL; /* mark it as deleted in the old hash table */ + } else { /* write the element and jump out of the loop */ + entries[i] = entry; + break; + } + } + } + } + } + + if (nBuckets > newNBuckets) /* shrink the hash table */ + { + { + var e = new NativeArray(newNBuckets); + arrayCopy(entries, 0, e, 0, newNBuckets); + this.entries = e; + } + } + + this.hashes = newHash; + this.nBuckets = newNBuckets; + this.nOccupied = size; + this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); + } + } + + public function get( key : K ) : Null + { + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return cachedEntry.value; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return entry.value; + } + + return null; + } + + private function getDefault( key : K, def : V ) : V + { + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return cachedEntry.value; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return entry.value; + } + + return def; + } + + public function exists( key : K ) : Bool + { + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return true; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return true; + } + + return false; + } + + public function remove( key : K ) : Bool + { + var idx = -1; + if ( !(cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) ) + { + idx = lookup(key); + } + + if (idx == -1) + { + return false; + } else { + if (cachedEntry != null && cachedEntry.keyEquals(key)) + { + cachedIndex = -1; + cachedEntry = null; + } + + hashes[idx] = FLAG_DEL; + entries[idx] = null; + --size; + + return true; + } + } + + /** + Returns an iterator of all keys in the hashtable. + Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration + **/ + public function keys() : Iterator + { + var i = 0; + var len = nBuckets; + var lastKey = null; //keep a strong reference to the key while iterating, so it can't be collected while iterating + return { + hasNext: function() { + for (j in i...len) + { + if (!isEither(hashes[j])) + { + var entry = entries[j]; + var last = entry.Target; + if (last != null) + { + lastKey = last; + cachedIndex = i; + cachedEntry = entry; + i = j; + return true; + } else { + --size; + hashes[j] = FLAG_DEL; + entries[j] = null; + } + } + } + return false; + }, + next: function() { + i = i + 1; + return lastKey; + } + }; + } + + /** + Returns an iterator of all values in the hashtable. + Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration + **/ + public function iterator() : Iterator + { + var i = 0; + var len = nBuckets; + var lastKey = null; //keep a strong reference to the key while iterating, so it can't be collected while iterating + return { + hasNext: function() { + for (j in i...len) + { + if (!isEither(hashes[j])) + { + var entry = entries[j]; + var last = entry.Target; + if (last != null) + { + lastKey = last; + cachedIndex = i; + cachedEntry = entry; + i = j; + return true; + } else { + --size; + hashes[j] = FLAG_DEL; + entries[j] = null; + } + } + } + return false; + }, + next: function() { + var ret = entries[i].value; + i = i + 1; + return ret; + } + }; + } + + /** + Returns an displayable representation of the hashtable content. + **/ + + public function toString() : String { + var s = new StringBuf(); + s.add("{"); + var it = keys(); + for( i in it ) { + s.add(Std.string(i)); + s.add(" => "); + s.add(Std.string(get(i))); + if( it.hasNext() ) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + @:extern private static inline function roundUp(x:Int):Int + { + --x; + x |= (x) >>> 1; + x |= (x) >>> 2; + x |= (x) >>> 4; + x |= (x) >>> 8; + x |= (x) >>> 16; + return ++x; + } + + @:extern private static inline function getInc(k:Int, mask:Int):Int //return 1 for linear probing + return (((k) >> 3 ^ (k) << 3) | 1) & (mask); + + @:extern private static inline function isEither(v:HashType):Bool + return (v & 0xFFFFFFFE) == 0; + + @:extern private static inline function isEmpty(v:HashType):Bool + return v == FLAG_EMPTY; + + @:extern private static inline function isDel(v:HashType):Bool + return v == FLAG_DEL; + + //guarantee: Whatever this function is, it will never return 0 nor 1 + @:extern private static inline function hash(s:Dynamic):HashType + { + var k:Int = untyped s.GetHashCode(); + //k *= 357913941; + //k ^= k << 24; + //k += ~357913941; + //k ^= k >> 31; + //k ^= k << 31; + + // k = (k+0x7ed55d16) + (k<<12); + // k = (k^0xc761c23c) ^ (k>>19); + // k = (k+0x165667b1) + (k<<5); + // k = (k+0xd3a2646c) ^ (k<<9); + // k = (k+0xfd7046c5) + (k<<3); + // k = (k^0xb55a4f09) ^ (k>>16); + + var ret = k; + if (isEither(ret)) + { + if (ret == 0) + ret = 2; + else + ret = 0xFFFFFFFF; + } + + return ret; + } + + @:extern private static inline function arrayCopy(sourceArray:cs.system.Array, sourceIndex:Int, destinationArray:cs.system.Array, destinationIndex:Int, length:Int):Void + cs.system.Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length); + + @:extern private static inline function assert(x:Bool):Void + { +#if DEBUG_HASHTBL + if (!x) throw "assert failed"; +#end + } +} + +private class Entry extends WeakReference +{ + public var value:V; + public var hash(default, null):Int; + public function new(key:K, value:V, hash:Int) + { + super(key, false); + this.value = value; + this.hash = hash; + } + + public function reuse(key,hash) + { + this.Target = key; + this.hash = hash; + } + + @:final inline public function keyEquals(k:K):Bool + { + return k != null && untyped k.Equals(Target); + } +} + +private typedef HashType = Int; diff --git a/std/cs/_std/sys/FileSystem.hx b/std/cs/_std/sys/FileSystem.hx index b1a1287589b41a5aca38d1ea939836525a25f488..f27938858044de1029f53924e5543e299022f0e0 100644 --- a/std/cs/_std/sys/FileSystem.hx +++ b/std/cs/_std/sys/FileSystem.hx @@ -1,157 +1,132 @@ -/* - * Copyright (C)2005-2012 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; -import cs.system.io.DirectoryInfo; -import cs.system.io.File; -import cs.system.io.Directory; -import cs.system.io.FileInfo; - -/** - This class allows you to get informations about the files and directories. -**/ -@:coreApi -class FileSystem { - - /** - Tells if the given file or directory exists. - **/ - public static function exists( path : String ) : Bool - { - return (File.Exists(path) || Directory.Exists(path)); - } - - /** - Rename the corresponding file or directory, allow to move it accross directories as well. - **/ - public static function rename( path : String, newpath : String ) : Void - { - Directory.Move(path, newpath); - } - - /** - Returns informations for the given file/directory. - **/ - public static function stat( path : String ) : FileStat - { - if (File.Exists(path)) - { - var fi = new FileInfo(path); - return { - gid: 0, //C# doesn't let you get this info - uid: 0, //same - atime: untyped Date.fromNative(fi.LastAccessTime), - mtime: untyped Date.fromNative(fi.LastWriteTime), - ctime: untyped Date.fromNative(fi.CreationTime), - size: cast(fi.Length, Int), //TODO: maybe change to Int64 for Haxe 3? - dev: 0, //FIXME: not sure what that is - ino: 0, //FIXME: not sure what that is - nlink: 0, //FIXME: not sure what that is - rdev: 0, //FIXME: not sure what that is - mode: 0 //FIXME: not sure what that is - }; - } else if (Directory.Exists(path)) { - var fi = new DirectoryInfo(path); - return { - gid: 0, //C# doesn't let you get this info - uid: 0, //same - atime: untyped Date.fromNative(fi.LastAccessTime), - mtime: untyped Date.fromNative(fi.LastWriteTime), - ctime: untyped Date.fromNative(fi.CreationTime), - size: 0, //TODO: maybe change to Int64 for Haxe 3? - dev: 0, //FIXME: not sure what that is - ino: 0, //FIXME: not sure what that is - nlink: 0, //FIXME: not sure what that is - rdev: 0, //FIXME: not sure what that is - mode: 0 //FIXME: not sure what that is - }; - } else { - throw "Path '" + path + "' doesn't exist"; - } - - } - - /** - Returns the full path for the given path which is relative to the current working directory. - **/ - public static function fullPath( relpath : String ) : String - { - return new FileInfo(relpath).FullName; - } - - /** - Tells if the given path is a directory. Throw an exception if it does not exists or is not accesible. - **/ - public static function isDirectory( path : String ) : Bool - { - var isdir = Directory.Exists(path); - if (isdir != File.Exists(path)) - return isdir; - throw "Path '" + path + "' doesn't exist"; - } - - /** - Create the given directory. Not recursive : the parent directory must exists. - **/ - public static function createDirectory( path : String ) : Void - { - Directory.CreateDirectory(path); - } - - /** - Delete a given file. - **/ - public static function deleteFile( path : String ) : Void - { - File.Delete(path); - } - - /** - Delete a given directory. - **/ - public static function deleteDirectory( path : String ) : Void - { - Directory.Delete(path); - } - - /** - Read all the files/directories stored into the given directory. - **/ - public static function readDirectory( path : String ) : Array - { - var ret = Directory.GetFileSystemEntries(path); - if (ret.Length > 0) - { - var fst = ret[0]; - var sep = "/"; - if (fst.lastIndexOf(sep) < fst.lastIndexOf("\\")) - sep = "\\"; - for (i in 0...ret.Length) - { - var path = ret[i]; - ret[i] = path.substr(path.lastIndexOf(sep) + 1); - } - } - - return cs.Lib.array( ret ); - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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; +import cs.system.io.DirectoryInfo; +import cs.system.io.File; +import cs.system.io.Directory; +import cs.system.io.FileInfo; + +@:coreApi +class FileSystem { + + public static function exists( path : String ) : Bool + { + return (File.Exists(path) || Directory.Exists(path)); + } + + public static function rename( path : String, newPath : String ) : Void + { + Directory.Move(path, newPath); + } + + public static function stat( path : String ) : FileStat + { + if (File.Exists(path)) + { + var fi = new FileInfo(path); + return { + gid: 0, //C# doesn't let you get this info + uid: 0, //same + atime: untyped Date.fromNative(fi.LastAccessTime), + mtime: untyped Date.fromNative(fi.LastWriteTime), + ctime: untyped Date.fromNative(fi.CreationTime), + size: cast(fi.Length, Int), //TODO: maybe change to Int64 for Haxe 3? + dev: 0, //FIXME: not sure what that is + ino: 0, //FIXME: not sure what that is + nlink: 0, //FIXME: not sure what that is + rdev: 0, //FIXME: not sure what that is + mode: 0 //FIXME: not sure what that is + }; + } else if (Directory.Exists(path)) { + var fi = new DirectoryInfo(path); + return { + gid: 0, //C# doesn't let you get this info + uid: 0, //same + atime: untyped Date.fromNative(fi.LastAccessTime), + mtime: untyped Date.fromNative(fi.LastWriteTime), + ctime: untyped Date.fromNative(fi.CreationTime), + size: 0, //TODO: maybe change to Int64 for Haxe 3? + dev: 0, //FIXME: not sure what that is + ino: 0, //FIXME: not sure what that is + nlink: 0, //FIXME: not sure what that is + rdev: 0, //FIXME: not sure what that is + mode: 0 //FIXME: not sure what that is + }; + } else { + throw "Path '" + path + "' doesn't exist"; + } + + } + + public static function fullPath( relPath : String ) : String + { + return new FileInfo(relPath).FullName; + } + + public static function absolutePath ( relPath : String ) : String { + if (haxe.io.Path.isAbsolute(relPath)) return relPath; + return haxe.io.Path.join([Sys.getCwd(), relPath]); + } + + public static function isDirectory( path : String ) : Bool + { + var isdir = Directory.Exists(path); + if (isdir != File.Exists(path)) + return isdir; + throw "Path '" + path + "' doesn't exist"; + } + + public static function createDirectory( path : String ) : Void + { + Directory.CreateDirectory(path); + } + + public static function deleteFile( path : String ) : Void + { + File.Delete(path); + } + + public static function deleteDirectory( path : String ) : Void + { + Directory.Delete(path); + } + + public static function readDirectory( path : String ) : Array + { + var ret = Directory.GetFileSystemEntries(path); + if (ret.Length > 0) + { + var fst = ret[0]; + var sep = "/"; + if (fst.lastIndexOf(sep) < fst.lastIndexOf("\\")) + sep = "\\"; + for (i in 0...ret.Length) + { + var path = ret[i]; + ret[i] = path.substr(path.lastIndexOf(sep) + 1); + } + } + + return cs.Lib.array( ret ); + } + +} diff --git a/std/cs/_std/sys/db/Sqlite.hx b/std/cs/_std/sys/db/Sqlite.hx new file mode 100644 index 0000000000000000000000000000000000000000..efa64ab429b492119f3fb04d08eba4b654f058ae --- /dev/null +++ b/std/cs/_std/sys/db/Sqlite.hx @@ -0,0 +1,48 @@ +package sys.db; + +class Sqlite +{ + static var type:Class; + /** + Opens a new SQLite connection on the specified path. + Note that you will need a SQLite ADO.NET Provider (see http://www.mono-project.com/docs/database-access/providers/sqlite/). + Also note that this will try to open an assembly named `Mono.Data.Sqlite` if it wasn't loaded yet. + **/ + public static function open(file:String):sys.db.Connection + { + var cnxString = 'Data Source=$file'; + if (type == null) + { + var t = null; + var assemblies = cs.system.AppDomain.CurrentDomain.GetAssemblies(); + for (i in 0...assemblies.Length) + { + var a = assemblies[i]; + t = a.GetType('Mono.Data.Sqlite.SqliteConnection'); + if (t == null) + t = a.GetType('System.Data.SQLite.SQLiteConnection'); + if (t != null) + { + break; + } + } + + if (t == null) + { + var asm = cs.system.reflection.Assembly.Load('Mono.Data.Sqlite'); + t = asm.GetType('Mono.Data.Sqlite.SqliteConnection'); + } + + if (t != null) + type = cast cs.Lib.fromNativeType(t); + } + + if (type == null) + { + throw "No ADO.NET SQLite provider was found!"; + } + var ret = Type.createInstance(type,[cnxString]); + ret.Open(); + return cs.db.AdoNet.create(ret,'SQLite'); + } +} diff --git a/std/cs/_std/sys/io/File.hx b/std/cs/_std/sys/io/File.hx index 27350f6ae8ca8d6d133c739da003da2cfc625af7..05f08ef6f7873b61ea2b67c171897a5ef9ca1d39 100644 --- a/std/cs/_std/sys/io/File.hx +++ b/std/cs/_std/sys/io/File.hx @@ -1,94 +1,91 @@ -/* - * Copyright (C)2005-2012 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.io; - -/** - API for reading and writing to files. -**/ -@:coreApi -class File { - - public static function getContent( path : String ) : String - { - var f = read(path, false); - var ret = f.readAll().toString(); - f.close(); - return ret; - } - - public static function saveContent( path : String, content : String ) : Void - { - var f = write(path, false); - f.writeString(content); - f.close(); - } - - public static function getBytes( path : String ) : haxe.io.Bytes - { - var f = read(path, true); - var ret = f.readAll(); - f.close(); - return ret; - } - - public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void - { - var f = write(path, true); - f.writeBytes(bytes, 0, bytes.length); - f.close(); - } - - public static function read( path : String, binary : Bool = true ) : FileInput - { - #if std-buffer //standardize 4kb buffers - var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite, 4096); - #else - var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite); - #end - return new FileInput(stream); - } - - public static function write( path : String, binary : Bool = true ) : FileOutput - { - #if std-buffer //standardize 4kb buffers - var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite, 4096); - #else - var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite); - #end - return new FileOutput(stream); - } - - public static function append( path : String, binary : Bool = true ) : FileOutput - { - #if std-buffer //standardize 4kb buffers - var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite, 4096); - #else - var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite); - #end - return new FileOutput(stream); - } - - public static function copy( src : String, dst : String ) : Void - { - cs.system.io.File.Copy(src, dst); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.io; + +@:coreApi +class File { + + public static function getContent( path : String ) : String + { + var f = read(path, false); + var ret = f.readAll().toString(); + f.close(); + return ret; + } + + public static function saveContent( path : String, content : String ) : Void + { + var f = write(path, false); + f.writeString(content); + f.close(); + } + + public static function getBytes( path : String ) : haxe.io.Bytes + { + var f = read(path, true); + var ret = f.readAll(); + f.close(); + return ret; + } + + public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void + { + var f = write(path, true); + f.writeBytes(bytes, 0, bytes.length); + f.close(); + } + + public static function read( path : String, binary : Bool = true ) : FileInput + { + #if std_buffer //standardize 4kb buffers + var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite, 4096); + #else + var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite); + #end + return new FileInput(stream); + } + + public static function write( path : String, binary : Bool = true ) : FileOutput + { + #if std_buffer //standardize 4kb buffers + var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite, 4096); + #else + var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite); + #end + return new FileOutput(stream); + } + + public static function append( path : String, binary : Bool = true ) : FileOutput + { + #if std_buffer //standardize 4kb buffers + var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite, 4096); + #else + var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite); + #end + return new FileOutput(stream); + } + + public static function copy( srcPath : String, dstPath : String ) : Void + { + cs.system.io.File.Copy(srcPath, dstPath); + } +} diff --git a/std/cs/_std/sys/io/FileInput.hx b/std/cs/_std/sys/io/FileInput.hx index 2f192fdfa4ccc711d49a91cf9cf3d6283e93917a..305f615f8d8b7f32b1ca866f1c30eb338e5dc84f 100644 --- a/std/cs/_std/sys/io/FileInput.hx +++ b/std/cs/_std/sys/io/FileInput.hx @@ -1,32 +1,29 @@ -/* - * Copyright (C)2005-2012 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.io; - -/** - Use [sys.io.File.read] to create a [FileInput] -**/ -class FileInput extends cs.io.NativeInput { - public function new(stream:cs.system.io.FileStream) - { - super(stream); - } -} +/* + * Copyright (C)2005-2012 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.io; + +class FileInput extends cs.io.NativeInput { + public 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 629c60fbf9425f2c0e635c4bbd6a17a321e6605b..640fe8e0d9bb209467737b9c2b1b2d678284b76e 100644 --- a/std/cs/_std/sys/io/FileOutput.hx +++ b/std/cs/_std/sys/io/FileOutput.hx @@ -1,32 +1,29 @@ -/* - * Copyright (C)2005-2012 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.io; - -/** - Use [sys.io.File.write] to create a [FileOutput] -**/ -class FileOutput extends cs.io.NativeOutput { - public function new(stream:cs.system.io.FileStream) - { - super(stream); - } -} +/* + * Copyright (C)2005-2012 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.io; + +class FileOutput extends cs.io.NativeOutput { + public function new(stream:cs.system.io.FileStream) + { + super(stream); + } +} diff --git a/std/cs/_std/sys/io/Process.hx b/std/cs/_std/sys/io/Process.hx index 223de2f1116040a087a8032acc590479baffe274..af578c52e898ac633acdd68863b2726ff5c9a3a7 100644 --- a/std/cs/_std/sys/io/Process.hx +++ b/std/cs/_std/sys/io/Process.hx @@ -1,111 +1,83 @@ -/* - * Copyright (C)2005-2012 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.io; -import haxe.io.BytesInput; -import cs.system.io.StreamReader; -import cs.system.io.StreamWriter; - -@:coreApi -class Process { - - public var stdout(default,null) : haxe.io.Input; - public var stderr(default,null) : haxe.io.Input; - public var stdin(default, null) : haxe.io.Output; - - private var native:NativeProcess; - - - public function new( cmd : String, args : Array ) : Void - { - this.native = new NativeProcess(); - native.StartInfo.FileName = cmd; - var buf = new StringBuf(); - for (arg in args) - { - buf.add("\""); - buf.add(StringTools.replace(arg, "\"", "\\\"")); - buf.add("\" "); - } - native.StartInfo.Arguments = buf.toString(); - native.StartInfo.RedirectStandardError = native.StartInfo.RedirectStandardInput = native.StartInfo.RedirectStandardOutput = true; - native.StartInfo.UseShellExecute = false; - - native.Start(); - - this.stdout = new cs.io.NativeInput(native.StandardOutput.BaseStream); - this.stderr = new cs.io.NativeInput(native.StandardError.BaseStream); - this.stdin = new cs.io.NativeOutput(native.StandardInput.BaseStream); - } - - public function getPid() : Int - { - return native.Id; - } - - public function exitCode() : Int - { - native.WaitForExit(); - return native.ExitCode; - } - - public function close() : Void - { - native.Close(); - } - - public function kill() : Void - { - native.Kill(); - } - -} - -/* -FIXME: The actual process class is much more complex than this, so here it is included a very simplified version. -*/ -@:native('System.Diagnostics.Process') private extern class NativeProcess -{ - var ExitCode(default, null):Int; - var Id(default, null):Int; - var StartInfo(default, null):NativeStartInfo; - var StandardError(default, null):StreamReader; - var StandardInput(default, null):StreamWriter; - var StandardOutput(default, null):StreamReader; - - function new():Void; - function Close():Void; - function Kill():Void; - function Start():Void; - function WaitForExit():Void; -} - -@:native('System.Diagnostics.ProcessStartInfo') private extern class NativeStartInfo -{ - var Arguments:String; - var FileName:String; - var RedirectStandardError:Bool; - var RedirectStandardInput:Bool; - var RedirectStandardOutput:Bool; - var UseShellExecute:Bool; - function new(filename:String, args:String):Void; - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.io; +import haxe.io.BytesInput; +import cs.system.io.StreamReader; +import cs.system.io.StreamWriter; +import cs.system.diagnostics.Process as NativeProcess; +import cs.system.diagnostics.ProcessStartInfo as NativeStartInfo; + +@:coreApi +class Process { + + public var stdout(default,null) : haxe.io.Input; + public var stderr(default,null) : haxe.io.Input; + public var stdin(default, null) : haxe.io.Output; + + private var native:NativeProcess; + + + public function new( cmd : String, args : Array ) : Void + { + this.native = new NativeProcess(); + native.StartInfo.FileName = cmd; + native.StartInfo.CreateNoWindow = true; + var buf = new StringBuf(); + for (arg in args) + { + buf.add("\""); + buf.add(StringTools.replace(arg, "\"", "\\\"")); + buf.add("\" "); + } + native.StartInfo.Arguments = buf.toString(); + native.StartInfo.RedirectStandardError = native.StartInfo.RedirectStandardInput = native.StartInfo.RedirectStandardOutput = true; + native.StartInfo.UseShellExecute = false; + + native.Start(); + + this.stdout = new cs.io.NativeInput(native.StandardOutput.BaseStream); + this.stderr = new cs.io.NativeInput(native.StandardError.BaseStream); + this.stdin = new cs.io.NativeOutput(native.StandardInput.BaseStream); + } + + public function getPid() : Int + { + return native.Id; + } + + public function exitCode() : Int + { + native.WaitForExit(); + return native.ExitCode; + } + + public function close() : Void + { + native.Close(); + } + + public function kill() : Void + { + native.Kill(); + } + +} diff --git a/std/cs/_std/sys/net/Host.hx b/std/cs/_std/sys/net/Host.hx new file mode 100644 index 0000000000000000000000000000000000000000..b9d0b4963d5bfc14eec85e2b89e27196d41eef38 --- /dev/null +++ b/std/cs/_std/sys/net/Host.hx @@ -0,0 +1,63 @@ + +package sys.net; + +import cs.system.Array; +import cs.system.net.Dns; +import cs.system.net.IPAddress; +import cs.system.net.IPHostEntry; +import cs.system.net.sockets.AddressFamily; +import haxe.io.Bytes; +import haxe.io.BytesInput; + +/** + A given IP host name. +**/ +@:coreapi +class Host { + public var hostEntry(default, null) : IPHostEntry; + public var ipAddress(default, null) : IPAddress; + + /** + The actual IP corresponding to the host. + **/ + public var ip(get, null) : Int; + private function get_ip() : Int { + return new BytesInput(Bytes.ofData( ipAddress.GetAddressBytes() )).readInt32(); + } + + /** + Creates a new Host : the name can be an IP in the form "127.0.0.1" or an host name such as "google.com", in which case + the corresponding IP address is resolved using DNS. An exception occur if the host name could not be found. + **/ + public function new( name : String ) : Void { + hostEntry = Dns.GetHostEntry(name); + for (i in 0...hostEntry.AddressList.Length) { + if (hostEntry.AddressList[i].AddressFamily == InterNetwork) { + ipAddress = hostEntry.AddressList[i]; + break; + } + } + } + + /** + Returns the IP representation of the host + **/ + public function toString() : String { + return ipAddress.ToString(); + } + + /** + Perform a reverse-DNS query to resolve a host name from an IP. + **/ + public function reverse() : String { + return hostEntry.HostName; + } + + /** + Returns the local computer host name + **/ + static public function localhost() : String { + return Dns.GetHostName(); + } + +} diff --git a/std/cs/_std/sys/net/Socket.hx b/std/cs/_std/sys/net/Socket.hx new file mode 100644 index 0000000000000000000000000000000000000000..31c9f77792ccaadc2d1fea2355169db402e16b7a --- /dev/null +++ b/std/cs/_std/sys/net/Socket.hx @@ -0,0 +1,187 @@ + +package sys.net; + +import cs.system.net.IPEndPoint; +import cs.system.net.sockets.AddressFamily; +import cs.system.net.sockets.NetworkStream; +import cs.system.net.sockets.ProtocolType; +import cs.system.net.sockets.SocketFlags; +import cs.system.net.sockets.SocketShutdown; +import cs.system.net.sockets.SocketType; +import cs.system.threading.Thread; +import haxe.io.Bytes; +import haxe.io.Error; +import haxe.io.Input; +import haxe.io.Output; + +/** + A TCP socket class : allow you to both connect to a given server and exchange messages or start your own server and wait for connections. +**/ +@:coreapi +class Socket { + private var sock : cs.system.net.sockets.Socket = null; + + /** + The stream on which you can read available data. By default the stream is blocking until the requested data is available, + use [setBlocking(false)] or [setTimeout] to prevent infinite waiting. + **/ + public var input(default,null) : haxe.io.Input; + + /** + The stream on which you can send data. Please note that in case the output buffer you will block while writing the data, use [setBlocking(false)] or [setTimeout] to prevent that. + **/ + public var output(default,null) : haxe.io.Output; + + /** + A custom value that can be associated with the socket. Can be used to retreive your custom infos after a [select]. + ***/ + public var custom : Dynamic; + + /** + Creates a new unconnected socket. + **/ + public function new() : Void { + sock = new cs.system.net.sockets.Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); + sock.Blocking = true; + } + + /** + Closes the socket : make sure to properly close all your sockets or you will crash when you run out of file descriptors. + **/ + public function close() : Void { + sock.Close(); + input = null; + output = null; + } + + /** + Read the whole data available on the socket. + **/ + public function read() : String { + return input.readAll().toString(); + } + + /** + Write the whole data to the socket output. + **/ + public function write( content : String ) : Void { + output.writeString( content ); + } + + /** + Connect to the given server host/port. Throw an exception in case we couldn't sucessfully connect. + **/ + public function connect( host : Host, port : Int ) : Void { + sock.Connect( host.ipAddress, port ); + if (sock.Connected) { + this.output = new cs.io.NativeOutput( new NetworkStream(sock) ); + this.input = new cs.io.NativeInput( new NetworkStream(sock) ); + } else { + throw "Connection failed."; + } + } + + /** + Allow the socket to listen for incoming questions. The parameter tells how many pending connections we can have until they get refused. Use [accept()] to accept incoming connections. + **/ + public function listen( connections : Int ) : Void { + sock.Listen( connections ); + } + + /** + Shutdown the socket, either for reading or writing. + **/ + public function shutdown( read : Bool, write : Bool ) : Void { + if ( read && write ) { + sock.Shutdown( SocketShutdown.Both ); + input = null; + output = null; + } else if ( read ) { + sock.Shutdown( SocketShutdown.Receive ); + input = null; + } else if ( write ) { + sock.Shutdown( SocketShutdown.Send ); + output = null; + } + } + + /** + Bind the socket to the given host/port so it can afterwards listen for connections there. + **/ + public function bind( host : Host, port : Int ) : Void { + sock = new cs.system.net.sockets.Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); + sock.Bind( new IPEndPoint(host.ipAddress, port) ); + } + + /** + Accept a new connected client. This will return a connected socket on which you can read/write some data. + **/ + public function accept() : Socket { + var r = new Socket(); + r.sock = sock.Accept(); + r.output = new cs.io.NativeOutput( new NetworkStream(r.sock) ); + r.input = new cs.io.NativeInput( new NetworkStream(r.sock) ); + return r; + } + + /** + Return the informations about the other side of a connected socket. + **/ + public function peer() : { host : Host, port : Int } { + var remoteIP = cast(sock.RemoteEndPoint, IPEndPoint); + return { host: new Host(remoteIP.Address.ToString()), port: remoteIP.Port }; + } + + /** + Return the informations about our side of a connected socket. + **/ + public function host() : { host : Host, port : Int } { + var localIP = cast(sock.LocalEndPoint, IPEndPoint); + return { host: new Host(localIP.Address.ToString()), port: localIP.Port }; + } + + /** + Gives a timeout after which blocking socket operations (such as reading and writing) will abort and throw an exception. + **/ + public function setTimeout( timeout : Float ) : Void { + sock.ReceiveTimeout = sock.SendTimeout = Math.round(timeout * 1000); + } + + /** + Block until some data is available for read on the socket. + **/ + public function waitForRead() : Void { + var end = Date.now().getTime() + ((sock.ReceiveTimeout <= 0) ? Math.POSITIVE_INFINITY : sock.ReceiveTimeout); + while ( sock.Available == 0 && Date.now().getTime() < end) { + Thread.Sleep(5); + } + } + + /** + Change the blocking mode of the socket. A blocking socket is the default behavior. A non-blocking socket will abort blocking operations immediatly by throwing a haxe.io.Error.Blocking value. + **/ + public function setBlocking( b : Bool ) : Void { + sock.Blocking = b; + } + + /** + Allows the socket to immediatly send the data when written to its output : this will cause less ping but might increase the number of packets / data size, especially when doing a lot of small writes. + **/ + public function setFastSend( b : Bool ) : Void { + sock.NoDelay = b; + } + + /** + Wait until one of the sockets groups is ready for the given operation : + [read] contains sockets on which we want to wait for available data to be read, + [write] contains sockets on which we want to wait until we are allowed to write some data to their output buffers, + [others] contains sockets on which we want to wait for exceptional conditions. + [select] will block until one of the condition is met, in which case it will return the sockets for which the condition was true. + In case a [timeout] (in seconds) is specified, select might wait at worse until the timeout expires. + **/ + static public function select(read : Array, write : Array, others : Array, ?timeout : Float) : { read: Array,write: Array,others: Array } { + throw "Not implemented yet."; + return null; + } + +} diff --git a/std/cs/db/AdoNet.hx b/std/cs/db/AdoNet.hx new file mode 100644 index 0000000000000000000000000000000000000000..58cea1eabbb9733ea7079a37e2e730ac98ccc913 --- /dev/null +++ b/std/cs/db/AdoNet.hx @@ -0,0 +1,350 @@ +package cs.db; +import sys.db.*; +import cs.system.data.*; + +class AdoNet +{ + public static function create(cnx:IDbConnection, dbName:String):Connection + { + return new AdoConnection(cnx,dbName); + } +} + +private class AdoConnection implements Connection +{ + private static var ids = 0; + private var id:Int; + + private var cnx:IDbConnection; + //escape handling + private var escapeRegex:EReg; + private var escapes:Array; + private var name:String; + private var command:IDbCommand; + private var transaction:IDbTransaction; + + public function new(cnx,name:String) + { + this.id = cs.system.threading.Interlocked.Increment(ids); + this.cnx = cnx; + this.name = name; + this.escapes = []; + this.command = cnx.CreateCommand(); + this.escapeRegex = ~/@HX_ESCAPE(\d+)_(\d+)/; + } + + public function close() : Void + { + cnx.Close(); + } + + public function escape(s:String):String + { + var param = command.CreateParameter(); + var name = "@HX_ESCAPE" + id + "_" +escapes.push(param) + ""; + param.ParameterName = name; + param.Value = s; + return name; + } + + public function quote(s:String):String + { + var param = command.CreateParameter(); + var name = "@HX_ESCAPE" + id + "_" +escapes.push(param) + ""; + param.ParameterName = name; + param.Value = s; + return name; + } + + public function addValue(s:StringBuf, v:Dynamic) + { + if (Std.is(v, Date)) + { + v = Std.string(v); + } else if (Std.is(v, haxe.io.Bytes)) { + var bt:haxe.io.Bytes = v; + v = bt.getData(); + } + var param = command.CreateParameter(); + var name = "@HX_ESCAPE" + id + "_" +escapes.push(param) + ""; + param.ParameterName = name; + param.Value = v; + s.add(name); + } + + public function lastInsertId():Int + { + var ret = cnx.CreateCommand(); + ret.CommandText = switch(name) { + case 'SQLite': + 'SELECT last_insert_rowid()'; + case _: + 'SELECT @@IDENTITY'; + } + ret.CommandType = CommandType.Text; + var r = cast ret.ExecuteScalar(); + ret.Dispose(); + + return r; + } + + public function dbName() : String + { + return name; + } + + public function startTransaction() : Void + { + if (this.transaction != null) + throw 'Transaction already active'; + this.transaction = cnx.BeginTransaction(); + } + + public function commit() : Void + { + if (this.transaction == null) + throw 'No transaction was initiated'; + this.transaction.Commit(); + } + + public function rollback() : Void + { + if (this.transaction == null) + throw 'No transaction was initiated'; + this.transaction.Rollback(); + } + + private static function getFirstStatement(s:String) + { + var buf = new StringBuf(); + var hasData = false; + var chr = 0, + i = 0; + inline function getch() return chr = StringTools.fastCodeAt(s,i++); + while ( !StringTools.isEof(getch()) ) + { + inline function peek() { var c = StringTools.fastCodeAt(s,i); if (StringTools.isEof(c)) break; return c; } + switch(chr) + { + case ' '.code | '\t'.code | '\n'.code: + if (hasData) + return buf.toString(); + case '-'.code if (peek() == '-'.code): + if (hasData) + return buf.toString(); + while (!StringTools.isEof(getch())) + { + if (chr == '\n'.code) break; + } + case '#'.code: + if (hasData) + return buf.toString(); + while (!StringTools.isEof(getch())) + { + if (chr == '\n'.code) break; + } + case '/'.code if (peek() == '*'.code): + i++; + if (hasData) + return buf.toString(); + while (!StringTools.isEof(getch())) + { + if (chr == '*'.code && peek() == '/'.code) + { + i++; + break; + } + } + case _: + hasData = true; + buf.addChar(chr); + } + } + return buf.toString(); + } + + public function request( s : String ) : ResultSet + { + var newst = new StringBuf(); + //cycle through the request string, adding any @HX_ESCAPE reference to the command + var ret:ResultSet = null; + var r = escapeRegex; + var myid = id + "", escapes = escapes, elen = escapes.length; + var cmd = this.command; + try + { + while (r.match(s)) + { + var id = r.matched(1); +#if debug + if (id != myid) throw "Request quotes are only valid for one single request; They can't be cached."; +#end + + newst.add(r.matchedLeft()); + var eid = Std.parseInt(r.matched(2)); +#if debug + if (eid == null || eid > elen) + throw "Invalid request quote ID " + eid; +#end + cmd.Parameters.Add(escapes[eid - 1]); + newst.add(escapes[eid-1].ParameterName); + s = r.matchedRight(); + } + newst.add(s); + + s = newst.toString(); + cmd.CommandText = s; + + var stmt = getFirstStatement(s).toLowerCase(); + if (stmt == 'select') + { + ret = new AdoResultSet( cmd.ExecuteReader() ); + } else { + cmd.ExecuteNonQuery(); + ret = EmptyResultSet.empty; + } + + if (escapes.length != 0) + this.escapes = []; + this.id = cs.system.threading.Interlocked.Increment(ids); + cmd.Dispose(); + this.command = cnx.CreateCommand(); + return ret; + } + catch(e:Dynamic) + { + if (escapes.length != 0) + this.escapes = []; + this.id = cs.system.threading.Interlocked.Increment(ids); + try { cmd.Dispose(); } catch(e:Dynamic) {} + this.command = cnx.CreateCommand(); + cs.Lib.rethrow(e); + } + return null; + } +} + +private class AdoResultSet implements ResultSet +{ + public var length(get,null) : Int; + public var nfields(get,null) : Int; + + private var reader:IDataReader; + private var didNext:Bool; + private var names:Array; + private var types:Array>; + + public function new(reader) + { + this.reader = reader; + this.names = [ for (i in 0...reader.FieldCount) reader.GetName(i) ]; + this.types = [ for (i in 0...names.length) cs.Lib.fromNativeType(reader.GetFieldType(i)) ]; + } + + private function get_length() + { + return reader.Depth; + } + + private function get_nfields() + { + return names.length; + } + + public function hasNext() : Bool + { + didNext = true; + return reader.Read(); + } + + public function next() : Dynamic + { + if (!didNext && !hasNext()) + return null; + didNext = false; + var ret = {}, names = names, types = types; + for (i in 0...names.length) + { + var name = names[i], t = types[i], val:Dynamic = null; + if (t == cs.system.Single) + { + val = reader.GetDouble(i); + } else if (t == cs.system.DateTime || t == cs.system.TimeSpan) { + var d = reader.GetDateTime(i); + if (d != null) + val = Date.fromTime(cast(d.Ticks,Float) / cast(cs.system.TimeSpan.TicksPerMillisecond,Float)); + } else if (t == cs.system.DBNull) { + val = null; + } else if (t == cs.system.Byte) { + var v2:cs.StdTypes.UInt8 = reader.GetValue(i); + val = cast(v2,Int); + } else if (Std.string(t) == 'System.Byte[]') { + val = haxe.io.Bytes.ofData(reader.GetValue(i)); + } else { + val = reader.GetValue(i); + } + if (Std.is(val,cs.system.DBNull)) + val = null; + Reflect.setField(ret, name, val); + } + return ret; + } + + public function results() : List + { + var l = new List(); + while (hasNext()) + l.add(next()); + return l; + } + + public function getResult( n : Int ) : String + { + return reader.GetString(n); + } + + public function getIntResult( n : Int ) : Int + { + return reader.GetInt32(n); + } + + public function getFloatResult( n : Int ) : Float + { + return reader.GetDouble(n); + } + + public function getFieldsNames() : Null> + { + return names; + } + +} + +private class EmptyResultSet implements ResultSet +{ + public static var empty = new EmptyResultSet(); + public function new() + { + } + + public var length(get,null) : Int; + public var nfields(get,null) : Int; + + private function get_length() + { + return 0; + } + + private function get_nfields() + { + return 0; + } + + public function hasNext() : Bool return false; + public function next() : Dynamic return null; + public function results() : List return new List(); + public function getResult( n : Int ) : String return null; + public function getIntResult( n : Int ) : Int return 0; + public function getFloatResult( n : Int ) : Float return 0; + public function getFieldsNames() : Null> return null; +} diff --git a/std/cs/internal/BoxedPointer.hx b/std/cs/internal/BoxedPointer.hx new file mode 100644 index 0000000000000000000000000000000000000000..e76d5677a092bfa1e667bc68633ca70acab02fbc --- /dev/null +++ b/std/cs/internal/BoxedPointer.hx @@ -0,0 +1,12 @@ +package cs.internal; + +@:unsafe @:keep @:native('haxe.lang.BoxedPointer') @:nativeGen class BoxedPointer +{ + @:readonly public var value(default,null):Pointer; + + public function new(val) + { + this.value = val; + } + +} diff --git a/std/cs/internal/Exceptions.hx b/std/cs/internal/Exceptions.hx index 45d6bbd5600e23b96740308bd44779c437246683..2a75ac8c845870fac344c4df4e74fad9dd0dea5e 100644 --- a/std/cs/internal/Exceptions.hx +++ b/std/cs/internal/Exceptions.hx @@ -1,58 +1,66 @@ -/* - * Copyright (C)2005-2012 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 cs.internal; -import cs.system.Exception; - -//should NOT be usable inside haxe code -@: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 function getObject():Dynamic - { - return obj; - } - - public function toString():String - { - return "Haxe Exception: " + obj; - } - - public static function wrap(obj:Dynamic):Exception - { - if (Std.is(obj, Exception)) return obj; - - return new HaxeException(obj); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs.internal; +import cs.system.Exception; + +@:nativeGen @:keep @:native("haxe.lang.Exceptions") class Exceptions { + + @:allow(haxe.CallStack) + @:meta(System.ThreadStaticAttribute) + static var exception:cs.system.Exception; +} + +//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 function getObject():Dynamic + { + return obj; + } + + public function toString():String + { + return Std.string(obj); + } + + public static function wrap(obj:Dynamic):Exception + { + if (Std.is(obj, Exception)) return obj; + + return new HaxeException(obj); + } +} diff --git a/std/cs/internal/FieldLookup.hx b/std/cs/internal/FieldLookup.hx index c3e59dea2545842cbdec4e7b207ff05210698138..9ca1580dd9fba2a85df878a97183f7db8184cf6e 100644 --- a/std/cs/internal/FieldLookup.hx +++ b/std/cs/internal/FieldLookup.hx @@ -1,122 +1,328 @@ -/* - * Copyright (C)2005-2012 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 cs.internal; - -@:native('haxe.lang.FieldLookup') -@:keep @:static private class FieldLookup -{ - - @:private private static var fieldIds:Array; - @:private private static var fields:Array; - - //s cannot be null here - private static inline function doHash(s:String):Int - { - var acc = 0; //alloc_int - for (i in 0...s.length) - { - acc = (( 223 * (acc >> 1) + s.charCodeAt(i) ) << 1); - } - - return acc >>> 1; //always positive - } - - public static function lookupHash(key:Int):String - { - //start of binary search algorithm - var ids = fieldIds; - var min = 0; - var max = ids.length; - - while (min < max) - { - var mid = min + Std.int((max - min) / 2); - var imid = ids[mid]; - if (key < imid) - { - max = mid; - } else if (key > imid) { - min = mid + 1; - } else { - return fields[mid]; - } - } - //if not found, it's definately an error - throw "Field not found for hash " + key; - } - - public static function hash(s:String):Int - { - if (s == null) return 0; - - var key = doHash(s); - - //start of binary search algorithm - var ids = fieldIds; - var min = 0; - var max = ids.length; - - while (min < max) - { - var mid = Std.int(min + (max - min) / 2); //overflow safe - var imid = ids[mid]; - if (key < imid) - { - max = mid; - } else if (key > imid) { - min = mid + 1; - } else { - var field = fields[mid]; - if (field != s) - return ~key; //special case - return key; - } - } - //if not found, min holds the value where we should insert the key - ids.insert(min, key); - fields.insert(min, s); - return key; - } - - public static function findHash(hash:Int, hashs:Array):Int - { - var min = 0; - var max = hashs.length; - - while (min < max) - { - var mid = Std.int((max + min) / 2); //overflow safe - var imid = hashs[mid]; - if (hash < imid) - { - max = mid; - } else if (hash > imid) { - min = mid + 1; - } else { - return mid; - } - } - //if not found, return a negative value of where it should be inserted - return ~min; - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs.internal; + +@:native('haxe.lang.FieldLookup') +@:final @:nativeGen +@:classCode("#pragma warning disable 628\n") +@:keep @:static class FieldLookup +{ + @:protected private static var fieldIds:cs.NativeArray; + @:protected private static var fields:cs.NativeArray; + @:protected private static var length:Int; + + static function __init__() + { + length = fieldIds.Length; + } + + private static function addFields(nids:cs.NativeArray, nfields:cs.NativeArray):Void + { + // first see if we need to add anything + var cids = fieldIds, + cfields = fields; + var nlen = nids.Length; + var clen = length; + if (nfields.Length != nlen) throw 'Different fields length: $nlen and ${nfields.Length}'; + + //TODO optimize + var needsChange = false; + for (i in nids) + { + if (findHash(i, cids, clen) < 0) + { + needsChange = true; + break; + } + } + + // if we do, lock and merge + if (needsChange) + { + cs.Lib.lock(FieldLookup, { + // trace(cs.Lib.array(nids), cs.Lib.array(cids)); + var ansIds = new cs.NativeArray(clen + nlen), + ansFields = new cs.NativeArray(clen + nlen); + var ci = 0, ni = 0, ansi = 0; + while (ci < clen && ni < nlen) + { + if (cids[ci] < nids[ni]) + { + ansIds[ansi] = cids[ci]; + ansFields[ansi] = cfields[ci]; + ++ci; + } else { + ansIds[ansi] = nids[ni]; + ansFields[ansi] = nfields[ni]; + ++ni; + } + ++ansi; + } + + if (ci < clen) + { + cs.system.Array.Copy(cids, ci, ansIds, ansi, clen - ci); + cs.system.Array.Copy(cfields, ci, ansFields, ansi, clen - ci); + ansi += clen - ci; + } + + if (ni < nlen) + { + cs.system.Array.Copy(nids, ni, ansIds, ansi, nlen - ni); + cs.system.Array.Copy(nfields, ni, ansFields, ansi, nlen - ni); + ansi += nlen - ni; + } + + // trace(cs.Lib.array(ansIds)); + fieldIds = ansIds; + fields = ansFields; + length = ansi; + }); + } + } + + //s cannot be null here + private static inline function doHash(s:String):Int + { + var acc = 0; //alloc_int + for (i in 0...s.length) + { + acc = (( 223 * (acc >> 1) + cast(s[i], Int)) << 1); + } + + return acc >>> 1; //always positive + } + + public static function lookupHash(key:Int):String + { + //start of binary search algorithm + var ids = fieldIds; + var min = 0; + var max = length; + + while (min < max) + { + var mid = min + Std.int((max - min) / 2); + var imid = ids[mid]; + if (key < imid) + { + max = mid; + } else if (key > imid) { + min = mid + 1; + } else { + return fields[mid]; + } + } + //if not found, it's definitely an error + throw "Field not found for hash " + key; + } + + public static function hash(s:String):Int + { + if (s == null) return 0; + + var key = doHash(s); + + //start of binary search algorithm + var ids = fieldIds, + fld = fields; + var min = 0; + var max = length; + + var len = length; + + while (min < max) + { + var mid = Std.int(min + (max - min) / 2); //overflow safe + var imid = ids[mid]; + if (key < imid) + { + max = mid; + } else if (key > imid) { + min = mid + 1; + } else { + var field = fld[mid]; + if (field != s) + return ~key; //special case + return key; + } + } + + //if not found, min holds the value where we should insert the key + //ensure thread safety: + cs.Lib.lock(FieldLookup, { + if (len != length) //race condition which will very rarely happen - other thread modified sooner. + return hash(s); //since we already own the lock, this second try will always succeed + +#if erase_generics + fieldIds = insertInt(fieldIds, length, min, key); + fields = insertString(fields, length, min, s); +#else + insert(fieldIds, length, min, key); + insert(fields, length, min, s); + // ids.insert(min, key); + // fields.insert(min, s); +#end + ++length; + }); + return key; + } + + public static function findHash(hash:Int, hashs:cs.NativeArray, length:Int):Int + { + var min = 0; + var max = length; + + while (min < max) + { + var mid = Std.int((max + min) / 2); //overflow safe + var imid = hashs[mid]; + if (hash < imid) + { + max = mid; + } else if (hash > imid) { + min = mid + 1; + } else { + return mid; + } + } + //if not found, return a negative value of where it should be inserted + return ~min; + } + + #if !erase_generics + static function remove(a:cs.NativeArray, length:Int, pos:Int) + { + cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = null; + } + + static function insert(a:cs.Ref>, length:Int, pos:Int, x:T) + { + var capacity = a.Length; + if (pos == length) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + a.CopyTo(newarr, 0); + a = newarr; + } + } + else if (pos == 0) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + cs.system.Array.Copy(a, 0, newarr, 1, length); + a = newarr; + } + else + { + cs.system.Array.Copy(a, 0, a, 1, length); + } + } + else + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + cs.system.Array.Copy(a, 0, newarr, 0, pos); + cs.system.Array.Copy(a, pos, newarr, pos + 1, length - pos); + a = newarr; + } + else + { + cs.system.Array.Copy(a, pos, a, pos + 1, length - pos); + cs.system.Array.Copy(a, 0, a, 0, pos); + } + } + a[pos] = x; + } + #else + static function removeInt(a:cs.NativeArray, length:Int, pos:Int) + { + cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = 0; + } + static function removeFloat(a:cs.NativeArray, length:Int, pos:Int) + { + cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = 0; + } + static function removeDynamic(a:cs.NativeArray, length:Int, pos:Int) + { + cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = null; + } + + @:extern + static inline function __insert(a:cs.NativeArray, length:Int, pos:Int, x:T):cs.NativeArray + { + var capacity = a.Length; + if (pos == length) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + a.CopyTo(newarr, 0); + a = newarr; + } + } + else if (pos == 0) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + cs.system.Array.Copy(a, 0, newarr, 1, length); + a = newarr; + } + else + { + cs.system.Array.Copy(a, 0, a, 1, length); + } + } + else + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + cs.system.Array.Copy(a, 0, newarr, 0, pos); + cs.system.Array.Copy(a, pos, newarr, pos + 1, length - pos); + a = newarr; + } + else + { + cs.system.Array.Copy(a, pos, a, pos + 1, length - pos); + cs.system.Array.Copy(a, 0, a, 0, pos); + } + } + a[pos] = x; + return a; + } + + static function insertInt(a:cs.NativeArray, length:Int, pos:Int, x:Int):cs.NativeArray return __insert(a, length, pos, x); + static function insertFloat(a:cs.NativeArray, length:Int, pos:Int, x:Float):cs.NativeArray return __insert(a, length, pos, x); + static function insertDynamic(a:cs.NativeArray, length:Int, pos:Int, x:Dynamic):cs.NativeArray return __insert(a, length, pos, x); + static function insertString(a:cs.NativeArray, length:Int, pos:Int, x:Dynamic):cs.NativeArray return __insert(a, length, pos, x); + #end +} diff --git a/std/cs/internal/Function.hx b/std/cs/internal/Function.hx index 3f38c09a98af185d1af23945626ccb80d8af7e33..abfadac6a9b14ba80d794e6ab84c069ec4383480 100644 --- a/std/cs/internal/Function.hx +++ b/std/cs/internal/Function.hx @@ -1,81 +1,94 @@ -/* - * Copyright (C)2005-2012 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 cs.internal; - -/** - These classes are automatically generated by the compiler. They are only - here so there is an option for e.g. defining them as externs if you are compiling - in modules (untested). -**/ - -@:keep @:abstract @:nativeGen @:native("haxe.lang.Function") private class Function -{ - function new(arity:Int, type:Int) - { - - } -} - -@:keep @:nativeGen @:native("haxe.lang.VarArgsBase") private class VarArgsBase extends Function -{ - public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - throw "Abstract implementation"; - return null; - } -} - -@:keep @:nativeGen @:native('haxe.lang.VarArgsFunction') class VarArgsFunction extends VarArgsBase -{ - private var fun:Array->Dynamic; - - public function new(fun) - { - super(-1, -1); - this.fun = fun; - } - - override public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - return fun(dynArgs); - } -} - -@:keep @:nativeGen @:native('haxe.lang.Closure') class Closure extends VarArgsBase -{ - private var obj:Dynamic; - private var field:String; - private var hash:Int; - - public function new(obj:Dynamic, field, hash) - { - super(-1, -1); - this.obj = obj; - this.field = field; - this.hash = hash; - } - - override public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - return Runtime.callField(obj, field, hash, dynArgs); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs.internal; + +/** + These classes are automatically generated by the compiler. They are only + here so there is an option for e.g. defining them as externs if you are compiling + in modules (untested). +**/ + +@:keep @:abstract @:nativeGen @:native("haxe.lang.Function") class Function +{ + function new(arity:Int, type:Int) + { + + } +} + +@:keep @:nativeGen @:native("haxe.lang.VarArgsBase") private class VarArgsBase extends Function +{ + public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + throw "Abstract implementation"; + } +} + +@:keep @:nativeGen @:native('haxe.lang.VarArgsFunction') class VarArgsFunction extends VarArgsBase +{ + private var fun:Array->Dynamic; + + public function new(fun) + { + super(-1, -1); + this.fun = fun; + } + + override public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + return fun(dynArgs); + } +} + +@:keep @:nativeGen @:native('haxe.lang.Closure') class Closure extends VarArgsBase +{ + private var obj:Dynamic; + private var field:String; + private var hash:Int; + + public function new(obj:Dynamic, field, hash) + { + super(-1, -1); + this.obj = obj; + this.field = field; + this.hash = hash; + } + + override public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + return Runtime.callField(obj, field, hash, dynArgs); + } + + public function Equals(obj:Dynamic):Bool + { + if (obj == null) + return false; + + var c:Closure = cast obj; + return (c.obj == this.obj && c.field == this.field); + } + + public function GetHashCode():Int + { + return obj.GetHashCode() ^ untyped field.GetHashCode(); + } +} diff --git a/std/cs/internal/HxObject.hx b/std/cs/internal/HxObject.hx index d49a8f1326d6bd85ba3ad5d17526bbae1409658a..2a91688a964a5ae65d038d15d8a4235540067040 100644 --- a/std/cs/internal/HxObject.hx +++ b/std/cs/internal/HxObject.hx @@ -21,20 +21,24 @@ */ package cs.internal; import cs.system.Type; +import haxe.ds.Vector; private typedef StdType = std.Type; @:keep @:native('haxe.lang.HxObject') -private class HxObject implements IHxObject +class HxObject implements IHxObject { } @:keep @:native('haxe.lang.IHxObject') -private interface IHxObject +interface IHxObject { } +#if core_api_serialize +@:meta(System.Serializable) +#end @:keep @:native('haxe.lang.DynamicObject') -private class DynamicObject extends HxObject implements Dynamic +class DynamicObject extends HxObject implements Dynamic { @:skipReflection public function toString():String { @@ -60,28 +64,69 @@ private class DynamicObject extends HxObject implements Dynamic } } +#if !erase_generics @:keep @:native('haxe.lang.IGenericObject') interface IGenericObject { } -@:native('haxe.lang.Enum') -@:keep @:skipCtor -private class Enum +@:nativeGen @:keep @:native('haxe.lang.GenericInterface') class GenericInterface extends cs.system.Attribute { - @:readOnly private var index:Int; - @:readOnly private var params:Array<{}>; + @:readOnly public var generic(default,never):cs.system.Type; - public function new(index:Int, params:Array<{}>) + public function new(generic) { - this.index = index; - this.params = params; + super(); + untyped this.generic = generic; } - @:final public function getTag():String +} +#end + +@:keep @:native('haxe.lang.Enum') @:nativeGen +#if core_api_serialize +@:meta(System.Serializable) +#end +class HxEnum +{ + @:readOnly private var index(default,never):Int; + + public function new(index:Int) + { + untyped this.index = index; + } + + public function getTag():String + { + return throw 'Not Implemented'; + } + + public function getParams():Array<{}> { - var cl:Dynamic = StdType.getClass(this); - return cl.constructs[index]; + return []; } + public function toString():String + { + return getTag(); + } +} + +@:keep @:native('haxe.lang.ParamEnum') @:nativeGen +private class ParamEnum extends HxEnum +{ + @:readOnly private var params(default,never):Vector; + + public function new(index:Int, params:Vector) + { + super(index); + untyped this.params = params; + } + + override public function getParams():Array<{}> + { + return params == null ? [] : cs.Lib.array(cast params.toData()); + } + + override public function toString():String { if (params == null || params.length == 0) return getTag(); var ret = new StringBuf(); @@ -98,11 +143,12 @@ private class Enum ret.add(")"); return ret.toString(); } + public function Equals(obj:Dynamic) { if (obj == this) //we cannot use == as .Equals ! return true; - var obj:Enum = cast obj; + var obj:ParamEnum = Std.instance(obj, ParamEnum); var ret = obj != null && Std.is(obj, StdType.getClass(this)) && obj.index == this.index; if (!ret) return false; @@ -121,12 +167,12 @@ private class Enum public function GetHashCode():Int { - var h = 19; + var h:Int = 19; if (params != null) for (p in params) { h = h * 31; if (p != null) - h += untyped p.GetHashCode(); + untyped h += p.GetHashCode(); } h += index; return h; diff --git a/std/cs/internal/Iterator.hx b/std/cs/internal/Iterator.hx index a56e0719097e98a8cef83bc20e610102bde61579..9b63d3275a6aeae552a132e2180ad7a2902ceaae 100644 --- a/std/cs/internal/Iterator.hx +++ b/std/cs/internal/Iterator.hx @@ -1,38 +1,38 @@ -/* - * Copyright (C)2005-2012 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 cs.internal; - -@:keep @:native('haxe.lang.Iterator') interface Iterator -{ - - public function hasNext():Bool; - - public function next():T; - -} - -@:keep @:native('haxe.lang.Iterable') interface Iterable -{ - - public function iterator():Iterator; - +/* + * Copyright (C)2005-2012 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 cs.internal; + +@:keep @:native('haxe.lang.Iterator') interface Iterator +{ + + public function hasNext():Bool; + + public function next():T; + +} + +@:keep @:native('haxe.lang.Iterable') interface Iterable +{ + + public function iterator():Iterator; + } \ No newline at end of file diff --git a/std/cs/internal/Null.hx b/std/cs/internal/Null.hx index e562d0ffe85075d7a7ba6cc192bf079b3825239e..3fa19e2e24487b05707e91d2f7a5ac6fa4af98c3 100644 --- a/std/cs/internal/Null.hx +++ b/std/cs/internal/Null.hx @@ -21,6 +21,14 @@ */ package cs.internal; +@:classCode(' + static public readonly System.Type Type = typeof(T); + static public readonly bool IsValueType = haxe.lang.NullMetadata.Type.IsValueType; +') +@:keep @:nativeGen @:native("haxe.lang.NullMetadata") private class NullMetadata +{ +} + @:classCode(' //This function is here to be used with Reflection, when the haxe.lang.Null type is known public static haxe.lang.Null _ofDynamic(object obj) @@ -37,14 +45,17 @@ package cs.internal; } } ') +#if core_api_serialize +@:meta(System.Serializable) +#end @:keep @:struct @:nativeGen @:native("haxe.lang.Null") private class Nullable { - @:readOnly public var value:T; - @:readOnly public var hasValue:Bool; + @:readOnly public var value(default,never):T; + @:readOnly public var hasValue(default,never):Bool; @:functionCode(' - if ( !(v is System.ValueType) && System.Object.ReferenceEquals(v, default(T))) + if (!haxe.lang.NullMetadata.IsValueType && System.Object.ReferenceEquals(v, default(T))) { hasValue = false; } @@ -54,8 +65,8 @@ package cs.internal; ') public function new(v:T, hasValue:Bool) { - this.value = v; - this.hasValue = hasValue; + untyped this.value = v; + untyped this.hasValue = hasValue; } @:functionCode(' @@ -84,4 +95,4 @@ package cs.internal; { return null; } -} \ No newline at end of file +} diff --git a/std/cs/internal/Runtime.hx b/std/cs/internal/Runtime.hx index f9510ee2a0f66a8886282b42aabac5f213115f83..b4be8bcb9070453b9d755788bfdbf9e6379bab9a 100644 --- a/std/cs/internal/Runtime.hx +++ b/std/cs/internal/Runtime.hx @@ -21,13 +21,17 @@ */ package cs.internal; import cs.Lib; +import cs.Lib.*; import cs.NativeArray; import cs.NativeArray; import cs.system.Activator; import cs.system.IConvertible; +import cs.system.IComparable; import cs.system.reflection.MethodBase; import cs.system.reflection.MethodInfo; +import cs.system.reflection.*; import cs.system.Type; +import cs.system.Object; /** This class is meant for internal compiler use only. It provides the Haxe runtime @@ -36,6 +40,7 @@ import cs.system.Type; @:nativeGen @:native('haxe.lang.Runtime') +@:access(String) @:classCode(' public static object getField(haxe.lang.HxObject obj, string field, int fieldHash, bool throwErrors) { @@ -66,355 +71,353 @@ import cs.system.Type; ') @:keep class Runtime { - public static var undefined(default, never):Dynamic = { }; + @:readOnly public static var undefined(default, never):Dynamic = new cs.system.Object(); - @:functionCode(' - return new haxe.lang.Closure(obj, field, hash); - ') public static function closure(obj:Dynamic, hash:Int, field:String):Dynamic { - return null; + return new cs.internal.Function.Closure(obj, field, hash); } - @:functionCode(' - if (System.Object.ReferenceEquals(v1, v2)) - return true; - if (v1 == null || v2 == null) - return false; - - System.IConvertible v1c = v1 as System.IConvertible; + public static function eq(v1:Dynamic, v2:Dynamic):Bool + { + if (Object.ReferenceEquals(v1, v2)) + return true; + if (Object.ReferenceEquals(v1,null) || Object.ReferenceEquals(v2,null)) + return false; - if (v1c != null) + var v1c = Lib.as(v1, IConvertible); + if (v1c != null) + { + var v2c = Lib.as(v2, IConvertible); + if (v2c == null) { - System.IConvertible v2c = v2 as System.IConvertible; + return false; + } - if (v2c == null) - { - return false; - } + var t1 = v1c.GetTypeCode(), + t2 = v2c.GetTypeCode(); + if (t1 == t2) + return Object._Equals(v1c,v2c); - System.TypeCode t1 = v1c.GetTypeCode(); - System.TypeCode t2 = v2c.GetTypeCode(); - if (t1 == t2) - return v1c.Equals(v2c); + if (t1 == cs.system.TypeCode.String || t2 == cs.system.TypeCode.String) + return false; - switch(t1) - { - case System.TypeCode.Int64: - case System.TypeCode.UInt64: - return v1c.ToUInt64(null) == v2c.ToUInt64(null); - default: - return v1c.ToDouble(null) == v2c.ToDouble(null); - } + switch [t1,t2] + { + case [Decimal, _] | [_, Decimal]: + return v1c.ToDecimal(null) == v2c.ToDecimal(null); + case [UInt64 | Int64 | DateTime, _] | [_, UInt64 | Int64 | DateTime]: + return v1c.ToUInt64(null) == v2c.ToUInt64(null); + case [Double | Single, _] | [_, Double | Single]: + return v1c.ToDouble(null) == v2c.ToDouble(null); + case _: + return v1c.ToInt32(null) == v2c.ToInt32(null); } + } - System.ValueType v1v = v1 as System.ValueType; - if (v1v != null) + var v1v = Lib.as(v1, cs.system.ValueType); + if (v1v != null) + { + return v1.Equals(v2); +#if !erase_generics + } else { + var v1t = Lib.as(v1, Type); + if (v1t != null) { - return v1.Equals(v2); - } else { - System.Type v1t = v1 as System.Type; - if (v1t != null) - { - System.Type v2t = v2 as System.Type; - if (v2t != null) - return typeEq(v1t, v2t); - return false; - } + var v2t = Lib.as(v2, Type); + if (v2t != null) + return typeEq(v1t, v2t); + return false; } +#end + } - return false; - ') - public static function eq(v1:Dynamic, v2:Dynamic):Bool - { return false; } - @:functionCode(' - if (v1 is System.Type) - return typeEq(v1 as System.Type, v2 as System.Type); - return System.Object.ReferenceEquals(v1, v2); - ') public static function refEq(v1: { }, v2: { } ):Bool { - return false; +#if !erase_generics + if (Std.is(v1, Type)) + return typeEq(Lib.as(v1,Type), Lib.as(v2,Type)); +#end + return Object.ReferenceEquals(v1,v2); } - @:functionCode(' - return (obj == null) ? 0.0 : (obj is double) ? (double)obj : ((System.IConvertible) obj).ToDouble(null); - ') public static function toDouble(obj:Dynamic):Float { - return 0.0; + return (obj == null) ? .0 : Std.is(obj,Float) ? cast obj : Lib.as(obj,IConvertible).ToDouble(null); } - @:functionCode(' - return (obj == null) ? 0 : (obj is int) ? (int)obj : ((System.IConvertible) obj).ToInt32(null); - ') public static function toInt(obj:Dynamic):Int { - return 0; + return (obj == null) ? 0 : Std.is(obj,Int) ? cast obj : Lib.as(obj,IConvertible).ToInt32(null); } - @:functionCode(' - System.IConvertible cv1 = obj as System.IConvertible; - if (cv1 != null) - { - switch (cv1.GetTypeCode()) - { - case System.TypeCode.Double: - double d = (double)obj; - - return d >= int.MinValue && d <= int.MaxValue && d == ( (int)d ); - case System.TypeCode.UInt32: - case System.TypeCode.Int32: - return true; - default: - return false; - } - - } - return false; - ') public static function isInt(obj:Dynamic):Bool { + var cv1 = Lib.as(obj, IConvertible); + if (cv1 != null) + { + switch (cv1.GetTypeCode()) + { + case Double: + var d:Float = cast obj; + return d >= cs.system.Int32.MinValue && d <= cs.system.Int32.MaxValue && d == ( cast(d,Int) ); + case UInt32, Int32: + return true; + default: + return false; + } + } return false; } - @:functionCode(' - if (v1 == v2) return 0; - if (v1 == null) return -1; - if (v2 == null) return 1; - System.IConvertible cv1 = v1 as System.IConvertible; - if (cv1 != null) + public static function isUInt(obj:Dynamic):Bool + { + var cv1 = Lib.as(obj, IConvertible); + if (cv1 != null) + { + switch (cv1.GetTypeCode()) { - System.IConvertible cv2 = v2 as System.IConvertible; - - if (cv2 == null) - { - throw new System.ArgumentException("Cannot compare " + v1.GetType().ToString() + " and " + v2.GetType().ToString()); - } + case Double: + var d:Float = cast obj; + return d >= cs.system.UInt32.MinValue && d <= cs.system.UInt32.MaxValue && d == ( cast(d,UInt) ); + case UInt32: + return true; + default: + return false; + } - switch(cv1.GetTypeCode()) - { - case System.TypeCode.String: - if (cv2.GetTypeCode() != System.TypeCode.String) - throw new System.ArgumentException("Cannot compare " + v1.GetType().ToString() + " and " + v2.GetType().ToString()); - string s1 = v1 as string; - string s2 = v2 as string; - int i =0; - int l1 = s1.Length; - int l2 = s2.Length; - bool active = true; - while(active) - { - char h1; char h2; - if (i >= l1) - { - h1 = (char) 0; - active = false; - } else { - h1 = s1[i]; - } - - if (i >= l2) - { - h2 = (char) 0; - active = false; - } else { - h2 = s2[i]; - } - - int v = h1 - h2; - if (v > 0) - return 1; - else if (v < 0) - return -1; - - i++; - } - return 0; - case System.TypeCode.Double: - double d1 = (double) v1; - double d2 = cv2.ToDouble(null); + } + return false; + } - if (double.IsInfinity(d1) || double.IsInfinity(d2)) - return (d1 < d2) ? -1 : (d1 > d2) ? 1 : 0; - else - return (int) (d1 - d2); - default: - return ((int) (cv1.ToDouble(null) - cv2.ToDouble(null))); - } - } + public static function compare(v1:Dynamic, v2:Dynamic):Int + { + if (Object.ReferenceEquals(v1,v2)) return 0; + if (Object.ReferenceEquals(v1,null)) return -1; + if (Object.ReferenceEquals(v2,null)) return 1; - System.IComparable c1 = v1 as System.IComparable; - System.IComparable c2 = v2 as System.IComparable; + var cv1 = Lib.as(v1, IConvertible); + if (cv1 != null) + { + var cv2 = Lib.as(v2, IConvertible); - if (c1 == null || c2 == null) + if (cv2 == null) { - if (c1 == c2) - return 0; + throw new cs.system.ArgumentException("Cannot compare " + getNativeType(v1).ToString() + " and " + getNativeType(v2).ToString()); + } - throw new System.ArgumentException("Cannot compare " + v1.GetType().ToString() + " and " + v2.GetType().ToString()); + switch(cv1.GetTypeCode()) + { + case cs.system.TypeCode.String: + if (cv2.GetTypeCode() != cs.system.TypeCode.String) + throw new cs.system.ArgumentException("Cannot compare " + getNativeType(v1).ToString() + " and " + getNativeType(v2).ToString()); + var s1 = Lib.as(v1,String); + var s2 = Lib.as(v2,String); + return String.Compare(s1,s2, cs.system.StringComparison.Ordinal); + case cs.system.TypeCode.Double: + var d1:Float = cast v1, + d2:Float = cv2.ToDouble(null); + return (d1 < d2) ? -1 : (d1 > d2) ? 1 : 0; + default: + var d1d = cv1.ToDouble(null); + var d2d = cv2.ToDouble(null); + return (d1d < d2d) ? -1 : (d1d > d2d) ? 1 : 0; } + } - return c1.CompareTo(c2); - ') - public static function compare(v1:Dynamic, v2:Dynamic):Int - { - return 0; - } + var c1 = Lib.as(v1, IComparable); + var c2 = Lib.as(v2, IComparable); - @:functionCode(' - if (v1 is string || v2 is string) - return Std.@string(v1) + Std.@string(v2); + if (c1 == null || c2 == null) + { + throw new cs.system.ArgumentException("Cannot compare " + getNativeType(v1).ToString() + " and " + getNativeType(v2).ToString()); + } - System.IConvertible cv1 = v1 as System.IConvertible; - if (cv1 != null) - { - System.IConvertible cv2 = v2 as System.IConvertible; + return c1.CompareTo(c2); + } - if (cv2 == null) - { - throw new System.ArgumentException("Cannot dynamically add " + v1.GetType().ToString() + " and " + v2.GetType().ToString()); - } + public static function plus(v1:Dynamic, v2:Dynamic):Dynamic + { + if (Std.is(v1,String) || Std.is(v2,String)) + return Std.string(v1) + Std.string(v2); - return cv1.ToDouble(null) + cv2.ToDouble(null); + if (v1 == null) + { + if (v2 == null) return null; + v1 = 0; + } else if (v2 == null) v2 = 0; + + var cv1 = Lib.as(v1, IConvertible); + if (cv1 != null) + { + var cv2 = Lib.as(v2, IConvertible); + if (cv2 == null) + { + throw new cs.system.ArgumentException("Cannot dynamically add " + cs.Lib.getNativeType(v1).ToString() + " and " + cs.Lib.getNativeType(v2).ToString()); } + return cv1.ToDouble(null) + cv2.ToDouble(null); + } - throw new System.ArgumentException("Cannot dynamically add " + v1 + " and " + v2); - ') - public static function plus(v1:Dynamic, v2:Dynamic):Dynamic - { - return null; + throw new cs.system.ArgumentException("Cannot dynamically add " + v1 + " and " + v2); } - @:functionCode(' - + public static function slowGetField(obj:Dynamic, field:String, throwErrors:Bool):Dynamic + { if (obj == null) if (throwErrors) - throw new System.NullReferenceException("Cannot access field \'" + field + "\' of null."); + throw new cs.system.NullReferenceException("Cannot access field \'" + field + "\' of null."); else return null; - System.Type t = obj as System.Type; - System.Reflection.BindingFlags bf; - if (t == null) - { - string s = obj as string; - if (s != null) - return haxe.lang.StringRefl.handleGetField(s, field, throwErrors); - t = obj.GetType(); - bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy; - } else { - if (obj == typeof(string) && field.Equals("fromCharCode")) - return new haxe.lang.Closure(typeof(haxe.lang.StringExt), field, 0); + var t = Lib.as(obj, cs.system.Type); + var bf = + if (t == null) + { + var s = Lib.as(obj, String); + if (s != null) + return cs.internal.StringExt.StringRefl.handleGetField(s, field, throwErrors); + t = obj.GetType(); + new cs.Flags(BindingFlags.Instance) | BindingFlags.Public | BindingFlags.FlattenHierarchy; + } else { + if (t == Lib.toNativeType(String) && field == "fromCharCode") + return new cs.internal.Function.Closure(StringExt, field, 0); - obj = null; - bf = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; - } + obj = null; + new cs.Flags(BindingFlags.Static) | BindingFlags.Public; + } - System.Reflection.FieldInfo f = t.GetField(field, bf); + var f = t.GetField(field, bf); if (f != null) { - return haxe.lang.Runtime.unbox(f.GetValue(obj)); - } else { - System.Reflection.PropertyInfo prop = t.GetProperty(field, bf); + return unbox(f.GetValue(obj)); + } + else + { + var prop = t.GetProperty(field, bf); if (prop == null) { - System.Reflection.MemberInfo[] m = t.GetMember(field, bf); + var m = t.GetMember(field, bf); + if (m.length == 0 && (field == "__get" || field == "__set")) + m = t.GetMember(field == "__get" ? "get_Item" : "set_Item", bf); + if (m.Length > 0) { - return new haxe.lang.Closure(obj != null ? obj : t, field, 0); - } else { + return new cs.internal.Function.Closure(obj != null ? obj : t, field, 0); + } + else + { + // COM object handling + if (t.IsCOMObject) + { + try + { + return t.InvokeMember(field, BindingFlags.GetProperty, null, obj, new cs.NativeArray(0)); + } + catch (e:cs.system.Exception) + { + //Closures of COM objects not supported currently + } + } + if (throwErrors) - throw HaxeException.wrap("Cannot access field \'" + field + "\'."); + throw "Cannot access field \'" + field + "\'."; else return null; } } - return haxe.lang.Runtime.unbox(prop.GetValue(obj, null)); + return unbox(prop.GetValue(obj, null)); } - - ') - public static function slowGetField(obj:Dynamic, field:String, throwErrors:Bool):Dynamic - { - return null; } - @:functionCode(' - if (obj == null) return false; - System.Type t = obj as System.Type; - System.Reflection.BindingFlags bf; - if (t == null) - { - string s = obj as string; - if (s != null) - return haxe.lang.StringRefl.handleGetField(s, field, false) != null; - t = obj.GetType(); - bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy; - } else { - if (t == typeof(string)) - return field.Equals("fromCharCode"); - obj = null; - bf = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; - } - - System.Reflection.MemberInfo[] mi = t.GetMember(field, bf); - return mi != null && mi.Length > 0; - ') public static function slowHasField(obj:Dynamic, field:String):Bool { - return false; + if (obj == null) return false; + var t = Lib.as(obj, cs.system.Type); + var bf = + if (t == null) { + var s = Lib.as(obj, String); + if (s != null) + return cs.internal.StringExt.StringRefl.handleGetField(s, field, false) != null; + t = obj.GetType(); + new cs.Flags(BindingFlags.Instance) | BindingFlags.Public | BindingFlags.FlattenHierarchy; + } else { + if (t == Lib.toNativeType(String)) + return field == "fromCharCode"; + obj = null; + new cs.Flags(BindingFlags.Static) | BindingFlags.Public; + } + var mi = t.GetMember(field, bf); + return mi != null && mi.length > 0; } - @:functionCode(' + public static function slowSetField(obj:Dynamic, field:String, value:Dynamic):Dynamic + { if (obj == null) - throw new System.NullReferenceException("Cannot access field \'" + field + "\' of null."); + throw new cs.system.NullReferenceException("Cannot access field \'" + field + "\' of null."); - System.Type t = obj as System.Type; - System.Reflection.BindingFlags bf; - if (t == null) - { - t = obj.GetType(); - bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy; - } else { - obj = null; - bf = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; - } + var t = Lib.as(obj, cs.system.Type); + var bf = + if (t == null) + { + t = obj.GetType(); + new cs.Flags(BindingFlags.Instance) | BindingFlags.Public | BindingFlags.FlattenHierarchy; + } else { + obj = null; + new cs.Flags(BindingFlags.Static) | BindingFlags.Public; + } - System.Reflection.FieldInfo f = t.GetField(field, bf); + var f = t.GetField(field, bf); if (f != null) { if (f.FieldType.ToString().StartsWith("haxe.lang.Null")) { - @value = haxe.lang.Runtime.mkNullable(@value, f.FieldType); + value = mkNullable(value, f.FieldType); + } + if (Object.ReferenceEquals(Lib.toNativeType(cs.system.Double), Lib.getNativeType(value)) && !Object.ReferenceEquals(t, f.FieldType)) + { + var ic = Lib.as(value, IConvertible); + value = ic.ToType(f.FieldType, null); } - f.SetValue(obj, @value); - return @value; - } else { - System.Reflection.PropertyInfo prop = t.GetProperty(field, bf); + f.SetValue(obj, value); + return value; + } + else + { + var prop = t.GetProperty(field, bf); if (prop == null) { - throw haxe.lang.HaxeException.wrap("Field \'" + field + "\' not found for writing from Class " + t); + // COM object handling + if (t.IsCOMObject) + { + try + { + return t.InvokeMember(field, BindingFlags.SetProperty, null, obj, cs.NativeArray.make(value)); + } + catch (e:cs.system.Exception) + { + //Closures of COM objects not supported currently + } + } + throw "Field \'" + field + "\' not found for writing from Class " + t; } if (prop.PropertyType.ToString().StartsWith("haxe.lang.Null")) { - @value = haxe.lang.Runtime.mkNullable(@value, prop.PropertyType); + value = mkNullable(value, prop.PropertyType); + } + if (Object.ReferenceEquals(Lib.toNativeType(cs.system.Double), Lib.getNativeType(value)) && !Object.ReferenceEquals(t, f.FieldType)) + { + var ic = Lib.as(value, IConvertible); + value = ic.ToType(f.FieldType, null); } - prop.SetValue(obj, @value, null); + prop.SetValue(obj, value, null); - return @value; + return value; } - - ') - public static function slowSetField(obj:Dynamic, field:String, value:Dynamic):Dynamic - { - //not implemented yet; - throw "Not implemented"; - return null; } public static function callMethod(obj:Dynamic, methods:NativeArray, methodLength:Int, args:Array):Dynamic @@ -422,14 +425,14 @@ import cs.system.Type; if (methodLength == 0) throw "No available methods"; var length = args.length; var oargs:NativeArray = new NativeArray(length); - var ts:NativeArray = new NativeArray(length); + var ts:NativeArray = new NativeArray(length); var rates:NativeArray = new NativeArray(methods.Length); for (i in 0...length) { oargs[i] = args[i]; if (args[i] != null) - ts[i] = Lib.nativeType(args[i]); + ts[i] = Lib.getNativeType(args[i]); } var last = 0; @@ -448,7 +451,7 @@ import cs.system.Type; { var param = params[i].ParameterType; var strParam = param + ""; - if (param.IsAssignableFrom(ts[i])) + if (param.IsAssignableFrom(ts[i]) || (ts[i] == null && !param.IsValueType)) { //if it is directly assignable, we'll give it top rate continue; @@ -484,7 +487,7 @@ import cs.system.Type; if (methodLength == 0) throw "Invalid calling parameters for method " + methods[0].Name; - var best = Math.POSITIVE_INFINITY; + var best = cs.system.Double.PositiveInfinity; var bestMethod = 0; for(i in 0...methodLength) { @@ -500,16 +503,17 @@ import cs.system.Type; for (i in 0...params.Length) { var param = params[i].ParameterType; - var strParam = param + ""; + var strParam = param + "", + arg = oargs[i]; if (StringTools.startsWith(strParam, "haxe.lang.Null")) { - oargs[i] = mkNullable(oargs[i], param); + oargs[i] = mkNullable(arg, param); } else if (cast(untyped __typeof__(IConvertible), Type).IsAssignableFrom(param)) { - if (oargs[i] == null) { + if (arg == null) { if (param.IsValueType) oargs[i] = Activator.CreateInstance(param); - } else { - oargs[i] = cast(oargs[i], IConvertible).ToType(param, null); + } else if (!cs.Lib.getNativeType(arg).IsAssignableFrom(param)) { + oargs[i] = cast(arg, IConvertible).ToType(param, null); } } } @@ -540,7 +544,7 @@ import cs.system.Type; public static function unbox(dyn:Dynamic):Dynamic { - if (dyn != null && untyped (Lib.nativeType(dyn) + "").StartsWith("haxe.lang.Null")) + if (dyn != null && untyped (Lib.getNativeType(dyn) + "").StartsWith("haxe.lang.Null")) { return dyn.toDynamic(); } else { @@ -548,130 +552,195 @@ import cs.system.Type; } } +#if !erase_generics @:functionCode(' if (nullableType.ContainsGenericParameters) return haxe.lang.Null.ofDynamic(obj); return nullableType.GetMethod("_ofDynamic").Invoke(null, new object[] { obj }); ') - public static function mkNullable(obj:Dynamic, nullableType:cs.system.Type):Dynamic + public static function mkNullable(obj:Dynamic, nullableType:Type):Dynamic { return null; } - - @:functionCode(' - if (field == "toString") +#else + public static function mkNullable(obj:Dynamic, nullable:Type):Dynamic + { + return obj; //do nothing + } +#end + + // @:functionCode(' + // if (field == "toString") + // { + // if (args == null) + // return obj.ToString(); + // field = "ToString"; + // } + // if (args == null) args = new Array(); + + // System.Reflection.BindingFlags bf; + // System.Type t = obj as System.Type; + // if (t == null) + // { + // string s = obj as string; + // if (s != null) + // return haxe.lang.StringRefl.handleCallField(s, field, args); + // t = obj.GetType(); + // bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy; + // } else { + // if (t == typeof(string) && field.Equals("fromCharCode")) + // return haxe.lang.StringExt.fromCharCode(toInt(args[0])); + // obj = null; + // bf = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; + // } + + // System.Reflection.MethodInfo[] mis = t.GetMethods(bf); + // int last = 0; + // for (int i = 0; i < mis.Length; i++) + // { + // string name = mis[i].Name; + // if (name.Equals(field)) + // { + // mis[last++] = mis[i]; + // } + // } + + // if (last == 0 && (field == "__get" || field == "__set")) + // { + // field = field == "__get" ? "get_Item" : "set_Item"; + // for (int i = 0; i < mis.Length; i++) + // { + // string name = mis[i].Name; + // if (name.Equals(field)) + // { + // mis[last++] = mis[i]; + // } + // } + // } + + // if (last == 0 && t.IsCOMObject) + // { + // object[] oargs = new object[arrLen(args)]; + // for (int i = 0; i < oargs.Length; i++) + // { + // oargs[i] = args[i]; + // } + // return t.InvokeMember(field, System.Reflection.BindingFlags.InvokeMethod, null, obj, oargs); + // } + + // if (last == 0) + // { + // throw haxe.lang.HaxeException.wrap("Method \'" + field + "\' not found on type " + t); + // } + + // return haxe.lang.Runtime.callMethod(obj, mis, last, args); + // ') + public static function slowCallField(obj:Dynamic, field:String, args:Array):Dynamic + { + if (field == "toString" && (args == null || args.length == 0)) { - if (args == null) - return obj.ToString(); - field = "ToString"; + return obj.ToString(); } - if (args == null) args = new Array(); + if (args == null) args = []; - System.Reflection.BindingFlags bf; - System.Type t = obj as System.Type; + var bf:BindingFlags; + var t = Lib.as(obj,cs.system.Type); if (t == null) { - string s = obj as string; + var s = Lib.as(obj,String); if (s != null) - return haxe.lang.StringRefl.handleCallField(s, field, args); - t = obj.GetType(); - bf = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy; + return cs.internal.StringExt.StringRefl.handleCallField(untyped s, untyped field, args); + t = untyped obj.GetType(); + bf = new Flags(BindingFlags.Instance) | BindingFlags.Public | BindingFlags.FlattenHierarchy; } else { - if (t == typeof(string) && field.Equals("fromCharCode")) - return haxe.lang.StringExt.fromCharCode(toInt(args[0])); + if (t == Lib.toNativeType(String) && field == 'fromCharCode') + return cs.internal.StringExt.fromCharCode(toInt(args[0])); obj = null; - bf = System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public; + bf = new Flags(BindingFlags.Static) | BindingFlags.Public; } - System.Reflection.MethodInfo[] mis = t.GetMethods(bf); - int last = 0; - for (int i = 0; i < mis.Length; i++) + var mis:NativeArray = untyped t.GetMethods(bf); + var last = 0; + for (i in 0...mis.Length) { - if (mis[i].Name.Equals(field)) - { + var name = mis[i].Name; + if (name == field) mis[last++] = mis[i]; + } + + if (last == 0 && (field == "__get" || field == "__set")) + { + field = field == "__get" ? "get_Item" : "set_Item"; + for (i in 0...mis.Length) + { + var name = mis[i].Name; + if (name == field) + { + mis[last++] = mis[i]; + } } } + if (last == 0 && t.IsCOMObject) + { + var oargs = new NativeArray(args.length); + for (i in 0...oargs.Length) + { + oargs[i] = args[i]; + } + return t.InvokeMember(field, BindingFlags.InvokeMethod, null, obj, oargs); + } + if (last == 0) { - throw haxe.lang.HaxeException.wrap("Method \'" + field + "\' not found on type " + t); + throw 'Method "$field" not found on type $t'; } - return haxe.lang.Runtime.callMethod(obj, mis, last, args); - ') - public static function slowCallField(obj:Dynamic, field:String, args:Array):Dynamic - { - throw "not implemented"; - return null; + return Runtime.callMethod(obj, mis, last, args); } - @:functionCode(' - haxe.lang.HxObject hxObj = obj as haxe.lang.HxObject; - if (hxObj != null) - return hxObj.__hx_invokeField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, args); - - return slowCallField(obj, field, args); - ') public static function callField(obj:Dynamic, field:String, fieldHash:Int, args:Array):Dynamic { - return null; - } - - @:functionCode(' - - haxe.lang.HxObject hxObj = obj as haxe.lang.HxObject; + var hxObj = Lib.as(obj, HxObject); if (hxObj != null) - return hxObj.__hx_getField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, throwErrors, false, false); - - return slowGetField(obj, field, throwErrors); + return untyped hxObj.__hx_invokeField(field, (fieldHash == 0) ? FieldLookup.hash(field) : fieldHash, args); + return slowCallField(obj, field, args); + } - ') public static function getField(obj:Dynamic, field:String, fieldHash:Int, throwErrors:Bool):Dynamic { - return null; - } - - @:functionCode(' - - haxe.lang.HxObject hxObj = obj as haxe.lang.HxObject; + var hxObj = Lib.as(obj, HxObject); if (hxObj != null) - return hxObj.__hx_getField_f(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, throwErrors, false); + return untyped hxObj.__hx_getField(field, (fieldHash == 0) ? FieldLookup.hash(field) : fieldHash, throwErrors, false, false); - return (double)slowGetField(obj, field, throwErrors); + return slowGetField(obj, field, throwErrors); + } - ') public static function getField_f(obj:Dynamic, field:String, fieldHash:Int, throwErrors:Bool):Float { - return 0.0; - } - - @:functionCode(' - - haxe.lang.HxObject hxObj = obj as haxe.lang.HxObject; + var hxObj = Lib.as(obj, HxObject); if (hxObj != null) - return hxObj.__hx_setField(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, value, false); + return untyped hxObj.__hx_getField_f(field, (fieldHash == 0) ? FieldLookup.hash(field) : fieldHash, throwErrors, false); - return slowSetField(obj, field, value); + return toDouble(slowGetField(obj, field, throwErrors)); + } - ') public static function setField(obj:Dynamic, field:String, fieldHash:Int, value:Dynamic):Dynamic { - return null; - } - - @:functionCode(' - - haxe.lang.HxObject hxObj = obj as haxe.lang.HxObject; + var hxObj = Lib.as(obj, HxObject); if (hxObj != null) - return hxObj.__hx_setField_f(field, (fieldHash == 0) ? haxe.lang.FieldLookup.hash(field) : fieldHash, value, false); + return untyped hxObj.__hx_setField(field, (fieldHash == 0) ? FieldLookup.hash(field) : fieldHash, value, false); - return (double)slowSetField(obj, field, value); + return slowSetField(obj, field, value); + } - ') public static function setField_f(obj:Dynamic, field:String, fieldHash:Int, value:Float):Float { - return 0.0; + var hxObj = Lib.as(obj, HxObject); + if (hxObj != null) + return untyped hxObj.__hx_setField_f(field, (fieldHash == 0) ? FieldLookup.hash(field) : fieldHash, value, false); + + return toDouble(slowSetField(obj, field, value)); } public static function toString(obj:Dynamic):String @@ -687,19 +756,48 @@ import cs.system.Type; return untyped obj.ToString(); } - @:functionCode(' - if (t1 == null || t2 == null) - return t1 == t2; - string n1 = Type.getClassName(t1); - string n2 = Type.getClassName(t2); - return n1.Equals(n2); - ') - public static function typeEq(t1:cs.system.Type, t2:cs.system.Type):Bool +#if erase_generics + inline +#end + public static function typeEq(t1:Type, t2:Type):Bool { - return false; + if (t1 == null || t2 == null) + return t1 == t2; +#if !erase_generics + var t1i = t1.IsInterface, + t2i = t2.IsInterface; + if (t1i != t2i) + { + if (t1i) + { + var g = getGenericAttr(t1); + if (g != null) + t1 = g.generic; + } else { + var g = getGenericAttr(t2); + if (g != null) + t2 = g.generic; + } + } + +#end + if (t1.GetGenericArguments().Length > 0) t1 = t1.GetGenericTypeDefinition(); + if (t2.GetGenericArguments().Length > 0) t2 = t2.GetGenericTypeDefinition(); + return Object.ReferenceEquals(t1,t2); } +#if !erase_generics + private 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)) + return cast attr; + return null; + } +#end + +#if !erase_generics @:functionCode(' if (obj is To) return (To) obj; @@ -709,6 +807,10 @@ import cs.system.Type; return (To)(object) toDouble(obj); else if (typeof(To) == typeof(int)) return (To)(object) toInt(obj); + else if (typeof(To) == typeof(float)) + return (To)(object)(float)toDouble(obj); + else if (typeof(To) == typeof(long)) + return (To)(object)(long)toDouble(obj); else return (To) obj; ') @@ -716,6 +818,7 @@ import cs.system.Type; { return null; } +#end @:functionCode(' return (s1 == null ? "null" : s1) + (s2 == null ? "null" : s2); @@ -725,6 +828,11 @@ import cs.system.Type; return null; } + public static function toBool(dyn:Dynamic):Bool + { + return if (dyn == null) false else untyped __cs__("(bool){0}", dyn); + } + //TODO: change from genericCast to getConverter, so we don't need to handle extra boxing associated with it /*@:functionCode(' @@ -741,6 +849,7 @@ import cs.system.Type; }*/ } +@:nativeGen @:keep @:native("haxe.lang.EmptyObject") private enum EmptyObject { EMPTY; diff --git a/std/cs/internal/StringExt.hx b/std/cs/internal/StringExt.hx index 417b2ab054faa76c626c4cfae395b9220431c194..3d0b5b57ba1888289476aa6ba3774211ffeddeea 100644 --- a/std/cs/internal/StringExt.hx +++ b/std/cs/internal/StringExt.hx @@ -21,175 +21,158 @@ */ package cs.internal; import cs.internal.Function; -private typedef NativeString = String; +private typedef NativeString = cs.system.String; -@:keep @:nativeGen @:native("haxe.lang.StringExt") private class StringExt +@:keep @:nativeGen @:native("haxe.lang.StringExt") class StringExt { + @:readOnly static var empty(default,never) = new NativeString(cast 0,0); - @:functionCode(' - if ( ((uint) index) >= me.Length) - return ""; - else - return new string(me[index], 1); - ') public static function charAt(me:NativeString, index:Int):NativeString { - return null; + if (cast(index,UInt) >= me.Length) + return empty; + else + return new NativeString(me[index], 1); } - @:functionCode(' - if ( ((uint) index) >= me.Length) - return default(haxe.lang.Null); - else - return new haxe.lang.Null((int)me[index], true); - ') public static function charCodeAt(me:NativeString, index:Int):Null { - return null; + if (cast(index,UInt) >= me.Length) + return null; + else + return cast(me[index], Int); } - @:functionCode(' - uint sIndex = (startIndex.hasValue) ? ((uint) startIndex.@value) : 0; - if (sIndex >= me.Length) - return -1; - return me.IndexOf(str, (int)sIndex); - ') - public static function indexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int + public static function indexOf(me:NativeString, str:String, ?startIndex:Int):Int { - return -1; + var sIndex:Int = startIndex != null ? startIndex : 0; + if (sIndex >= me.Length) + return -1; + return @:privateAccess me.IndexOf(str, sIndex, cs.system.StringComparison.Ordinal); } - @:functionCode(' - int sIndex = (startIndex.hasValue) ? (startIndex.@value) : (me.Length - 1); - if (sIndex >= me.Length) - sIndex = me.Length - 1; - else if (sIndex < 0) - return -1; - - //TestBaseTypes.hx@133 fix - if (startIndex.hasValue) + public static function lastIndexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int + { + var sIndex:Int = startIndex == null ? me.Length - 1 : startIndex; + if (sIndex >= me.Length) + sIndex = me.Length - 1; + else if (sIndex < 0) + return -1; + + //TestBaseTypes.hx@133 fix + if (startIndex != null) + { + var i = sIndex + 1; + while (i --> 0) { - for(int i = sIndex; i >= 0; i--) + var found = true; + for (j in 0...str.Length) { - bool found = true; - for(int j = 0; j < str.Length; j++) + if(me[i + j] != str[j]) { - if(me[i + j] != str[j]) - { - found = false; - break; - } + found = false; + break; } - - if (found) - return i; } - return -1; - } else { - return me.LastIndexOf(str, sIndex); + if (found) + return i; } - ') - public static function lastIndexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int - { + + return -1; + } else { + return me.LastIndexOf(untyped str, sIndex, cs.system.StringComparison.Ordinal); + } return -1; } - @:functionCode(' - string[] native; - if (delimiter.Length == 0) - { - int len = me.Length; - native = new string[len]; - for (int i = 0; i < len; i++) - native[i] = new string(me[i], 1); - } else { - native = me.Split(new string[] { delimiter }, System.StringSplitOptions.None); - } - return new Array(native); - ') - public static function split(me:NativeString, delimiter:NativeString):Array + public static function split(me:NativeString, delimiter:NativeString):Array { - return null; + var native:NativeArray; + if (delimiter.Length == 0) + { + var len = me.Length; + native = new NativeArray(len); + for (i in 0...len) + native[i] = untyped new NativeString(me[i],1); + } else { + var str = new NativeArray(1); + str[0] = cast delimiter; + + native = me.Split(str, cs.system.StringSplitOptions.None); + } + + return cs.Lib.array(native); } - @:functionCode(' - int meLen = me.Length; - int targetLen = meLen; - if (len.hasValue) - { - targetLen = len.@value; - if (targetLen == 0) - return ""; - if( pos != 0 && targetLen < 0 ){ - return ""; - } - } + public static function substr(me:NativeString, pos:Int, ?len:Int):String + { + var meLen = me.Length; + var targetLen = meLen; + if (len != null) + { + targetLen = len; + if (targetLen == 0 || (pos != 0 && targetLen < 0)) + return ""; + } - if( pos < 0 ){ - pos = meLen + pos; - if( pos < 0 ) pos = 0; - } else if( targetLen < 0 ){ - targetLen = meLen + targetLen - pos; - } + if (pos < 0) + { + pos = meLen + pos; + if (pos < 0) pos = 0; + } else if (targetLen < 0) { + targetLen = meLen + targetLen - pos; + } - if( pos + targetLen > meLen ){ - targetLen = meLen - pos; - } + if (pos + targetLen > meLen) + { + targetLen = meLen - pos; + } - if ( pos < 0 || targetLen <= 0 ) return ""; + if (pos < 0 || targetLen <= 0) return ""; - return me.Substring(pos, targetLen); - ') - public static function substr(me:NativeString, pos:Int, ?len:Int):NativeString - { - return null; + return me.Substring(pos, targetLen); } - @:functionCode(' - int endIdx; - int len = me.Length; - if ( !endIndex.hasValue ) { + public static function substring(me:NativeString, startIndex:Int, ?endIndex:Int):String + { + var len = me.Length; + var endIdx:Int; + if (endIndex == null) endIdx = len; - } else if ( (endIdx = endIndex.@value) < 0 ) { + else if ( (endIdx = endIndex) < 0 ) endIdx = 0; - } else if ( endIdx > len ) { + else if (endIdx > len) endIdx = len; - } - if ( startIndex < 0 ) { + if (startIndex < 0) startIndex = 0; - } else if ( startIndex > len ) { + else if (startIndex > len) startIndex = len; - } - if ( startIndex > endIdx ) { - int tmp = startIndex; + if (startIndex > endIdx) + { + var tmp = startIndex; startIndex = endIdx; endIdx = tmp; } return me.Substring(startIndex, endIdx - startIndex); - ') - public static function substring(me:NativeString, startIndex:Int, ?endIndex:Int):NativeString + } + + public static function toString(me:NativeString):NativeString { - return null; + return me; } - @:functionCode(' - return me.ToLower(); - ') - public static function toLowerCase(me:NativeString):NativeString + public static function toLowerCase(me:NativeString):String { - return null; + return me.ToLowerInvariant(); } - @:functionCode(' - return me.ToUpper(); - ') - public static function toUpperCase(me:NativeString):NativeString + public static function toUpperCase(me:NativeString):String { - return null; + return me.ToUpperInvariant(); } public static function toNativeString(me:NativeString):NativeString @@ -197,20 +180,17 @@ private typedef NativeString = String; return me; } - @:functionCode(' - return new string( (char) code, 1 ); - ') public static function fromCharCode(code:Int):NativeString { - return null; + return new NativeString( cast(code,cs.StdTypes.Char16), 1 ); } } -@:keep @:nativeGen @:native('haxe.lang.StringRefl') private class StringRefl +@:keep @:nativeGen @:native('haxe.lang.StringRefl') class StringRefl { public static var fields = ["length", "toUpperCase", "toLowerCase", "charAt", "charCodeAt", "indexOf", "lastIndexOf", "split", "substr", "substring"]; - public static function handleGetField(str:NativeString, f:NativeString, throwErrors:Bool):Dynamic + public static function handleGetField(str:String, f:String, throwErrors:Bool):Dynamic { switch(f) { @@ -225,7 +205,7 @@ private typedef NativeString = String; } } - public static function handleCallField(str:NativeString, f:NativeString, args:Array):Dynamic + public static function handleCallField(str:NativeString, f:String, args:Array):Dynamic { var _args:Array = [str]; if (args == null) diff --git a/std/cs/io/NativeInput.hx b/std/cs/io/NativeInput.hx index d88710ee79c2c3da66118be2599672416f1dd438..08907e4a1568e9d5c7dc111c8173867cdba340fb 100644 --- a/std/cs/io/NativeInput.hx +++ b/std/cs/io/NativeInput.hx @@ -1,88 +1,97 @@ -/* - * Copyright (C)2005-2012 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 cs.io; -import haxe.Int64; -import haxe.io.Bytes; -import haxe.io.Eof; -import haxe.io.Error; -import haxe.io.Input; - -class NativeInput extends Input -{ - public var canSeek(get_canSeek, null):Bool; - - var stream:cs.system.io.Stream; - public function new(stream) - { - this.stream = stream; - if (!stream.CanRead) throw "Write-only stream"; - } - - override public function readByte():Int - { - var ret = stream.ReadByte(); - if (ret == -1) throw new Eof(); - return ret; - } - - 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); - if (ret == 0) - throw new Eof(); - return ret; - } - - override public function close():Void - { - stream.Close(); - } - - private function get_canSeek():Bool - { - return stream.CanSeek; - } - - public function seek( p : Int, pos : sys.io.FileSeek ) : Void - { - var p = switch(pos) - { - case SeekBegin: cs.system.io.SeekOrigin.Begin; - case SeekCur: cs.system.io.SeekOrigin.Current; - case SeekEnd: cs.system.io.SeekOrigin.End; - }; - - stream.Seek(cast(p, Int64), p); - } - - public function tell() : Int - { - return cast(stream.Position, Int); - } - - public function eof() : Bool - { - return stream.Position == stream.Length; - } +/* + * Copyright (C)2005-2012 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 cs.io; +import haxe.Int64; +import haxe.io.Bytes; +import haxe.io.Eof; +import haxe.io.Error; +import haxe.io.Input; + +class NativeInput extends Input +{ + public var canSeek(get_canSeek, null):Bool; + + var stream:cs.system.io.Stream; + var _eof:Bool; + + public function new(stream) + { + this.stream = stream; + this._eof = false; + if (!stream.CanRead) throw "Write-only stream"; + } + + override public function readByte():Int + { + var ret = stream.ReadByte(); + if (ret == -1) { + _eof = true; + throw new Eof(); + } + return ret; + } + + 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); + if (ret == 0) { + _eof = true; + throw new Eof(); + } + return ret; + } + + override public function close():Void + { + stream.Close(); + } + + private function get_canSeek():Bool + { + return stream.CanSeek; + } + + public function seek( p : Int, pos : sys.io.FileSeek ) : Void + { + _eof = false; + var pos = switch(pos) + { + case SeekBegin: cs.system.io.SeekOrigin.Begin; + case SeekCur: cs.system.io.SeekOrigin.Current; + case SeekEnd: cs.system.io.SeekOrigin.End; + }; + + stream.Seek(cast(p, Int64), pos); + } + + public function tell() : Int + { + return cast(stream.Position, Int); + } + + public inline function eof() : Bool + { + return _eof; + } } \ No newline at end of file diff --git a/std/cs/io/NativeOutput.hx b/std/cs/io/NativeOutput.hx index 87cc15373289c4f5a08b442e15f9064d34ac49ea..3fa5f822f8473e0d6efc28cd036f3fa2bf85ffdb 100644 --- a/std/cs/io/NativeOutput.hx +++ b/std/cs/io/NativeOutput.hx @@ -1,79 +1,79 @@ -/* - * Copyright (C)2005-2012 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 cs.io; -import haxe.Int64; -import haxe.io.Bytes; -import haxe.io.Output; - -class NativeOutput extends Output -{ - var canSeek(get_canSeek, null):Bool; - var stream:cs.system.io.Stream; - public function new(stream) - { - this.stream = stream; - if (!stream.CanWrite) throw "Read-only stream"; - } - - override public function writeByte(c:Int):Void - { - stream.WriteByte(c); - } - - override public function close():Void - { - stream.Close(); - } - - override public function flush():Void - { - stream.Flush(); - } - - override public function prepare(nbytes:Int):Void - { - //TODO see if implementation is correct - stream.SetLength(haxe.Int64.add(stream.Length, cast(nbytes, Int64))); - } - - private function get_canSeek():Bool - { - return stream.CanSeek; - } - - public function seek( p : Int, pos : sys.io.FileSeek ) : Void - { - var p = switch(pos) - { - case SeekBegin: cs.system.io.SeekOrigin.Begin; - case SeekCur: cs.system.io.SeekOrigin.Current; - case SeekEnd: cs.system.io.SeekOrigin.End; - }; - - stream.Seek(cast(p, Int64), p); - } - - public function tell() : Int - { - return cast(stream.Position, Int); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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 cs.io; +import haxe.Int64; +import haxe.io.Bytes; +import haxe.io.Output; + +class NativeOutput extends Output +{ + var canSeek(get_canSeek, null):Bool; + var stream:cs.system.io.Stream; + public function new(stream) + { + this.stream = stream; + if (!stream.CanWrite) throw "Read-only stream"; + } + + override public function writeByte(c:Int):Void + { + stream.WriteByte(cast c); + } + + override public function close():Void + { + stream.Close(); + } + + override public function flush():Void + { + stream.Flush(); + } + + override public function prepare(nbytes:Int):Void + { + //TODO see if implementation is correct + stream.SetLength(haxe.Int64.add(stream.Length, cast(nbytes, Int64))); + } + + private function get_canSeek():Bool + { + return stream.CanSeek; + } + + public function seek( p : Int, pos : sys.io.FileSeek ) : Void + { + var p = switch(pos) + { + case SeekBegin: cs.system.io.SeekOrigin.Begin; + case SeekCur: cs.system.io.SeekOrigin.Current; + case SeekEnd: cs.system.io.SeekOrigin.End; + }; + + stream.Seek(cast(p, Int64), p); + } + + public function tell() : Int + { + return cast(stream.Position, Int); + } +} diff --git a/std/cs/system/Math.hx b/std/cs/system/Math.hx deleted file mode 100644 index d5deffff6e5d05381a444d2703859b9820758cbf..0000000000000000000000000000000000000000 --- a/std/cs/system/Math.hx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system; - -@:native("System.Math") @:nativeGen extern class Math -{ - public static var PI(default, null) : Float; - - public static function Abs(v:Float):Float; - public static function Min(a:Float,b:Float):Float; - public static function Max(a:Float,b:Float):Float; - public static function Sin(v:Float):Float; - public static function Cos(v:Float):Float; - public static function Atan2(y:Float,x:Float):Float; - public static function Tan(v:Float):Float; - public static function Exp(v:Float):Float; - public static function Log(v:Float):Float; - public static function Sqrt(v:Float):Float; - public static function Round(v:Float):Float; - public static function Floor(v:Float):Float; - public static function Ceiling(v:Float):Float; - public static function Atan(v:Float):Float; - public static function Asin(v:Float):Float; - public static function Acos(v:Float):Float; - public static function Pow(v:Float,exp:Float):Float; -} \ No newline at end of file diff --git a/std/cs/system/collections/IEnumerable.hx b/std/cs/system/collections/IEnumerable.hx deleted file mode 100644 index cdda1bf8b1f1125be63f9774d553dce4b07315b0..0000000000000000000000000000000000000000 --- a/std/cs/system/collections/IEnumerable.hx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.collections; - -@:native('System.Collections.IEnumerable') extern interface IEnumerable -{ - function GetEnumerator():IEnumerator; -} \ No newline at end of file diff --git a/std/cs/system/collections/IEnumerator.hx b/std/cs/system/collections/IEnumerator.hx deleted file mode 100644 index 7a32cd787ecf6d4446e132d15091942aad131860..0000000000000000000000000000000000000000 --- a/std/cs/system/collections/IEnumerator.hx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.collections; - -@:native('System.Collections.IEnumerator') extern interface IEnumerator -{ - var Current(default, null):Dynamic; - function MoveNext():Bool; - function Reset():Void; -} \ No newline at end of file diff --git a/std/cs/system/io/Directory.hx b/std/cs/system/io/Directory.hx deleted file mode 100644 index 7dbd5bd34cf4a72b0cd10986e666f31a2a701a05..0000000000000000000000000000000000000000 --- a/std/cs/system/io/Directory.hx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; -import cs.NativeArray; -import cs.NativeArray; - -@:native('System.IO.Directory') extern class Directory -{ - static function CreateDirectory(path:String):Void; - static function Delete(path:String):Void; - static function Exists(path:String):Bool; - static function GetCurrentDirectory():String; - static function GetDirectories(path:String):NativeArray; - static function GetDirectoryRoot(path:String):String; - static function GetFiles(path:String):NativeArray; - static function GetFileSystemEntries(path:String):NativeArray; - static function GetCreationTime(path:String):cs.system.DateTime; - static function GetLastAccessTime(path:String):cs.system.DateTime; - static function GetLastWriteTime(path:String):cs.system.DateTime; - static function Move(path:String, newpath:String):Void; - static function SetCurrentDirectory(path:String):Void; -} \ No newline at end of file diff --git a/std/cs/system/io/File.hx b/std/cs/system/io/File.hx deleted file mode 100644 index 23726e228ad21658b112e90ccd97d1ea71f5fd27..0000000000000000000000000000000000000000 --- a/std/cs/system/io/File.hx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; - -@:native('System.IO.File') extern class File -{ - //not compatible with XNA - //static function AppendAllText(path:String, contents:String):Void; - static function Copy(source:String, dest:String):Void; - - @:overload(function(path:String, bufferSize:Int):FileStream {}) - static function Create(path:String):FileStream; - - static function Delete(path:String):Void; - static function Exists(path:String):Bool; - static function GetCreationTime(path:String):cs.system.DateTime; - static function GetLastAccessTime(path:String):cs.system.DateTime; - static function GetLastWriteTime(path:String):cs.system.DateTime; - static function Move(source:String, dest:String):Void; - - -} \ No newline at end of file diff --git a/std/cs/system/io/FileInfo.hx b/std/cs/system/io/FileInfo.hx deleted file mode 100644 index 1700ac46e8fb0aa2c6aa540000c6997d8b00e3cb..0000000000000000000000000000000000000000 --- a/std/cs/system/io/FileInfo.hx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; -import haxe.Int64; - -@:final @:native('System.IO.FileInfo') extern class FileInfo -{ - var Attributes(default, null):FileAttributes; - var CreationTime(default, null):cs.system.DateTime; - var Directory(default, null):DirectoryInfo; - var DirectoryName(default, null):String; - var Exists(default, null):Bool; - var Extension(default, null):String; - var FullName(default, null):String; - var LastAccessTime(default, null):cs.system.DateTime; - var LastWriteTime(default, null):cs.system.DateTime; - var Length(default, null):Int64; - var Name(default, null):String; - - function new(filename:String):Void; -} \ No newline at end of file diff --git a/std/cs/system/io/FileShare.hx b/std/cs/system/io/FileShare.hx deleted file mode 100644 index 11aef674525051fec6754171da52a7830831d031..0000000000000000000000000000000000000000 --- a/std/cs/system/io/FileShare.hx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; - -@:native('System.IO.FileShare') extern enum FileShare -{ - None; - Read; - Write; - ReadWrite; -} \ No newline at end of file diff --git a/std/cs/system/io/FileStream.hx b/std/cs/system/io/FileStream.hx deleted file mode 100644 index 77362b66abeb1933103f91e5c0c0ffc6c79fe82d..0000000000000000000000000000000000000000 --- a/std/cs/system/io/FileStream.hx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; - -@:native('System.IO.FileStream') extern class FileStream extends Stream -{ - @:overload(function (path:String, mode:FileMode, access:FileAccess, share:FileShare, bufferSize:Int, useAsync:Bool):Void {}) - @:overload(function (path:String, mode:FileMode, access:FileAccess, share:FileShare, bufferSize:Int):Void {}) - @:overload(function (path:String, mode:FileMode, access:FileAccess, share:FileShare):Void {}) - @:overload(function (path:String, mode:FileMode, access:FileAccess):Void {}) - function new(path:String, mode:FileMode):Void; - var IsAsync(default, null):Bool; - var Name(default, null):String; -} \ No newline at end of file diff --git a/std/cs/system/io/Stream.hx b/std/cs/system/io/Stream.hx deleted file mode 100644 index 1002e69faffc6e8ff2e33f536f515fa7c482a52b..0000000000000000000000000000000000000000 --- a/std/cs/system/io/Stream.hx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; -import cs.StdTypes; -import haxe.Int64; -import haxe.io.BytesData; - -@:native('System.IO.Stream') extern class Stream -{ - var CanRead(default, null):Bool; - var CanSeek(default, null):Bool; - var CanTimeout(default, null):Bool; - var CanWrite(default, null):Bool; - var Length(default, null):Int64; - var Position(default, null):Int64; - var ReadTimeout:Bool; - var WriteTimeout:Bool; - - function Close():Void; - function CopyTo(dest:Stream):Void; - function Dispose():Void; - function Flush():Void; - function Read(buf:BytesData, offset:Int, count:Int):Int; - function ReadByte():Int; - function Seek(offset:Int64, origin:SeekOrigin):Int64; - function SetLength(value:Int64):Void; - function Write(buf:BytesData, offset:Int, count:Int):Void; - function WriteByte(value:UInt8):Void; -} \ No newline at end of file diff --git a/std/cs/system/reflection/MethodBase.hx b/std/cs/system/reflection/MethodBase.hx deleted file mode 100644 index dbc7f2b0c951245b3f3904353ea8d1e567a36c07..0000000000000000000000000000000000000000 --- a/std/cs/system/reflection/MethodBase.hx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.reflection; -import cs.NativeArray; - -@:native('System.Reflection.MethodBase') extern class MethodBase -{ - var Name(default, null):String; - var ContainsGenericParameters(default, null):Bool; - function GetParameters():NativeArray; - function GetGenericArguments():NativeArray; - @:overload(function():Dynamic {}) - function Invoke(obj:Dynamic, args:NativeArray):Dynamic; -} \ No newline at end of file diff --git a/std/cs/system/reflection/MethodInfo.hx b/std/cs/system/reflection/MethodInfo.hx deleted file mode 100644 index a4c9ed547898cb7e3133c76410c936006471c55d..0000000000000000000000000000000000000000 --- a/std/cs/system/reflection/MethodInfo.hx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.reflection; -import cs.NativeArray; -import cs.NativeArray; -import cs.system.Type; - -@:native('System.Reflection.MethodInfo') extern class MethodInfo extends MethodBase -{ - function MakeGenericMethod(g:NativeArray):MethodInfo; -} \ No newline at end of file diff --git a/std/cs/system/reflection/ParameterInfo.hx b/std/cs/system/reflection/ParameterInfo.hx deleted file mode 100644 index e6449af8e8c3ab7283d9b6437176a60e93a77ef7..0000000000000000000000000000000000000000 --- a/std/cs/system/reflection/ParameterInfo.hx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.reflection; - -@:native('System.Reflection.ParameterInfo') extern class ParameterInfo -{ - var ParameterType(default, null):cs.system.Type; -} \ No newline at end of file diff --git a/std/cs/system/text/regularExpressions/Regex.hx b/std/cs/system/text/regularExpressions/Regex.hx deleted file mode 100644 index 9db9a215de3fc73e10358577d388a6b53353a327..0000000000000000000000000000000000000000 --- a/std/cs/system/text/regularExpressions/Regex.hx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C)2005-2012 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 cs.system.text.regularExpressions; -import cs.NativeArray; - -@:native('System.Text.RegularExpressions.Regex') extern class Regex -{ - function new(pattern:String, options:RegexOptions):Void; - @:overload(function(input:String, startPos:Int, len:Int):Match{}) - @:overload(function(input:String, startPos:Int):Match{}) - function Match(input:String):Match; - function Split(input:String):NativeArray; - @:overload(function(input:String, replacement:String,max:Int):String{}) - function Replace(input:String, replacement:String):String; -} - -@:native("System.Text.RegularExpressions.RegexOptions") extern enum RegexOptions -{ - None; - IgnoreCase; - Multiline; - ExplicitCapture; - Compiled; - Singleline; - IgnorePatternWhitespace; - RightToLeft; - ECMAScript; - CultureInvariant; -} - -@:native("System.Text.RegularExpressions.Capture") extern class Capture -{ - var Index(default, null):Int; - var Length(default, null):Int; - var Value(default, null):String; -} - -@:native("System.Text.RegularExpressions.Group") extern class Group extends Capture -{ - var Success(default, null):Bool; -} - -@:native("System.Text.RegularExpressions.Match") extern class Match extends Group -{ - var Captures(default, null):CaptureCollection; - var Groups(default, null):GroupCollection; -} - -@:native("System.Text.RegularExpressions.CaptureCollection") extern class CaptureCollection implements ArrayAccess -{ - var Count(default, null):Int; -} - -@:native("System.Text.RegularExpressions.GroupCollection") extern class GroupCollection implements ArrayAccess -{ - var Count(default, null):Int; -} diff --git a/std/cs/types/Char16.hx b/std/cs/types/Char16.hx new file mode 100644 index 0000000000000000000000000000000000000000..084eb711ef7ae6b25fb58bf9d12d716d0d2d9e4d --- /dev/null +++ b/std/cs/types/Char16.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef Char16 = cs.StdTypes.Char16; diff --git a/std/cs/types/Int16.hx b/std/cs/types/Int16.hx new file mode 100644 index 0000000000000000000000000000000000000000..682d19fdbd727470f59b9627e194890cb524ea9f --- /dev/null +++ b/std/cs/types/Int16.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef Int16 = cs.StdTypes.Int16; diff --git a/std/cs/types/Int64.hx b/std/cs/types/Int64.hx new file mode 100644 index 0000000000000000000000000000000000000000..a39604a38e2586388631fabe54ab6247077b383c --- /dev/null +++ b/std/cs/types/Int64.hx @@ -0,0 +1,4 @@ +package cs.types; + +typedef Int64 = cs.StdTypes.Int64; + diff --git a/std/cs/types/Int8.hx b/std/cs/types/Int8.hx new file mode 100644 index 0000000000000000000000000000000000000000..ac4d92fd8005bfd858cb220729188aec05ef028c --- /dev/null +++ b/std/cs/types/Int8.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef Int8 = cs.StdTypes.Int8; diff --git a/std/cs/types/UInt16.hx b/std/cs/types/UInt16.hx new file mode 100644 index 0000000000000000000000000000000000000000..28e8876e595ede6649fd532f032ff46b801c77d2 --- /dev/null +++ b/std/cs/types/UInt16.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef UInt16 = cs.StdTypes.UInt16; diff --git a/std/cs/types/UInt64.hx b/std/cs/types/UInt64.hx new file mode 100644 index 0000000000000000000000000000000000000000..a556a53ffac5125cbb2b11aabe023de70106892a --- /dev/null +++ b/std/cs/types/UInt64.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef UInt64 = cs.StdTypes.UInt64; diff --git a/std/cs/types/UInt8.hx b/std/cs/types/UInt8.hx new file mode 100644 index 0000000000000000000000000000000000000000..2635604c81aff2a766dba428a7980edd7396cf3c --- /dev/null +++ b/std/cs/types/UInt8.hx @@ -0,0 +1,3 @@ +package cs.types; + +typedef UInt8 = cs.StdTypes.UInt8; diff --git a/std/flash/Boot.hx b/std/flash/Boot.hx index 4af156fe1df70f060f776d4930e0c770eb834e6e..a49d6afdc76853d9c928a1c4f0efdde5861e35ca 100644 --- a/std/flash/Boot.hx +++ b/std/flash/Boot.hx @@ -51,7 +51,6 @@ class Boot extends flash.display.MovieClip { public static var skip_constructor = false; function start() { - #if (mt && !doc_gen) mt.flash.Init.check(); #end #if dontWaitStage init(); #else @@ -209,6 +208,21 @@ class Boot extends flash.display.MovieClip { return s; } + static public function mapDynamic(d:Dynamic, f:Dynamic) { + if (Std.is(d, Array)) { + return untyped d["mapHX"](f); + } else { + return untyped d["map"](f); + } + } + + static public function filterDynamic(d:Dynamic, f:Dynamic) { + if (Std.is(d, Array)) { + return untyped d["filterHX"](f); + } else { + return untyped d["filter"](f); + } + } static function __init__() untyped { var aproto = Array.prototype; @@ -240,7 +254,7 @@ class Boot extends flash.display.MovieClip { aproto.setPropertyIsEnumerable("insert", false); aproto.setPropertyIsEnumerable("remove", false); aproto.setPropertyIsEnumerable("iterator", false); - #if as3 + #if (as3 || no_flash_override) aproto.filterHX = function(f) { var ret = []; var i = 0; @@ -266,7 +280,7 @@ class Boot extends flash.display.MovieClip { aproto.setPropertyIsEnumerable("filterHX", false); String.prototype.charCodeAtHX = function(i) : Null { #else - aproto.filter = function(f) { + aproto["filter"] = function(f) { var ret = []; var i = 0; var l = __this__.length; @@ -277,7 +291,7 @@ class Boot extends flash.display.MovieClip { } return ret; }; - aproto.map = function(f) { + aproto["map"] = function(f) { var ret = []; var i = 0; var l = __this__.length; diff --git a/std/flash/Lib.hx b/std/flash/Lib.hx index 6e9f8025970b559925aaf09a6669994fc47e02f0..19768d6dfff216cb5552f5c5dd07c5660e9706f2 100644 --- a/std/flash/Lib.hx +++ b/std/flash/Lib.hx @@ -64,6 +64,10 @@ class Lib { public static function trace( arg : Dynamic ) { untyped __global__["trace"](arg); } + + public static function describeType( value : Dynamic ) : flash.xml.XML { + return untyped __global__["flash.utils.describeType"](value); + } public static function attach( name : String ) : flash.display.MovieClip { var cl = untyped __as__(__global__["flash.utils.getDefinitionByName"](name),Class); @@ -73,7 +77,7 @@ class Lib { public inline static function as( v : Dynamic, c : Class ) : Null { return untyped __as__(v,c); } - + public static function redirectTraces() { if (flash.external.ExternalInterface.available) haxe.Log.trace = traceToConsole; diff --git a/std/flash/_std/Xml.hx b/std/flash/NativeXml.hx similarity index 93% rename from std/flash/_std/Xml.hx rename to std/flash/NativeXml.hx index 6ce07214a5baff62e7a54d847e5054462545a095..b9610a95a38d8c4f04800a93f15d9acbd2dc93fb 100644 --- a/std/flash/_std/Xml.hx +++ b/std/flash/NativeXml.hx @@ -1,412 +1,421 @@ -/* - * Copyright (C)2005-2012 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. - */ -import flash.xml.XML; -import flash.xml.XMLList; - -extern enum XmlType { -} - -@:coreApi class Xml { - - public static var Element(default,null) : XmlType; - public static var PCData(default,null) : XmlType; - public static var CData(default,null) : XmlType; - public static var Comment(default,null) : XmlType; - public static var DocType(default,null) : XmlType; - public static var ProcessingInstruction(default,null) : XmlType; - public static var Document(default,null) : XmlType; - - public var nodeType(default,null) : XmlType; - public var nodeName(get,set) : String; - public var nodeValue(get,set) : String; - public var parent(get,null) : Xml; - - var _node : flash.xml.XML; - - public static function parse( str : String ) : Xml { - XML.ignoreWhitespace = false; - XML.ignoreProcessingInstructions = false; - XML.ignoreComments = false; - var prefix = "<__document"; - var root = null; - while( root == null ) { - try { - root = new flash.xml.XML(prefix+">" + str + ""); - } catch( e : flash.errors.TypeError ) { - // if we miss a namespace, let's add it ! - var r = ~/"([^"]+)"/; //" - if( e.errorID == 1083 && r.match(e.message) ) { - var ns = r.matched(1); - prefix += " xmlns:" + ns + '="@' + ns + '"'; - } else - throw e; - } - } - return wrap( root, Xml.Document ); - } - - @:keep #if as3 @:hack public #end static function compare( a : Xml, b : Xml ) : Bool { - return a == null ? b == null : (b == null ? false : a._node == b._node); - } - - private function new() : Void {} - - public static function createElement( name : String ) : Xml { - return wrap( new flash.xml.XML("<"+name+"/>"), Xml.Element ); - } - - public static function createPCData( data : String ) : Xml { - XML.ignoreWhitespace = false; - return wrap( new flash.xml.XML(data), Xml.PCData ); - } - - public static function createCData( data : String ) : Xml { - return wrap( new flash.xml.XML(""), Xml.CData ); - } - - public static function createComment( data : String ) : Xml { - XML.ignoreComments = false; - return wrap( new flash.xml.XML(""), Xml.Comment ); - } - - public static function createDocType( data : String ) : Xml { - return wrap( new flash.xml.XML(""), Xml.DocType ); - } - - public static function createProcessingInstruction( data : String ) : Xml { - XML.ignoreProcessingInstructions = false; - return wrap( new flash.xml.XML(""), Xml.ProcessingInstruction ); - } - - public static function createDocument() : Xml { - return wrap( new flash.xml.XML("<__document/>"), Xml.Document ); - } - - private static function getNodeType( node : flash.xml.XML ) : XmlType { - switch( node.nodeKind() ) { - case "element": - return Xml.Element; - case "text": - return Xml.PCData; - case "processing-instruction": - return Xml.ProcessingInstruction; - case "comment": - return Xml.Comment; - default : - throw "unimplemented node type: " + node.nodeType; - } - return null; - } - - private function get_nodeName() : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = _node.namespace(); - return (ns.prefix == "") ? _node.localName() : ns.prefix+":"+_node.localName(); - } - - private function set_nodeName( n : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = n.split(":"); - if( ns.length == 1 ) - _node.setLocalName(n); - else { - _node.setLocalName(ns[1]); - _node.setNamespace(_node.namespace(ns[0])); - } - return n; - } - - private function get_nodeValue() : String { - var nodeType = nodeType; - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - if( nodeType == Xml.Comment ) - return _node.toString().substr(4,-7); - return _node.toString(); - } - - private function set_nodeValue( v : String ) : String { - var nodeType = nodeType; - var x = null; - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - else if( nodeType == Xml.PCData ) - x = createPCData(v); - else if( nodeType == Xml.CData ) - x = createCData(v); - else if( nodeType == Xml.Comment ) - x = createComment(v); - else if( nodeType == Xml.DocType ) - x = createDocType(v); - else - x = createProcessingInstruction(v); - var p = _node.parent(); - if( p != null ) { - p.insertChildAfter(_node, x._node); - var i = _node.childIndex(); - var children = p.children(); - untyped __delete__(children, Reflect.fields(children)[i]); - } - _node = x._node; - return v; - } - - private function get_parent() :Xml { - var p = _node.parent(); - return p == null ? null : wrap( p ); - } - - private static function wrap( node : XML, ?type : XmlType ) : Xml { - var x = new Xml(); - x._node = node; - x.nodeType = (type != null) ? type : getNodeType( node ); - return x; - } - - private function wraps( xList : XMLList ) : Array { - var out = new Array(); - for( i in 0...xList.length() ) - out.push( wrap(xList[i]) ); - return out; - } - - function getAttribNS( cur : XML, ns : Array ) : XMLList { - var n = cur.namespace(ns[0]); - if( n == null ) { - var parent = cur.parent(); - if( parent == null ) { - n = new flash.utils.Namespace(ns[0], "@"+ns[0]); - cur.addNamespace(n); - } else - return getAttribNS(parent, ns); - } - return _node.attribute(new flash.utils.QName(n,ns[1])); - } - - public function get( att : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = att.split(":"); - if( ns[0] == "xmlns" ) { - var n = _node.namespace((ns[1] == null) ? "" : ns[1]); - return (n == null) ? null : n.uri; - } - if( ns.length == 1 ) { - if( !Reflect.hasField(_node,"@"+att) ) - return null; - return Reflect.field(_node, "@"+att); - } - var a = getAttribNS(_node,ns); - return (a.length() == 0) ? null : a.toString(); - } - - public function set( att : String, value : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = att.split(":"); - if( ns[0] == "xmlns" ) { - var n = _node.namespace((ns[1] == null) ? "" : ns[1]); - if( n != null ) - throw "Can't modify namespace"; - if( ns[1] == null ) - throw "Can't set default namespace"; - _node.addNamespace(new flash.utils.Namespace(ns[1], value)); - return; - } - if( ns.length == 1 ) - Reflect.setField(_node, "@"+att, value); - else { - var a = getAttribNS(_node,ns); - untyped a[0] = value; - } - } - - public function remove( att : String ) : Void{ - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = att.split(":"); - if( ns.length == 1 ) - Reflect.deleteField(_node, "@"+att); - else - untyped __delete__(getAttribNS(_node,ns),0); - } - - public function exists( att : String ) : Bool { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var ns = att.split(":"); - if( ns[0] == "xmlns" ) - return _node.namespace((ns[1] == null) ? "" : ns[1]) != null; - if( ns.length == 1 ) - return Reflect.hasField(_node, "@"+att); - return getAttribNS(_node,ns).length() > 0; - } - - public function attributes() : Iterator { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - var attributes :XMLList = _node.attributes(); - var names = Reflect.fields(attributes); - var cur = 0; - return { - hasNext : function(){ - return cur < names.length; - }, - next : function(){ - return attributes[Std.parseInt(names[cur++])].name(); - } - } - } - - public function iterator() : Iterator { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var children:XMLList = _node.children(); - var wrappers :Array = wraps(children); - var cur = 0; - return { - hasNext : function(){ - return cur < wrappers.length; - }, - next : function(){ - return wrappers[cur++]; - } - }; - } - - public function elements() : Iterator { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var elements:XMLList = _node.elements(); - var wrappers :Array = wraps(elements); - var cur = 0; - return { - hasNext : function(){ - return cur < wrappers.length; - }, - next : function(){ - return wrappers[cur++]; - } - }; - } - - public function elementsNamed( name : String ) : Iterator { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var ns = name.split(":"); - var elements:XMLList; - if( ns.length == 1 ) - elements = _node.elements(name); - else - elements = _node.elements(); - var wrappers :Array = wraps(elements); - if( ns.length != 1 ) - for( w in wrappers.copy() ) - if( w._node.localName() != ns[1] || w._node.namespace().prefix != ns[0] ) - wrappers.remove(w); - var cur = 0; - return { - hasNext : function(){ - return cur < wrappers.length; - }, - next : function(){ - return wrappers[cur++]; - } - }; - } - - public function firstChild() : Xml { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var children:XMLList = _node.children(); - if( children.length() == 0 ) - return null; - return wrap( children[0] ); - } - - public function firstElement() : Xml { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var elements:XMLList = _node.elements(); - if( elements.length() == 0 ) - return null; - return wrap( elements[0] ); - } - - public function addChild( x : Xml ) : Void { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - if (x.parent != null) - x.parent.removeChild(x); - var children:XMLList = _node.children(); - _node.appendChild(x._node); - } - - public function removeChild( x : Xml ) : Bool { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var children:XMLList = _node.children(); - if( _node != x._node.parent() ) - return false; - var i = x._node.childIndex(); - untyped __delete__(children, Reflect.fields(children)[i]); - return true; - } - - public function insertChild( x : Xml, pos : Int ) : Void { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - if (x.parent != null) - x.parent.removeChild(x); - var children:XMLList = _node.children(); - if( pos < children.length() ) - _node.insertChildBefore(children[pos], x._node); - else - _node.appendChild(x._node); - } - - public function toString() : String { - XML.prettyPrinting = false; - if( nodeType == Xml.Document ) { - var str = _node.toXMLString(); - // remove <__document xmlns....>STR wrapper - str = str.substr(str.indexOf(">") + 1); - str = str.substr(0, str.length - 13); - return str; - } - return _node.toXMLString(); - } - - static function __init__() : Void untyped { - Element = "element"; - PCData = "pcdata"; - CData = "cdata"; - Comment = "comment"; - DocType = "doctype"; - ProcessingInstruction = "processingInstruction"; - Document = "document"; - } - - -} +/* + * Copyright (C)2005-2012 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 flash; + +import flash.xml.XML; +import flash.xml.XMLList; + +extern enum XmlType { +} + +typedef NativeXml = Xml; + +class Xml { + + public static var Element(default,null) : XmlType; + public static var PCData(default,null) : XmlType; + public static var CData(default,null) : XmlType; + public static var Comment(default,null) : XmlType; + public static var DocType(default,null) : XmlType; + public static var ProcessingInstruction(default,null) : XmlType; + public static var Document(default,null) : XmlType; + + public var nodeType(default,null) : XmlType; + public var nodeName(get,set) : String; + public var nodeValue(get,set) : String; + public var parent(get,null) : Xml; + + var _node : flash.xml.XML; + + public static function parse( str : String ) : Xml { + XML.ignoreWhitespace = false; + XML.ignoreProcessingInstructions = false; + XML.ignoreComments = false; + var prefix = "<__document"; + var root = null; + while( root == null ) { + try { + root = new flash.xml.XML(prefix+">" + str + ""); + } catch( e : flash.errors.TypeError ) { + // if we miss a namespace, let's add it ! + var r = ~/"([^"]+)"/; //" + if( e.errorID == 1083 && r.match(e.message) ) { + var ns = r.matched(1); + prefix += " xmlns:" + ns + '="@' + ns + '"'; + } else + throw e; + } + } + return wrap( root, Xml.Document ); + } + + @:keep #if as3 @:hack public #end static function compare( a : Xml, b : Xml ) : Bool { + return a == null ? b == null : (b == null ? false : a._node == b._node); + } + + private function new() : Void {} + + public static function createElement( name : String ) : Xml { + return wrap( new flash.xml.XML("<"+name+"/>"), Xml.Element ); + } + + public static function createPCData( data : String ) : Xml { + XML.ignoreWhitespace = false; + return wrap( new flash.xml.XML(data), Xml.PCData ); + } + + public static function createCData( data : String ) : Xml { + return wrap( new flash.xml.XML(""), Xml.CData ); + } + + public static function createComment( data : String ) : Xml { + XML.ignoreComments = false; + return wrap( new flash.xml.XML(""), Xml.Comment ); + } + + public static function createDocType( data : String ) : Xml { + return wrap( new flash.xml.XML(""), Xml.DocType ); + } + + public static function createProcessingInstruction( data : String ) : Xml { + XML.ignoreProcessingInstructions = false; + return wrap( new flash.xml.XML(""), Xml.ProcessingInstruction ); + } + + public static function createDocument() : Xml { + return wrap( new flash.xml.XML("<__document/>"), Xml.Document ); + } + + private static function getNodeType( node : flash.xml.XML ) : XmlType { + switch( node.nodeKind() ) { + case "element": + return Xml.Element; + case "text": + return Xml.PCData; + case "processing-instruction": + return Xml.ProcessingInstruction; + case "comment": + return Xml.Comment; + default : + throw "unimplemented node type: " + node.nodeType; + } + } + + private function get_nodeName() : String { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = _node.namespace(); + return (ns.prefix == "") ? _node.localName() : ns.prefix+":"+_node.localName(); + } + + private function set_nodeName( n : String ) : String { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = n.split(":"); + if( ns.length == 1 ) + _node.setLocalName(n); + else { + _node.setLocalName(ns[1]); + _node.setNamespace(_node.namespace(ns[0])); + } + return n; + } + + private function get_nodeValue() : String { + var nodeType = nodeType; + if( nodeType == Xml.Element || nodeType == Xml.Document ) + throw "bad nodeType"; + if( nodeType == Xml.Comment ) + return _node.toString().substr(4,-7); + return _node.toString(); + } + + private function set_nodeValue( v : String ) : String { + var nodeType = nodeType; + var x = null; + if( nodeType == Xml.Element || nodeType == Xml.Document ) + throw "bad nodeType"; + else if( nodeType == Xml.PCData ) + x = createPCData(v); + else if( nodeType == Xml.CData ) + x = createCData(v); + else if( nodeType == Xml.Comment ) + x = createComment(v); + else if( nodeType == Xml.DocType ) + x = createDocType(v); + else + x = createProcessingInstruction(v); + var p = _node.parent(); + if( p != null ) { + p.insertChildAfter(_node, x._node); + var i = _node.childIndex(); + var children = p.children(); + untyped __delete__(children, Reflect.fields(children)[i]); + } + _node = x._node; + return v; + } + + private function get_parent() :Xml { + var p = _node.parent(); + return p == null ? null : wrap( p ); + } + + private static function wrap( node : XML, ?type : XmlType ) : Xml { + var x = new Xml(); + x._node = node; + x.nodeType = (type != null) ? type : getNodeType( node ); + return x; + } + + private function wraps( xList : XMLList ) : Array { + var out = new Array(); + for( i in 0...xList.length() ) + out.push( wrap(xList[i]) ); + return out; + } + + function getAttribNS( cur : XML, ns : Array ) : XMLList { + var n = cur.namespace(ns[0]); + if( n == null ) { + var parent = cur.parent(); + if( parent == null ) { + n = new flash.utils.Namespace(ns[0], "@"+ns[0]); + cur.addNamespace(n); + } else + return getAttribNS(parent, ns); + } + return _node.attribute(new flash.utils.QName(n,ns[1])); + } + + public function get( att : String ) : String { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = att.split(":"); + if( ns[0] == "xmlns" ) { + var n = _node.namespace((ns[1] == null) ? "" : ns[1]); + return (n == null) ? null : n.uri; + } + if( ns.length == 1 ) { + if( !Reflect.hasField(_node,"@"+att) ) + return null; + return Reflect.field(_node, "@"+att); + } + var a = getAttribNS(_node,ns); + return (a.length() == 0) ? null : a.toString(); + } + + public function set( att : String, value : String ) : Void { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = att.split(":"); + if( ns[0] == "xmlns" ) { + var n = _node.namespace((ns[1] == null) ? "" : ns[1]); + if( n != null ) + throw "Can't modify namespace"; + if( ns[1] == null ) + throw "Can't set default namespace"; + _node.addNamespace(new flash.utils.Namespace(ns[1], value)); + return; + } + if( ns.length == 1 ) + Reflect.setField(_node, "@"+att, value); + else { + var a = getAttribNS(_node,ns); + untyped a[0] = value; + } + } + + public function remove( att : String ) : Void{ + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = att.split(":"); + if( ns.length == 1 ) + Reflect.deleteField(_node, "@"+att); + else + untyped __delete__(getAttribNS(_node,ns),0); + } + + public function exists( att : String ) : Bool { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var ns = att.split(":"); + if( ns[0] == "xmlns" ) + return _node.namespace((ns[1] == null) ? "" : ns[1]) != null; + if( ns.length == 1 ) + return Reflect.hasField(_node, "@"+att); + return getAttribNS(_node,ns).length() > 0; + } + + public function attributes() : Iterator { + if( nodeType != Xml.Element ) + throw "bad nodeType"; + var attributes :XMLList = _node.attributes(); + var names = Reflect.fields(attributes); + var cur = 0; + var nss = _node.namespaceDeclarations(); + return { + hasNext : function(){ + return cur < names.length + nss.length; + }, + next : function() { + if(cur { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var children:XMLList = _node.children(); + var wrappers :Array = wraps(children); + var cur = 0; + return { + hasNext : function(){ + return cur < wrappers.length; + }, + next : function(){ + return wrappers[cur++]; + } + }; + } + + public function elements() : Iterator { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var elements:XMLList = _node.elements(); + var wrappers :Array = wraps(elements); + var cur = 0; + return { + hasNext : function(){ + return cur < wrappers.length; + }, + next : function(){ + return wrappers[cur++]; + } + }; + } + + public function elementsNamed( name : String ) : Iterator { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var ns = name.split(":"); + var elements:XMLList; + if( ns.length == 1 ) + elements = _node.elements(name); + else + elements = _node.elements(); + var wrappers :Array = wraps(elements); + if( ns.length != 1 ) + for( w in wrappers.copy() ) + if( w._node.localName() != ns[1] || w._node.namespace().prefix != ns[0] ) + wrappers.remove(w); + var cur = 0; + return { + hasNext : function(){ + return cur < wrappers.length; + }, + next : function(){ + return wrappers[cur++]; + } + }; + } + + public function firstChild() : Xml { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var children:XMLList = _node.children(); + if( children.length() == 0 ) + return null; + return wrap( children[0] ); + } + + public function firstElement() : Xml { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var elements:XMLList = _node.elements(); + if( elements.length() == 0 ) + return null; + return wrap( elements[0] ); + } + + public function addChild( x : Xml ) : Void { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + if (x.parent != null) + x.parent.removeChild(x); + var children:XMLList = _node.children(); + _node.appendChild(x._node); + } + + public function removeChild( x : Xml ) : Bool { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + var children:XMLList = _node.children(); + if( _node != x._node.parent() ) + return false; + var i = x._node.childIndex(); + untyped __delete__(children, Reflect.fields(children)[i]); + return true; + } + + public function insertChild( x : Xml, pos : Int ) : Void { + if( nodeType != Xml.Element && nodeType != Xml.Document ) + throw "bad nodeType"; + if (x.parent != null) + x.parent.removeChild(x); + var children:XMLList = _node.children(); + if( pos < children.length() ) + _node.insertChildBefore(children[pos], x._node); + else + _node.appendChild(x._node); + } + + public function toString() : String { + XML.prettyPrinting = false; + if( nodeType == Xml.Document ) { + var str = _node.toXMLString(); + // remove <__document xmlns....>STR wrapper + str = str.substr(str.indexOf(">") + 1); + str = str.substr(0, str.length - 13); + return str; + } + return _node.toXMLString(); + } + + static function __init__() : Void untyped { + Element = "element"; + PCData = "pcdata"; + CData = "cdata"; + Comment = "comment"; + DocType = "doctype"; + ProcessingInstruction = "processingInstruction"; + Document = "document"; + } + + +} \ No newline at end of file diff --git a/std/flash/_std/EReg.hx b/std/flash/_std/EReg.hx index 76b639a7ba00f9dc9b68f99202777b5b197d92fd..7ba12b0ceb637e8a4906c4ffa2142ec156a840f6 100644 --- a/std/flash/_std/EReg.hx +++ b/std/flash/_std/EReg.hx @@ -22,7 +22,7 @@ @:coreApi class EReg { var r : flash.utils.RegExp; - var result : {> Array, index : Int, input : String }; + var result : Dynamic; public function new( r : String, opt : String ) : Void { this.r = new flash.utils.RegExp(r,opt); @@ -35,25 +35,25 @@ } public function matched( n : Int ) : String { - return if( result != null && n >= 0 && n < result.length ) result[n] else throw "EReg::matched"; + return if( result != null && n >= 0 && n < (result : Array).length ) result[n] else throw "EReg::matched"; } public function matchedLeft() : String { if( result == null ) throw "No string matched"; - var s = result.input; - return s.substr(0,result.index); + var s : String = untyped result.input; + return s.substr(0,untyped result["index"]); } public function matchedRight() : String { if( result == null ) throw "No string matched"; - var rl = result.index + result[0].length; - var s = result.input; + var rl = (result[untyped "index"] : Int) + (result[0] : String).length; + var s : String = untyped result.input; return s.substr(rl,s.length - rl); } public function matchedPos() : { pos : Int, len : Int } { if( result == null ) throw "No string matched"; - return { pos : result.index, len : result[0].length }; + return { pos : result[untyped "index"], len : (result[0] : String).length }; } public function matchSub( s : String, pos : Int, len : Int = -1):Bool { @@ -62,14 +62,14 @@ result = r.exec(len < 0 ? s : s.substr(0, pos + len)); var b = result != null; if (b) { - result.input = s; + untyped result.input = s; } b; } else { var b = match( len < 0 ? s.substr(pos) : s.substr(pos,len) ); if (b) { - result.input = s; - result.index += pos; + untyped result.input = s; + untyped result["index"] += pos; } b; } diff --git a/std/flash/_std/Reflect.hx b/std/flash/_std/Reflect.hx index 98b20307b45ec11919c787af9a02d979a0c4a458..a950f85ef47e0376365e7f7a55d9704bd56eb68f 100644 --- a/std/flash/_std/Reflect.hx +++ b/std/flash/_std/Reflect.hx @@ -37,7 +37,7 @@ public static function getProperty( o : Dynamic, field : String ) : Dynamic untyped { try { return o["get_" + field](); - } catch( e : Dynamic ) { + } catch( e : Dynamic ) try { return o[field]; } catch( e : Dynamic ) { return null; @@ -52,7 +52,7 @@ } } - public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic untyped { + public inline static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic untyped { return func.apply(o,args); } @@ -102,7 +102,7 @@ } return (t == "string"); } - + public static function isEnumValue( v : Dynamic ) : Bool { #if as3 return try Type.getEnum(v) != null catch ( e: Dynamic) false; diff --git a/std/flash/_std/Std.hx b/std/flash/_std/Std.hx index 3c8958afaea923675d04ee5754edc12c5bc4c079..0f4a78a7148d0296af8d9bf9e88e585c19aaa532 100644 --- a/std/flash/_std/Std.hx +++ b/std/flash/_std/Std.hx @@ -27,6 +27,10 @@ import flash.Boot; return untyped flash.Boot.__instanceof(v,t); } + public static inline function instance( value : T, c : Class ) : S { + return flash.Lib.as(value, c); + } + public static function string( s : Dynamic ) : String { return untyped flash.Boot.__string_rec(s,""); } diff --git a/std/flash/_std/Type.hx b/std/flash/_std/Type.hx index 206033dd5c0c5cd5d4f38d1557483d2ec7df2b6a..4aaeefaef70d950615aee49a99f1a1e5ac81ea98 100644 --- a/std/flash/_std/Type.hx +++ b/std/flash/_std/Type.hx @@ -162,7 +162,7 @@ enum ValueType { } public static function createEnum( e : Enum, constr : String, ?params : Array ) : T { - var f = Reflect.field(e,constr); + var f:Dynamic = untyped e[constr]; if( f == null ) throw "No such constructor "+constr; if( Reflect.isFunction(f) ) { if( params == null ) throw "Constructor "+constr+" need parameters"; diff --git a/std/flash/_std/haxe/Json.hx b/std/flash/_std/haxe/Json.hx new file mode 100644 index 0000000000000000000000000000000000000000..a7865eef094c753829160c93fdd5e5fe965997d5 --- /dev/null +++ b/std/flash/_std/haxe/Json.hx @@ -0,0 +1,39 @@ +/* + * Copyright (C)2005-2012 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 +#if (!haxeJSON && flash11) +@:native("JSON") extern +#end +class Json { + + #if (haxeJSON || !flash11) inline #end + public static function parse( text : String ) : Dynamic { + return haxe.format.JsonParser.parse(text); + } + + #if (haxeJSON || !flash11) inline #end + public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String { + return haxe.format.JsonPrinter.print(value, replacer, space); + } +} diff --git a/std/flash/_std/haxe/ds/IntMap.hx b/std/flash/_std/haxe/ds/IntMap.hx index 33ad7bffff350ee971d866cad0aed548c53dfd38..681de03b4d2281ae14a2e0e2767e40e69aa7c649 100644 --- a/std/flash/_std/haxe/ds/IntMap.hx +++ b/std/flash/_std/haxe/ds/IntMap.hx @@ -21,7 +21,7 @@ */ package haxe.ds; -@:coreApi class IntMap implements Map.IMap { +@:coreApi class IntMap implements haxe.Constraints.IMap { private var h : flash.utils.Dictionary; @@ -29,20 +29,20 @@ package haxe.ds; h = new flash.utils.Dictionary(); } - public function set( key : Int, value : T ) : Void { + public inline function set( key : Int, value : T ) : Void { untyped h[key] = value; } - public function get( key : Int ) : Null { + public inline function get( key : Int ) : Null { return untyped h[key]; } - public function exists( key : Int ) : Bool { - return untyped h.hasOwnProperty(key); + public inline function exists( key : Int ) : Bool { + return untyped __in__(key,h); } public function remove( key : Int ) : Bool { - if( untyped !h.hasOwnProperty(key) ) return false; + if( !exists(key) ) return false; untyped __delete__(h,key); return true; } @@ -51,7 +51,7 @@ package haxe.ds; return untyped (__keys__(h)).iterator(); } - public function iterator() : Iterator { + @:analyzer(ignore) public function iterator() : Iterator { return untyped { ref : h, it : keys(), diff --git a/std/flash/_std/haxe/ds/ObjectMap.hx b/std/flash/_std/haxe/ds/ObjectMap.hx index 228997ca3c50065c357748787064a1fe2ce84403..9c264761c88965e5bc50b5d1bd28fff8671e0626 100644 --- a/std/flash/_std/haxe/ds/ObjectMap.hx +++ b/std/flash/_std/haxe/ds/ObjectMap.hx @@ -1,120 +1,120 @@ -package haxe.ds; - -@:coreApi -class ObjectMap extends flash.utils.Dictionary implements Map.IMap { - - public function new() { - super(false); - } - - public inline function get( key : K ) : Null { - return untyped this[key]; - } - - public inline function set( key : K, value : V ):Void { - untyped this[key] = value; - } - - public inline function exists( key : K ) : Bool { - return untyped this[key] != null; - } - - public function remove( key : K ):Bool { - var has = exists(key); - untyped __delete__(this, key); - 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); - } - - public function iterator() : Iterator { - return NativeValueIterator.iterator(this); - } - - #end - - public function toString() : String { - var s = ""; - var it = keys(); - for( i in it ) { - s += (s == "" ? "" : ",") + Std.string(i); - s += " => "; - s += Std.string(get(i)); - } - return s + "}"; - } -} - -private class NativePropertyIterator { - var collection:Dynamic; - var index:Int = 0; - - public static inline function iterator(collection:Dynamic):NativePropertyIterator { - var result = new NativePropertyIterator(); - result.collection = collection; - return result; - } - - function new() {} - - public inline function hasNext():Bool { - var c = collection; - var i = index; - var result = untyped __has_next__(c, i); - collection = c; - index = i; - return result; - } - - public inline function next():Dynamic { - var i = index; - var result = untyped __forin__(collection, i); - index = i; - return result; - } -} - -private class NativeValueIterator { - var collection:Dynamic; - var index:Int = 0; - - public static inline function iterator(collection:Dynamic):NativeValueIterator { - var result = new NativeValueIterator(); - result.collection = collection; - return result; - } - - function new() {} - - public inline function hasNext():Bool { - var c = collection; - var i = index; - var result = untyped __has_next__(c, i); - collection = c; - index = i; - return result; - } - - public inline function next():Dynamic { - var i = index; - var result = untyped __foreach__(collection, i); - index = i; - return result; - } -} +package haxe.ds; + +@:coreApi +class ObjectMap extends flash.utils.Dictionary implements haxe.Constraints.IMap { + + public function new() { + super(false); + } + + public inline function get( key : K ) : Null { + return untyped this[key]; + } + + public inline function set( key : K, value : V ):Void { + untyped this[key] = value; + } + + public inline function exists( key : K ) : Bool { + return untyped this[key] != null; + } + + public function remove( key : K ):Bool { + var has = exists(key); + untyped __delete__(this, key); + 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); + } + + public function iterator() : Iterator { + return NativeValueIterator.iterator(this); + } + + #end + + public function toString() : String { + var s = ""; + var it = keys(); + for( i in it ) { + s += (s == "" ? "" : ",") + Std.string(i); + s += " => "; + s += Std.string(get(i)); + } + return s + "}"; + } +} + +private class NativePropertyIterator { + var collection:Dynamic; + var index:Int = 0; + + public static inline function iterator(collection:Dynamic):NativePropertyIterator { + var result = new NativePropertyIterator(); + result.collection = collection; + return result; + } + + function new() {} + + public inline function hasNext():Bool { + var c = collection; + var i = index; + var result = untyped __has_next__(c, i); + collection = c; + index = i; + return result; + } + + public inline function next():Dynamic { + var i = index; + var result = untyped __forin__(collection, i); + index = i; + return result; + } +} + +private class NativeValueIterator { + var collection:Dynamic; + var index:Int = 0; + + public static inline function iterator(collection:Dynamic):NativeValueIterator { + var result = new NativeValueIterator(); + result.collection = collection; + return result; + } + + function new() {} + + public inline function hasNext():Bool { + var c = collection; + var i = index; + var result = untyped __has_next__(c, i); + collection = c; + index = i; + return result; + } + + public inline function next():Dynamic { + var i = index; + var result = untyped __foreach__(collection, i); + index = i; + return result; + } +} diff --git a/std/flash/_std/haxe/ds/StringMap.hx b/std/flash/_std/haxe/ds/StringMap.hx index 6c68e911a4ddd85ec6cac401cdabeec3f3eb5617..edf394f3d60c7bb4ac528d3d327445fe73d5f215 100644 --- a/std/flash/_std/haxe/ds/StringMap.hx +++ b/std/flash/_std/haxe/ds/StringMap.hx @@ -21,46 +21,97 @@ */ package haxe.ds; -@:coreApi class StringMap implements Map.IMap { +@:coreApi class StringMap implements haxe.Constraints.IMap { - private var h :flash.utils.Dictionary; + private var h : Dynamic; + private var rh : Dynamic; + static var reserved = { }; public function new() : Void { - h = new flash.utils.Dictionary(); + h = {}; } - public function set( key : String, value : T ) : Void { - untyped h["$"+key] = value; + inline function isReserved(key:String) : Bool { + return untyped __in__(key,reserved); } - public function get( key : String ) : Null { - return untyped h["$"+key]; + public inline function set( key : String, value : T ) : Void { + if( isReserved(key) ) + setReserved(key, value); + else + untyped h[key] = value; } - public function exists( key : String ) : Bool { - return untyped h.hasOwnProperty("$"+key); + public inline function get( key : String ) : Null { + if( isReserved(key) ) + return getReserved(key); + return untyped h[key]; + } + + public inline function exists( key : String ) : Bool { + if( isReserved(key) ) + return existsReserved(key); + return untyped __in__(key,h); + } + + function setReserved( key : String, value : T ) : Void { + if( rh == null ) rh = {}; + untyped rh["$"+key] = value; + } + + function getReserved( key : String ) : Null { + return rh == null ? null : untyped rh["$"+key]; + } + + function existsReserved( key : String ) : Bool { + if( rh == null ) return false; + return untyped __in__("$"+key,rh); } public function remove( key : String ) : Bool { - key = "$"+key; - if( untyped !h.hasOwnProperty(key) ) return false; - untyped __delete__(h,key); - return true; + if( isReserved(key) ) { + key = "$" + key; + if( rh == null || !untyped __in__(key,rh) ) return false; + untyped __delete__(rh,key); + return true; + } else { + if( !untyped __in__(key,h) ) + return false; + untyped __delete__(h,key); + return true; + } } + #if as3 + + // unoptimized version + public function keys() : Iterator { - return untyped (__hkeys__(h)).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 { - ref : h, - it : __keys__(h).iterator(), + it : keys(), hasNext : function() { return __this__.it.hasNext(); }, - next : function() { var i : Dynamic = __this__.it.next(); return __this__.ref[i]; } + next : function() { return get(__this__.it.next()); } }; } + #else + + public inline function keys() : Iterator { + return new StringMapKeysIterator(h, rh); + } + + public inline function iterator() : Iterator { + return new StringMapValuesIterator(h, rh); + } + + #end + public function toString() : String { var s = new StringBuf(); s.add("{"); @@ -77,3 +128,82 @@ package haxe.ds; } } + +#if !as3 + +// this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation + +@:allow(haxe.ds.StringMap) +private class StringMapKeysIterator { + var h:Dynamic; + var rh:Dynamic; + var index : Int; + var nextIndex : Int; + var isReserved : Bool; + + inline function new(h:Dynamic, rh:Dynamic):Void { + this.h = h; + this.rh = rh; + this.index = 0; + isReserved = false; + hasNext(); + } + + public inline function hasNext():Bool { + var h = h, index = index; // tmp vars required for __has_next + var n = untyped __has_next__(h, index); + if( !n && rh != null ) { + h = this.h = rh; + index = this.index = 0; + rh = null; + isReserved = true; + n = untyped __has_next__(h, index); + } + this.nextIndex = index; // store next index + return n; + } + + public inline function next():String { + var r : String = untyped __forin__(h, nextIndex); + index = nextIndex; + if( isReserved ) r = r.substr(1); + return r; + } + +} + +@:allow(haxe.ds.StringMap) +private class StringMapValuesIterator { + var h:Dynamic; + var rh:Dynamic; + var index : Int; + var nextIndex : Int; + + inline function new(h:Dynamic, rh:Dynamic):Void { + this.h = h; + this.rh = rh; + this.index = 0; + hasNext(); + } + + public inline function hasNext():Bool { + var h = h, index = index; // tmp vars required for __has_next + var n = untyped __has_next__(h, index); + if( !n && rh != null ) { + h = this.h = rh; + index = this.index = 0; + rh = null; + n = untyped __has_next__(h, index); + } + this.nextIndex = index; // store next index + return n; + } + + public inline function next():T { + var r = untyped __foreach__(h, nextIndex); + index = nextIndex; + return r; + } + +} +#end diff --git a/std/flash/_std/haxe/ds/UnsafeStringMap.hx b/std/flash/_std/haxe/ds/UnsafeStringMap.hx new file mode 100644 index 0000000000000000000000000000000000000000..7c817f7f31c4ff3864ed77e4d55310b7b6a794b4 --- /dev/null +++ b/std/flash/_std/haxe/ds/UnsafeStringMap.hx @@ -0,0 +1,83 @@ +/* + * Copyright (C)2005-2012 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; + +/** + This is similar to `StringMap` excepts that it does not sanitize the keys. + As a result, it will be faster to access the map for reading, but it might fail + with some reserved keys such as `constructor` or `prototype`. +**/ +class UnsafeStringMap implements haxe.Constraints.IMap { + + private var h : flash.utils.Dictionary; + + public function new() : Void { + h = new flash.utils.Dictionary(); + } + + public inline function set( key : String, value : T ) : Void { + untyped h[key] = value; + } + + public inline function get( key : String ) : Null { + return untyped h[key]; + } + + public inline function exists( key : String ) : Bool { + return untyped __in__(key,h); + } + + public function remove( key : String ) : Bool { + if( untyped !h.hasOwnProperty(key) ) return false; + untyped __delete__(h,key); + return true; + } + + 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]; } + }; + } + + 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(); + } + +} diff --git a/std/flash/_std/haxe/ds/WeakMap.hx b/std/flash/_std/haxe/ds/WeakMap.hx index b5ee05b4be3502b98a51a26260d01e25e4bbaa56..4f2c5a2e9f6d6cf08c88edecb5f78eca00024714 100644 --- a/std/flash/_std/haxe/ds/WeakMap.hx +++ b/std/flash/_std/haxe/ds/WeakMap.hx @@ -1,120 +1,120 @@ -package haxe.ds; - -@:coreApi -class WeakMap extends flash.utils.Dictionary implements Map.IMap { - - public function new() { - super(true); - } - - public inline function get( key : K ) : Null { - return untyped this[key]; - } - - public inline function set( key : K, value : V ):Void { - untyped this[key] = value; - } - - public inline function exists( key : K ) : Bool { - return untyped this[key] != null; - } - - public function remove( key : K ):Bool { - var has = exists(key); - untyped __delete__(this, key); - 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); - } - - public function iterator() : Iterator { - return NativeValueIterator.iterator(this); - } - - #end - - public function toString() : String { - var s = ""; - var it = keys(); - for( i in it ) { - s += (s == "" ? "" : ",") + Std.string(i); - s += " => "; - s += Std.string(get(i)); - } - return s + "}"; - } -} - -private class NativePropertyIterator { - var collection:Dynamic; - var index:Int = 0; - - public static inline function iterator(collection:Dynamic):NativePropertyIterator { - var result = new NativePropertyIterator(); - result.collection = collection; - return result; - } - - function new() {} - - public inline function hasNext():Bool { - var c = collection; - var i = index; - var result = untyped __has_next__(c, i); - collection = c; - index = i; - return result; - } - - public inline function next():Dynamic { - var i = index; - var result = untyped __forin__(collection, i); - index = i; - return result; - } -} - -private class NativeValueIterator { - var collection:Dynamic; - var index:Int = 0; - - public static inline function iterator(collection:Dynamic):NativeValueIterator { - var result = new NativeValueIterator(); - result.collection = collection; - return result; - } - - function new() {} - - public inline function hasNext():Bool { - var c = collection; - var i = index; - var result = untyped __has_next__(c, i); - collection = c; - index = i; - return result; - } - - public inline function next():Dynamic { - var i = index; - var result = untyped __foreach__(collection, i); - index = i; - return result; - } -} +package haxe.ds; + +@:coreApi +class WeakMap extends flash.utils.Dictionary implements haxe.Constraints.IMap { + + public function new() { + super(true); + } + + public inline function get( key : K ) : Null { + return untyped this[key]; + } + + public inline function set( key : K, value : V ):Void { + untyped this[key] = value; + } + + public inline function exists( key : K ) : Bool { + return untyped this[key] != null; + } + + public function remove( key : K ):Bool { + var has = exists(key); + untyped __delete__(this, key); + 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); + } + + public function iterator() : Iterator { + return NativeValueIterator.iterator(this); + } + + #end + + public function toString() : String { + var s = ""; + var it = keys(); + for( i in it ) { + s += (s == "" ? "" : ",") + Std.string(i); + s += " => "; + s += Std.string(get(i)); + } + return s + "}"; + } +} + +private class NativePropertyIterator { + var collection:Dynamic; + var index:Int = 0; + + public static inline function iterator(collection:Dynamic):NativePropertyIterator { + var result = new NativePropertyIterator(); + result.collection = collection; + return result; + } + + function new() {} + + public inline function hasNext():Bool { + var c = collection; + var i = index; + var result = untyped __has_next__(c, i); + collection = c; + index = i; + return result; + } + + public inline function next():Dynamic { + var i = index; + var result = untyped __forin__(collection, i); + index = i; + return result; + } +} + +private class NativeValueIterator { + var collection:Dynamic; + var index:Int = 0; + + public static inline function iterator(collection:Dynamic):NativeValueIterator { + var result = new NativeValueIterator(); + result.collection = collection; + return result; + } + + function new() {} + + public inline function hasNext():Bool { + var c = collection; + var i = index; + var result = untyped __has_next__(c, i); + collection = c; + index = i; + return result; + } + + public inline function next():Dynamic { + var i = index; + var result = untyped __foreach__(collection, i); + index = i; + return result; + } +} diff --git a/std/flash/_std/haxe/zip/Compress.hx b/std/flash/_std/haxe/zip/Compress.hx new file mode 100644 index 0000000000000000000000000000000000000000..e833c6d2794bec4bea91c4890e1c6be812ac1b0c --- /dev/null +++ b/std/flash/_std/haxe/zip/Compress.hx @@ -0,0 +1,55 @@ +/* + * Copyright (C)2005-2012 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.zip; + +@:coreApi +class Compress { + + public function new( level : Int ) : Void { + throw "Not implemented for this platform"; + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return null; + } + + public function setFlushMode( f : FlushMode ) : Void { + } + + public function close() : Void { + } + + public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes { + if( s.length == 0 ) { + // Flash returns 0 bytes for 0 length compress (which can't be decoded on other platforms...) + var b = haxe.io.Bytes.alloc(8); + b.set(0,0x78);b.set(1,0xDA);b.set(2,0x03); + b.set(7,0x01); + return b; + } + var tmp = new flash.utils.ByteArray(); + tmp.writeBytes(s.getData(),0,s.length); + tmp.compress(); + return haxe.io.Bytes.ofData(tmp); + } + +} diff --git a/std/js/Scroll.hx b/std/flash/_std/haxe/zip/Uncompress.hx similarity index 63% rename from std/js/Scroll.hx rename to std/flash/_std/haxe/zip/Uncompress.hx index ad4547e679ab98afb1c4c36c963e5457e574f01d..8dbf8402b1330ec8a6f4a37f3bd1d9fe9f81254e 100644 --- a/std/js/Scroll.hx +++ b/std/flash/_std/haxe/zip/Uncompress.hx @@ -19,34 +19,30 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -package js; +package haxe.zip; -class Scroll { +@:coreApi +class Uncompress { - public static function getTop() : Int untyped { - var sy = window.pageYOffset; - if( __js__("typeof")(sy) == 'number' ) - return sy; - if( document.body ) { - sy = document.body.scrollTop; - if( sy ) return sy; - } - return document.documentElement.scrollTop; + public function new( ?windowBits : Int ) : Void { + throw "Not implemented for this platform"; } - public static function getLeft() : Int untyped { - var sx = window.pageXOffset; - if( __js__("typeof")(sx) == 'number' ) - return sx; - if( document.body ) { - sx = document.body.scrollLeft; - if( sx ) return sx; - } - return document.documentElement.scrollLeft; + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return null; } - public static function set(left:Int,top:Int) untyped { - window.scroll(left,top); + public function setFlushMode( f : FlushMode ) : Void { } -} \ No newline at end of file + public function close() : Void { + } + + public static function run( src : haxe.io.Bytes, ?bufsize : Int ) : haxe.io.Bytes { + var tmp = new flash.utils.ByteArray(); + tmp.writeBytes(src.getData(),0,src.length); + tmp.uncompress(); + return haxe.io.Bytes.ofData(tmp); + } + +} diff --git a/std/flash/display/DisplayObjectContainer.hx b/std/flash/display/DisplayObjectContainer.hx index 1b6aac24b10bb50890a1248212c1daca7c4fa15a..417c7a2db1d3cd449cc1e032e6b43bfdaa63a538 100644 --- a/std/flash/display/DisplayObjectContainer.hx +++ b/std/flash/display/DisplayObjectContainer.hx @@ -18,6 +18,7 @@ extern class DisplayObjectContainer extends InteractiveObject { function removeChildAt(index : Int) : DisplayObject; @:require(flash11) function removeChildren(beginIndex : Int = 0, endIndex : Int = 2147483647) : Void; function setChildIndex(child : DisplayObject, index : Int) : Void; + @:require(flash11_8) function stopAllMovieClips() : Void; function swapChildren(child1 : DisplayObject, child2 : DisplayObject) : Void; function swapChildrenAt(index1 : Int, index2 : Int) : Void; } diff --git a/std/flash/display/GraphicsPathCommand.hx b/std/flash/display/GraphicsPathCommand.hx index 340ab0045bfd06af4aa0c223fdf72bafc9f80965..48eff4c16e9adc5e6d43f41b662a7011bd18fa06 100644 --- a/std/flash/display/GraphicsPathCommand.hx +++ b/std/flash/display/GraphicsPathCommand.hx @@ -4,6 +4,7 @@ extern class GraphicsPathCommand { public static inline var LINE_TO = 2; public static inline var MOVE_TO = 1; public static inline var CURVE_TO = 3; + @:require(flash11) public static inline var CUBIC_CURVE_TO = 6; public static inline var WIDE_LINE_TO = 5; public static inline var WIDE_MOVE_TO = 4; public static inline var NO_OP = 0; diff --git a/std/flash/display/Stage.hx b/std/flash/display/Stage.hx index b8ba9236f8ffc6135078aad38ff2a7b8422456f4..3bebca4088bb964f51db03f1001ca91b7edecdbf 100644 --- a/std/flash/display/Stage.hx +++ b/std/flash/display/Stage.hx @@ -2,8 +2,9 @@ package flash.display; extern class Stage extends DisplayObjectContainer { var align : StageAlign; - @:require(flash11) var allowsFullScreen(default,null) : Bool; + @:require(flash10_2) var allowsFullScreen(default,null) : Bool; @:require(flash11_3) var allowsFullScreenInteractive(default,null) : Bool; + @:require(flash15) var browserZoomFactor(default,null) : Float; @:require(flash10_2) var color : UInt; @:require(flash10) var colorCorrection : ColorCorrection; @:require(flash10) var colorCorrectionSupport(default,null) : ColorCorrectionSupport; diff --git a/std/flash/display/Stage3D.hx b/std/flash/display/Stage3D.hx index 2e0ab34aa31dddc948ff976690885e8262f5b630..e76f9b67c4aa0b9ae71cd8066c31d860d5519d38 100644 --- a/std/flash/display/Stage3D.hx +++ b/std/flash/display/Stage3D.hx @@ -5,5 +5,6 @@ package flash.display; var visible : Bool; var x : Float; var y : Float; - function requestContext3D(?context3DRenderMode : String, ?profile : flash.display3D.Context3DProfile) : Void; + function requestContext3D(?context3DRenderMode : flash.display3D.Context3DRenderMode, ?profile : flash.display3D.Context3DProfile) : Void; + @:require(flash12) function requestContext3DMatchingProfiles(profiles : flash.Vector) : Void; } diff --git a/std/flash/display3D/Context3D.hx b/std/flash/display3D/Context3D.hx index 7a99349bd7d68bdb7e22ee90776cbe70fc7fb0df..e9154f7e413e471ec81a54bca90540dd5eb2bbe6 100644 --- a/std/flash/display3D/Context3D.hx +++ b/std/flash/display3D/Context3D.hx @@ -1,15 +1,22 @@ package flash.display3D; @:final extern class Context3D extends flash.events.EventDispatcher { + @:require(flash15) var backBufferHeight(default,null) : Int; + @:require(flash15) var backBufferWidth(default,null) : Int; var driverInfo(default,null) : String; var enableErrorChecking : Bool; + @:require(flash15) var maxBackBufferHeight : Int; + @:require(flash15) var maxBackBufferWidth : Int; + @:require(flash12) var profile(default,null) : String; function clear(red : Float = 0, green : Float = 0, blue : Float = 0, alpha : Float = 1, depth : Float = 1, stencil : UInt = 0, mask : UInt = 0xFFFFFFFF) : Void; - function configureBackBuffer(width : Int, height : Int, antiAlias : Int, enableDepthAndStencil : Bool = true, wantsBestResolution : Bool = false) : Void; + function configureBackBuffer(width : Int, height : Int, antiAlias : Int, enableDepthAndStencil : Bool = true, wantsBestResolution : Bool = false, wantsBestResolutionOnBrowserZoom : Bool = false) : Void; function createCubeTexture(size : Int, format : Context3DTextureFormat, optimizeForRenderToTexture : Bool, streamingLevels : Int = 0) : flash.display3D.textures.CubeTexture; - function createIndexBuffer(numIndices : Int) : IndexBuffer3D; + function createIndexBuffer(numIndices : Int, ?bufferUsage : Context3DBufferUsage) : IndexBuffer3D; function createProgram() : Program3D; + @:require(flash11_8) function createRectangleTexture(width : Int, height : Int, format : Context3DTextureFormat, optimizeForRenderToTexture : Bool) : flash.display3D.textures.RectangleTexture; function createTexture(width : Int, height : Int, format : Context3DTextureFormat, optimizeForRenderToTexture : Bool, streamingLevels : Int = 0) : flash.display3D.textures.Texture; - function createVertexBuffer(numVertices : Int, data32PerVertex : Int) : VertexBuffer3D; + function createVertexBuffer(numVertices : Int, data32PerVertex : Int, ?bufferUsage : Context3DBufferUsage) : VertexBuffer3D; + @:require(flash15) function createVideoTexture() : flash.display3D.textures.VideoTexture; function dispose(recreate : Bool = true) : Void; function drawToBitmapData(destination : flash.display.BitmapData) : Void; function drawTriangles(indexBuffer : IndexBuffer3D, firstIndex : Int = 0, numTriangles : Int = -1) : Void; @@ -18,16 +25,18 @@ package flash.display3D; function setColorMask(red : Bool, green : Bool, blue : Bool, alpha : Bool) : Void; function setCulling(triangleFaceToCull : Context3DTriangleFace) : Void; function setDepthTest(depthMask : Bool, passCompareMode : Context3DCompareMode) : Void; + @:require(flash16) function setFillMode( fillMode : Context3DFillMode ) : Void; function setProgram(program : Program3D) : Void; @:require(flash11_2) function setProgramConstantsFromByteArray(programType : Context3DProgramType, firstRegister : Int, numRegisters : Int, data : flash.utils.ByteArray, byteArrayOffset : UInt) : Void; function setProgramConstantsFromMatrix(programType : Context3DProgramType, firstRegister : Int, matrix : flash.geom.Matrix3D, transposedMatrix : Bool = false) : Void; function setProgramConstantsFromVector(programType : Context3DProgramType, firstRegister : Int, data : flash.Vector, numRegisters : Int = -1) : Void; function setRenderToBackBuffer() : Void; - function setRenderToTexture(texture : flash.display3D.textures.TextureBase, enableDepthAndStencil : Bool = false, antiAlias : Int = 0, surfaceSelector : Int = 0) : Void; + function setRenderToTexture(texture : flash.display3D.textures.TextureBase, enableDepthAndStencil : Bool = false, antiAlias : Int = 0, surfaceSelector : Int = 0, colorOutputIndex : Int = 0) : Void; @:require(flash11_6) function setSamplerStateAt(sampler : Int, wrap : Context3DWrapMode, filter : Context3DTextureFilter, mipfilter : Context3DMipFilter) : Void; function setScissorRectangle(rectangle : flash.geom.Rectangle) : Void; function setStencilActions(?triangleFace : Context3DTriangleFace, ?compareMode : Context3DCompareMode, ?actionOnBothPass : Context3DStencilAction, ?actionOnDepthFail : Context3DStencilAction, ?actionOnDepthPassStencilFail : Context3DStencilAction) : Void; function setStencilReferenceValue(referenceValue : UInt, readMask : UInt = 255, writeMask : UInt = 255) : Void; function setTextureAt(sampler : Int, texture : flash.display3D.textures.TextureBase) : Void; function setVertexBufferAt(index : Int, buffer : VertexBuffer3D, bufferOffset : Int = 0, ?format : Context3DVertexBufferFormat) : Void; + @:require(flash15) static var supportsVideoTexture(default,null) : Bool; } diff --git a/std/flash/display3D/Context3DBufferUsage.hx b/std/flash/display3D/Context3DBufferUsage.hx new file mode 100644 index 0000000000000000000000000000000000000000..96a4dca1e17cdd35474bd718d2c54c9b6d04355c --- /dev/null +++ b/std/flash/display3D/Context3DBufferUsage.hx @@ -0,0 +1,6 @@ +package flash.display3D; + +@:fakeEnum(String) @:require(flash12) extern enum Context3DBufferUsage { + DYNAMIC_DRAW; + STATIC_DRAW; +} diff --git a/std/flash/display3D/Context3DFillMode.hx b/std/flash/display3D/Context3DFillMode.hx new file mode 100644 index 0000000000000000000000000000000000000000..2d17d05aef3653eab3b3d8b13c17daaed36bfc75 --- /dev/null +++ b/std/flash/display3D/Context3DFillMode.hx @@ -0,0 +1,6 @@ +package flash.display3D; + +@:fakeEnum(String) @:require(flash16) extern enum Context3DFillMode { + SOLID; + WIREFRAME; +} diff --git a/std/flash/display3D/Context3DProfile.hx b/std/flash/display3D/Context3DProfile.hx index 72c892458a1d05a5b72cb660d21fada96c8d8cce..cd5184c7608d463b43e7df5afa244f8f8ad8420f 100644 --- a/std/flash/display3D/Context3DProfile.hx +++ b/std/flash/display3D/Context3DProfile.hx @@ -3,4 +3,7 @@ package flash.display3D; @:fakeEnum(String) extern enum Context3DProfile { BASELINE; BASELINE_CONSTRAINED; + BASELINE_EXTENDED; + STANDARD; + STANDARD_CONSTRAINED; } diff --git a/std/flash/display3D/Context3DTextureFilter.hx b/std/flash/display3D/Context3DTextureFilter.hx index b5f2d07aa3fa9590445ba081a03510c2cd5db10d..e47af2833d25802eb0063fb201fb81bce7d5f389 100644 --- a/std/flash/display3D/Context3DTextureFilter.hx +++ b/std/flash/display3D/Context3DTextureFilter.hx @@ -1,6 +1,10 @@ package flash.display3D; @:fakeEnum(String) extern enum Context3DTextureFilter { + ANISOTROPIC16X; + ANISOTROPIC2X; + ANISOTROPIC4X; + ANISOTROPIC8X; LINEAR; NEAREST; } diff --git a/std/flash/display3D/Context3DTextureFormat.hx b/std/flash/display3D/Context3DTextureFormat.hx index 39ff5672314ce7d5c799e6f5af972e2abc9079a9..0833a8560b5ba81299c7c3a755dc33cec9689159 100644 --- a/std/flash/display3D/Context3DTextureFormat.hx +++ b/std/flash/display3D/Context3DTextureFormat.hx @@ -6,4 +6,5 @@ package flash.display3D; BGR_PACKED; COMPRESSED; COMPRESSED_ALPHA; + RGBA_HALF_FLOAT; } diff --git a/std/flash/display3D/Context3DWrapMode.hx b/std/flash/display3D/Context3DWrapMode.hx index ab8788a5ee9aec7623988c3c2111977f5e392dcd..38999f3fb46cad73488e142ee0a956df6a877f08 100644 --- a/std/flash/display3D/Context3DWrapMode.hx +++ b/std/flash/display3D/Context3DWrapMode.hx @@ -2,5 +2,7 @@ package flash.display3D; @:fakeEnum(String) extern enum Context3DWrapMode { CLAMP; + CLAMP_U_REPEAT_V; REPEAT; + REPEAT_U_CLAMP_V; } diff --git a/std/flash/display3D/textures/VideoTexture.hx b/std/flash/display3D/textures/VideoTexture.hx new file mode 100644 index 0000000000000000000000000000000000000000..0c04f1d2d8b7f63e6ea3714c3c032bc0832696e3 --- /dev/null +++ b/std/flash/display3D/textures/VideoTexture.hx @@ -0,0 +1,9 @@ +package flash.display3D.textures; + +@:final extern class VideoTexture extends TextureBase { + var videoHeight(default,null) : Int; + var videoWidth(default,null) : Int; + function new() : Void; + function attachCamera(theCamera : flash.media.Camera) : Void; + function attachNetStream(netStream : flash.net.NetStream) : Void; +} diff --git a/std/flash/errors/ArgumentError.hx b/std/flash/errors/ArgumentError.hx index c9530682a94787a04e89fc44579db996fc63b855..ad8632579634927eb3128390438a1d75c2349259 100644 --- a/std/flash/errors/ArgumentError.hx +++ b/std/flash/errors/ArgumentError.hx @@ -1,4 +1,4 @@ -package flash.errors; - -@:native("ArgumentError") extern class ArgumentError extends Error { -} +package flash.errors; + +@:native("ArgumentError") extern class ArgumentError extends Error { +} diff --git a/std/flash/errors/SecurityError.hx b/std/flash/errors/SecurityError.hx index c1e827347454a5932fde0116fdf5214d9d9bd80c..ed8f5c057fdc5063a3b9ef4c331e6b212fed6a11 100644 --- a/std/flash/errors/SecurityError.hx +++ b/std/flash/errors/SecurityError.hx @@ -1,4 +1,4 @@ -package flash.errors; - -@:native("SecurityError") extern class SecurityError extends Error { -} +package flash.errors; + +@:native("SecurityError") extern class SecurityError extends Error { +} diff --git a/std/flash/errors/TypeError.hx b/std/flash/errors/TypeError.hx index fa90826c8db5aa0738fb29123e70b381b0c7ac08..0fcd9e0bf9537138cdf52339f790bfb2975e3cb7 100644 --- a/std/flash/errors/TypeError.hx +++ b/std/flash/errors/TypeError.hx @@ -1,4 +1,4 @@ -package flash.errors; - -@:native("TypeError") extern class TypeError extends Error { -} +package flash.errors; + +@:native("TypeError") extern class TypeError extends Error { +} diff --git a/std/flash/errors/VerifyError.hx b/std/flash/errors/VerifyError.hx index c8fd3e161a0396b52f5a4ec416bb6c1391f61be1..97cd5fa8aec53a03d2b960189f4606d0f59d61c7 100644 --- a/std/flash/errors/VerifyError.hx +++ b/std/flash/errors/VerifyError.hx @@ -1,4 +1,4 @@ -package flash.errors; - -@:native("VerifyError") extern class VerifyError extends Error { -} +package flash.errors; + +@:native("VerifyError") extern class VerifyError extends Error { +} diff --git a/std/flash/events/AVDictionaryDataEvent.hx b/std/flash/events/AVDictionaryDataEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..396ad8c2f7626972939dc089b361e91218bed0c4 --- /dev/null +++ b/std/flash/events/AVDictionaryDataEvent.hx @@ -0,0 +1,8 @@ +package flash.events; + +extern class AVDictionaryDataEvent extends Event { + var dictionary(default,null) : flash.utils.Dictionary; + var time(default,null) : Float; + function new(?type : String, bubbles : Bool = false, cancelable : Bool = false, ?init_dictionary : flash.utils.Dictionary, init_dataTime : Float = 0) : Void; + static var AV_DICTIONARY_DATA : String; +} diff --git a/std/flash/events/AVHTTPStatusEvent.hx b/std/flash/events/AVHTTPStatusEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..bed4c2e260ccba4e9b16761b5812ac2ad4fa1ce6 --- /dev/null +++ b/std/flash/events/AVHTTPStatusEvent.hx @@ -0,0 +1,9 @@ +package flash.events; + +extern class AVHTTPStatusEvent extends Event { + var responseHeaders : Array; + var responseURL : String; + var status(default,null) : Int; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, status : Int = 0, ?responseUrl : String, ?responseHeaders : Array) : Void; + static var AV_HTTP_RESPONSE_STATUS : String; +} diff --git a/std/flash/events/AVPauseAtPeriodEndEvent.hx b/std/flash/events/AVPauseAtPeriodEndEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..d211ebb9ab5b5c459b1f5ef9e53f2c8c2c1c34fc --- /dev/null +++ b/std/flash/events/AVPauseAtPeriodEndEvent.hx @@ -0,0 +1,7 @@ +package flash.events; + +extern class AVPauseAtPeriodEndEvent extends Event { + var userData(default,null) : Int; + function new(?type : String, bubbles : Bool = false, cancelable : Bool = false, userData : Int = 0) : Void; + static var AV_PAUSE_AT_PERIOD_END : String; +} diff --git a/std/flash/events/AVStatusEvent.hx b/std/flash/events/AVStatusEvent.hx index 8aca859cc33a47e1064cccb82ab360a0a520316e..24f618b495d143971ea17e54e7f57f6586eba473 100644 --- a/std/flash/events/AVStatusEvent.hx +++ b/std/flash/events/AVStatusEvent.hx @@ -6,6 +6,8 @@ extern class AVStatusEvent extends Event { var result(default,null) : flash.media.AVResult; function new(?type : String, bubbles : Bool = false, cancelable : Bool = false, ?inNotificationType : String, inResult : Int = 0, ?inDescription : String) : Void; static var AV_STATUS : String; + static var BACKGROUND_MANIFEST_ERROR : String; + static var BACKGROUND_MANIFEST_WARNING : String; static var BUFFER_STATE : String; static var DECODER_TYPE : String; static var DIMENSION_CHANGE : String; @@ -18,5 +20,6 @@ extern class AVStatusEvent extends Event { static var SEEK_COMPLETE : String; static var STEP_COMPLETE : String; static var STREAM_SWITCH : String; + static var TRICKPLAY_ENDED : String; static var WARNING : String; } diff --git a/std/flash/events/AVStreamSwitchEvent.hx b/std/flash/events/AVStreamSwitchEvent.hx index 80012772108a020a0f63459123a04c0b598ace1d..da837bb9105ae3d4218e2edbdbb0d92fc9d73733 100644 --- a/std/flash/events/AVStreamSwitchEvent.hx +++ b/std/flash/events/AVStreamSwitchEvent.hx @@ -2,10 +2,11 @@ package flash.events; extern class AVStreamSwitchEvent extends Event { var bitrate(default,null) : Int; + var description(default,null) : String; var switchType(default,null) : Int; var time(default,null) : Float; var userData(default,null) : Int; - function new(?type : String, bubbles : Bool = false, cancelable : Bool = false, time : Float = 0, switchType : Int = 0, bitrate : Int = 0, userData : Int = 0) : Void; + function new(?type : String, bubbles : Bool = false, cancelable : Bool = false, time : Float = 0, switchType : Int = 0, bitrate : Int = 0, ?description : String, userData : Int = 0) : Void; static var ABR_SWITCH : Int; static var AV_STREAM_SWITCH : String; static var PERIOD_SWITCH : Int; diff --git a/std/flash/events/DRMLicenseRequestEvent.hx b/std/flash/events/DRMLicenseRequestEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..db39bd6b9e9cff6ec7254917106684433c726362 --- /dev/null +++ b/std/flash/events/DRMLicenseRequestEvent.hx @@ -0,0 +1,7 @@ +package flash.events; + +extern class DRMLicenseRequestEvent extends Event { + var serverURL : String; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?inServerURL : String) : Void; + static var LICENSE_REQUEST : String; +} diff --git a/std/flash/events/DRMReturnVoucherCompleteEvent.hx b/std/flash/events/DRMReturnVoucherCompleteEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..076f21c49e7d9d7e871cb52f449ff1f336a5f7e8 --- /dev/null +++ b/std/flash/events/DRMReturnVoucherCompleteEvent.hx @@ -0,0 +1,10 @@ +package flash.events; + +extern class DRMReturnVoucherCompleteEvent extends Event { + var licenseID : String; + var numberOfVouchersReturned : Int; + var policyID : String; + var serverURL : String; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?inServerURL : String, ?inLicenseID : String, ?inPolicyID : String, inNumberOfVouchersReturned : Int = 0) : Void; + static var RETURN_VOUCHER_COMPLETE : String; +} diff --git a/std/flash/events/DRMReturnVoucherErrorEvent.hx b/std/flash/events/DRMReturnVoucherErrorEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..83b8911530df46d8a885923c0713d0b58be93451 --- /dev/null +++ b/std/flash/events/DRMReturnVoucherErrorEvent.hx @@ -0,0 +1,10 @@ +package flash.events; + +extern class DRMReturnVoucherErrorEvent extends ErrorEvent { + var licenseID : String; + var policyID : String; + var serverURL : String; + var subErrorID : Int; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?inDetail : String, inErrorID : Int = 0, inSubErrorID : Int = 0, ?inServerURL : String, ?inLicenseID : String, ?inPolicyID : String) : Void; + static var RETURN_VOUCHER_ERROR : String; +} diff --git a/std/flash/events/Event.hx b/std/flash/events/Event.hx index 909888b721b9db188a8fc24a7114ac6fed8a8375..af8180de96b5f00ad0f773103f2a6d894ca23a43 100644 --- a/std/flash/events/Event.hx +++ b/std/flash/events/Event.hx @@ -18,6 +18,7 @@ extern class Event { static var ACTIVATE : String; static var ADDED : String; static var ADDED_TO_STAGE : String; + @:require(flash15) static var BROWSER_ZOOM_CHANGE : String; static var CANCEL : String; static var CHANGE : String; static var CHANNEL_MESSAGE : String; diff --git a/std/flash/events/GameInputEvent.hx b/std/flash/events/GameInputEvent.hx index d3a8fa1d964e1c7c0743c7bd4a5dc43479d3fbc1..ea5b84bc7228bd98c2ed375477d6a2741a497c49 100644 --- a/std/flash/events/GameInputEvent.hx +++ b/std/flash/events/GameInputEvent.hx @@ -1,8 +1,9 @@ package flash.events; -@:final @:require(flash11_2) extern class GameInputEvent extends Event { +@:final @:require(flash11_8) extern class GameInputEvent extends Event { var device(default,null) : flash.ui.GameInputDevice; function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?device : flash.ui.GameInputDevice) : Void; static var DEVICE_ADDED : String; static var DEVICE_REMOVED : String; + static var DEVICE_UNUSABLE : String; } diff --git a/std/flash/events/HTTPStatusEvent.hx b/std/flash/events/HTTPStatusEvent.hx index b8703c63c95ac44026f5657323735cae486704e4..25d2e4daab7efe11e17aa007da02e5596be27e3c 100644 --- a/std/flash/events/HTTPStatusEvent.hx +++ b/std/flash/events/HTTPStatusEvent.hx @@ -1,10 +1,11 @@ package flash.events; extern class HTTPStatusEvent extends Event { + var redirected : Bool; @:require(flash10_1) var responseHeaders : Array; @:require(flash10_1) var responseURL : String; var status(default,null) : Int; - function new(type : String, bubbles : Bool = false, cancelable : Bool = false, status : Int = 0) : Void; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, status : Int = 0, redirected : Bool = false) : Void; @:require(flash10_1) static var HTTP_RESPONSE_STATUS : String; static var HTTP_STATUS : String; } diff --git a/std/flash/events/StageVideoAvailabilityEvent.hx b/std/flash/events/StageVideoAvailabilityEvent.hx index 586e83e1187be275e5b42a6758b059ff183f88c1..03a651219a490b164839878479fc94b7a54efabc 100644 --- a/std/flash/events/StageVideoAvailabilityEvent.hx +++ b/std/flash/events/StageVideoAvailabilityEvent.hx @@ -2,6 +2,8 @@ package flash.events; extern class StageVideoAvailabilityEvent extends Event { var availability(default,null) : String; + var driver : String; + var reason : String; function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?availability : String) : Void; static var STAGE_VIDEO_AVAILABILITY : String; } diff --git a/std/flash/events/VideoTextureEvent.hx b/std/flash/events/VideoTextureEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..2a10f06d355e83d61cc2e4dd49ae6b7fa42bcee1 --- /dev/null +++ b/std/flash/events/VideoTextureEvent.hx @@ -0,0 +1,9 @@ +package flash.events; + +extern class VideoTextureEvent extends Event { + var codecInfo : String; + var colorSpace(default,null) : String; + var status(default,null) : String; + function new(type : String, bubbles : Bool = false, cancelable : Bool = false, ?status : String, ?colorSpace : String) : Void; + static var RENDER_STATE : String; +} diff --git a/std/flash/media/AVABRProfileInfo.hx b/std/flash/media/AVABRProfileInfo.hx index 0f1619a02d6943115c42f5209302e4a8cfc9301e..90372068dc4af6887e683acee79e21711e602e61 100644 --- a/std/flash/media/AVABRProfileInfo.hx +++ b/std/flash/media/AVABRProfileInfo.hx @@ -2,5 +2,7 @@ package flash.media; extern class AVABRProfileInfo { var bitsPerSecond(default,null) : Int; - function new(init_bitsPerSecond : Int) : Void; + var height(default,null) : Int; + var width(default,null) : Int; + function new(init_bitsPerSecond : Int, init_width : Int, init_height : Int) : Void; } diff --git a/std/flash/media/AVCaptionStyle.hx b/std/flash/media/AVCaptionStyle.hx index a190a44623fb391eceafef331d19302d45e060df..dd1603b37997e4ebd412bf738d501ad899054403 100644 --- a/std/flash/media/AVCaptionStyle.hx +++ b/std/flash/media/AVCaptionStyle.hx @@ -3,6 +3,7 @@ package flash.media; extern class AVCaptionStyle { var backgroundColor : String; var backgroundOpacity : String; + var bottomInset : String; var edgeColor : String; var fillColor : String; var fillOpacity : String; diff --git a/std/flash/media/AVNetworkingParams.hx b/std/flash/media/AVNetworkingParams.hx new file mode 100644 index 0000000000000000000000000000000000000000..e0056540c191f548fc9273e9a65e448fc63d576c --- /dev/null +++ b/std/flash/media/AVNetworkingParams.hx @@ -0,0 +1,8 @@ +package flash.media; + +extern class AVNetworkingParams { + var forceNativeNetworking : Bool; + var readSetCookieHeader : Bool; + var useCookieHeaderForAllRequests : Bool; + function new(init_forceNativeNetworking : Bool = false, init_readSetCookieHeader : Bool = true, init_useCookieHeaderForAllRequests : Bool = false) : Void; +} diff --git a/std/flash/media/AVPeriodInfo.hx b/std/flash/media/AVPeriodInfo.hx index 437c9f89dd41f859470861598a847654817e2312..a5851039a16242d9c68497b95ed012f97cddaeb3 100644 --- a/std/flash/media/AVPeriodInfo.hx +++ b/std/flash/media/AVPeriodInfo.hx @@ -3,9 +3,13 @@ package flash.media; extern class AVPeriodInfo { var duration(default,null) : Float; var firstCuePointIndex(default,null) : Int; + var firstSubscribedTagIndex(default,null) : Int; var lastCuePointIndex(default,null) : Int; + var lastSubscribedTagIndex(default,null) : Int; var localStartTime(default,null) : Float; + var supportsTrickPlay(default,null) : Bool; + var targetDuration(default,null) : Float; var userData(default,null) : Int; var virtualStartTime(default,null) : Float; - function new(init_localStartTime : Float, init_virtualStartTime : Float, init_duration : Float, init_firstCuePointIndex : Int, init_lastCuePointIndex : Int, init_userData : Int) : Void; + function new(init_localStartTime : Float, init_virtualStartTime : Float, init_duration : Float, init_firstCuePointIndex : Int, init_lastCuePointIndex : Int, init_firstSubscribedTagIndex : Int, init_lastSubscribedTagIndex : Int, init_userData : Int, init_supportsTrickPlay : Bool, init_targetDuration : Float) : Void; } diff --git a/std/flash/media/AVPlayState.hx b/std/flash/media/AVPlayState.hx index cc8d4f268dede2bdc47c34aff655b179d429384c..6b49c80f4966d5d47f44edab59059a42b9ab03c9 100644 --- a/std/flash/media/AVPlayState.hx +++ b/std/flash/media/AVPlayState.hx @@ -9,6 +9,7 @@ extern class AVPlayState { static var PLAYING : Int; static var READY : Int; static var SUSPENDED : Int; + static var TRICK_PLAY : Int; static var UNINITIALIZED : Int; static var UNRECOVERABLE_ERROR : Int; } diff --git a/std/flash/media/AVResult.hx b/std/flash/media/AVResult.hx index b44b3c401788397fadd76ce28655b7f58dffa349..245e4d3b31982c5542d40416d7c7ba52c632c238 100644 --- a/std/flash/media/AVResult.hx +++ b/std/flash/media/AVResult.hx @@ -4,57 +4,98 @@ extern class AVResult { var result(default,null) : Int; function new(inResult : Int) : Void; static var ASYNC_OPERATION_IN_PROGRESS : Int; + static var AUDIO_ONLY_STREAM_END : Int; + static var AUDIO_ONLY_STREAM_START : Int; + static var AUDIO_START_ERROR : Int; static var BAD_MANIFEST_SIGNATURE : Int; + static var BAD_MEDIASAMPLE_FOUND : Int; static var BAD_MEDIA_INTERLEAVING : Int; static var CALLED_FROM_WRONG_THREAD : Int; + static var CANNOT_ERASE_TIMELINE : Int; static var CANNOT_FAIL_OVER : Int; + static var CANNOT_HANDLE_MAIN_MANIFEST_UPDATE : Int; static var CANNOT_LOAD_PLAY_LIST : Int; + static var CANNOT_SPLIT_TIMELINE : Int; static var CODEC_NOT_SUPPORTED : Int; static var COMPONENT_CREATION_FAILURE : Int; static var CONTAINER_NOT_SUPPORTED : Int; static var CONTENT_LENGTH_MISMATCH : Int; + static var CRYPTO_ALGORITHM_NOT_SUPPORTED : Int; + static var CRYPTO_ERROR_BAD_CERTIFICATE : Int; + static var CRYPTO_ERROR_BAD_PARAMETER : Int; + static var CRYPTO_ERROR_BUFFER_TOO_SMALL : Int; + static var CRYPTO_ERROR_CORRUPTED_DATA : Int; + static var CRYPTO_ERROR_DIGEST_FINISH : Int; + static var CRYPTO_ERROR_DIGEST_UPDATE : Int; + static var CRYPTO_ERROR_UNKNOWN : Int; static var CURRENT_PERIOD_EXPIRED : Int; static var DECODER_FAILED : Int; static var DEVICE_OPEN_ERROR : Int; + static var DID_NOT_GET_NEXT_FRAGMENT : Int; static var DRM_INIT_ERROR : Int; static var DRM_NOT_AVAILABLE : Int; + static var END_OF_PERIOD : Int; static var EOF : Int; static var FILE_NOT_FOUND : Int; + static var FILE_OPEN_ERROR : Int; + static var FILE_READ_ERROR : Int; static var FILE_STRUCTURE_INVALID : Int; + static var FILE_WRITE_ERROR : Int; static var FRAGMENT_READ_ERROR : Int; static var GENERIC_ERROR : Int; static var HTTP_TIME_OUT : Int; + static var ID3_PARSE_ERROR : Int; + static var INCOMPATIBLE_RENDER_MODE : Int; + static var INCOMPATIBLE_VERSION : Int; + static var INTERNAL_ERROR : Int; + static var INVALID_KEY : Int; static var INVALID_OPERATION : Int; static var INVALID_PARAMETER : Int; static var INVALID_REPLACE_DURATION : Int; static var INVALID_SEEK_TIME : Int; static var INVALID_WITH_AUDIO_ONLY_FILE : Int; static var IRRECOVERABLE_ERROR : Int; + static var KEY_NOT_FOUND : Int; + static var KEY_SERVER_NOT_FOUND : Int; + static var LISTENER_NOT_FOUND : Int; static var LIVE_HOLD : Int; static var LIVE_WINDOW_MOVED_BACKWARD : Int; static var LOST_CONNECTION_RECOVERABLE : Int; + static var MANIFEST_FILE_UNEXPECTEDLY_CHANGED : Int; static var NETWORK_DOWN : Int; static var NETWORK_ERROR : Int; static var NETWORK_UNAVAILABLE : Int; static var NOT_IMPLEMENTED : Int; + static var NO_AUDIO_SINK : Int; static var NO_FIXED_SIZE : Int; + static var NO_TIMELINE : Int; static var NO_USEABLE_BITRATE_PROFILE : Int; + static var NULL_OPERATION : Int; static var ONLY_ALLOWED_IN_PAUSED_STATE : Int; static var OPERATION_ABORTED : Int; static var OUT_OF_MEMORY : Int; static var OVERFLOW : Int; static var PARSE_ERROR : Int; + static var PARTIAL_REPLACEMENT : Int; static var PERIOD_HOLD : Int; static var PERIOD_NOT_LOADED : Int; static var PLAYBACK_NOT_ENABLED : Int; + static var POSTROLL_WITH_LIVE_NOT_ALLOWED : Int; static var PREVIOUS_STEP_SEEK_IN_PROGRESS : Int; + static var PROTOCOL_NOT_SUPPORTED : Int; static var RANGE_ERROR : Int; + static var RANGE_SPANS_READHEAD : Int; + static var RENDITION_M3U8_ERROR : Int; static var REPLACEMENT_FAILED : Int; static var RESOURCE_NOT_SPECIFIED : Int; + static var SECURITY_ERROR : Int; static var SEEK_FAILED : Int; + static var SEGMENT_SKIPPED_ON_FAILURE : Int; static var SIZE_UNKNOWN : Int; + static var SPS_PPS_FOUND_OUTSIDE_AVCC : Int; static var SUCCESS : Int; static var SWITCH_TO_ASYMMETRIC_PROFILE : Int; + static var TIMELINE_TOO_SHORT : Int; static var UNDERFLOW : Int; static var UNSUPPORTED_CONFIGURATION : Int; static var UNSUPPORTED_HLS_VERSION : Int; diff --git a/std/flash/media/AVSegmentedSource.hx b/std/flash/media/AVSegmentedSource.hx index 8d45a4171da0a8095609680c61f74587a32c0bfd..ab202aed68432aa8158ce2574a5c97b1592bc8e2 100644 --- a/std/flash/media/AVSegmentedSource.hx +++ b/std/flash/media/AVSegmentedSource.hx @@ -1,11 +1,21 @@ package flash.media; extern class AVSegmentedSource extends AVSource { + var cookieHeader(null,default) : String; + var masterUpdateInterval(null,default) : Int; + var networkingParams : AVNetworkingParams; + var useRedirectedUrl(null,default) : Bool; function new() : Void; + function clearPauseAtPeriodEnd(periodIndex : Int) : AVResult; function getABRProfileCount(periodIndex : Int) : Int; function getABRProfileInfoAtIndex(periodIndex : Int, abrProfileIndex : Int) : AVABRProfileInfo; + function getBackgroundPeriodInfo(periodIndex : Int) : AVPeriodInfo; + function getBackgroundTimeline() : AVTimeline; function getCuePoint(periodIndex : Int, cuePointIndex : Int) : AVCuePoint; + function getPerceivedBandwidth() : UInt; function getPeriodInfo(periodIndex : Int) : AVPeriodInfo; + function getSubscribedTag(periodIndex : Int, tagDataIndex : Int) : AVTagData; + function getSubscribedTagForBackgroundManifest(periodIndex : Int, tagDataIndex : Int) : AVTagData; function getTimeline() : AVTimeline; function getTrackCount(periodIndex : Int, payloadType : String) : Int; function getTrackInfo(periodIndex : Int, payloadType : String, trackIndex : Int) : AVTrackInfo; @@ -13,15 +23,27 @@ extern class AVSegmentedSource extends AVSource { function insertByVirtualTime(insertionTime : Float, handle : Int, userData : Int = 0, replaceDuration : Float = 0) : AVInsertionResult; function load(url : String, ?containerType : String, userData : Int = 0) : AVResult; function loadManifest(uri : String, userData : Int = 0, ?containerType : String) : AVResult; + function loadWithBackgroundManifest(url : String, containerType : String, userData : Int, backgroundManifest : String) : AVResult; function releaseManifest(handle : Int) : AVResult; - function removeByLocalTime(periodIndex : Int, timeStart : Float, timeEnd : Float) : AVResult; + function removeByLocalTime(periodIndex : Int, timeStart : Float, timeEnd : Float, replaceWithMainMedia : Bool) : AVResult; function removeByVirtualTime(virtualTimeStart : Float, virtualTimeEnd : Float) : AVResult; function selectTrack(periodIndex : Int, payloadType : String, trackIndex : Int) : AVResult; + function selectTrackString(periodIndex : Int, payloadType : String, trackString : String) : AVResult; function setABRParameters(params : AVABRParameters) : AVResult; function setBandwidth(bitsPerSecond : Int) : AVResult; + function setCuePointTags(tagArray : Array) : AVResult; function setHoldAt(time : Float) : AVResult; + function setPauseAtPeriodEnd(periodIndex : Int, userData : Int = 0) : AVResult; + function setSubscribedTags(tagArray : Array) : AVResult; + function setSubscribedTagsForBackgroundManifest(tagArray : Array) : AVResult; static var AUDIO : String; + static var AUDIO_DESCRIPTION : String; + static var AUDIO_LANGUAGE : String; + static var AUDIO_PID : String; + static var DASH : String; static var DATA : String; + static var DATA_DESCRIPTION : String; static var HLS : String; static var VIDEO : String; + static var VIDEO_DESCRIPTION : String; } diff --git a/std/flash/media/AVStream.hx b/std/flash/media/AVStream.hx index 1e0ad9910158b23a866fbd7f315f30c1ee960672..56b4a60d4f39ac43b0e19880779081dde84eb375 100644 --- a/std/flash/media/AVStream.hx +++ b/std/flash/media/AVStream.hx @@ -7,6 +7,7 @@ extern class AVStream extends flash.events.EventDispatcher { var bufferTime(null,default) : Float; var captionStyle(null,default) : AVCaptionStyle; var captionsEnabled : Bool; + var clientLivePoint(default,null) : Float; var currentFPS(default,null) : Float; var decoderType(default,null) : String; var droppedFrames(default,null) : Int; @@ -19,12 +20,16 @@ extern class AVStream extends flash.events.EventDispatcher { var volume : Float; function new(source : AVSource) : Void; function dispose() : Void; + function fastForward(rate : Float) : AVResult; function pause() : AVResult; function play() : AVResult; function resume() : Bool; + function rewind(rate : Float) : AVResult; function seek(offset : Float, inBufferSeek : Bool = true) : AVResult; + function seekToKeyFrame(offset : Float, inBufferSeek : Bool = true) : AVResult; function seekToLivePoint() : AVResult; function seekToLocalTime(periodIndex : Int, time : Float) : AVResult; + function setPlaySpeed(speed : Float, reserved : Float) : Void; function step(frames : Int) : AVResult; static var HARDWARE : String; static var SOFTWARE : String; diff --git a/std/flash/media/AVTagData.hx b/std/flash/media/AVTagData.hx new file mode 100644 index 0000000000000000000000000000000000000000..5b46941797e7ec15e6f94df439544f37f86d4e08 --- /dev/null +++ b/std/flash/media/AVTagData.hx @@ -0,0 +1,7 @@ +package flash.media; + +extern class AVTagData { + var data(default,null) : String; + var localTime(default,null) : Float; + function new(init_data : String, init_localTime : Float) : Void; +} diff --git a/std/flash/media/AVTrackInfo.hx b/std/flash/media/AVTrackInfo.hx index 73d665289bd92f91140ef691009afa0373500bf2..b47eafdf40ecedcc06d918e1778d1446451d3bb0 100644 --- a/std/flash/media/AVTrackInfo.hx +++ b/std/flash/media/AVTrackInfo.hx @@ -8,7 +8,9 @@ extern class AVTrackInfo { var description(default,null) : String; var forced(default,null) : Bool; var language(default,null) : String; - function new(init_description : String, init_language : String, init_defaultTrack : Bool, init_autoSelect : Bool, init_forced : Bool, init_activity : Bool, init_dataTrackInfoServiceType : String) : Void; + var pid(default,null) : Int; + function new(init_description : String, init_language : String, init_defaultTrack : Bool, init_autoSelect : Bool, init_forced : Bool, init_activity : Bool, init_dataTrackInfoServiceType : String, init_pid : Int) : Void; static var DTI_608_CAPTIONS : String; static var DTI_708_CAPTIONS : String; + static var DTI_WEBVTT_CAPTIONS : String; } diff --git a/std/flash/media/AVURLLoader.hx b/std/flash/media/AVURLLoader.hx new file mode 100644 index 0000000000000000000000000000000000000000..f0e2ab753cd0c64146c1a08ebaaf445dc5e8584f --- /dev/null +++ b/std/flash/media/AVURLLoader.hx @@ -0,0 +1,7 @@ +package flash.media; + +extern class AVURLLoader extends flash.net.URLLoader { + var cookieHeader(null,default) : String; + var stream : AVURLStream; + function new(?request : flash.net.URLRequest) : Void; +} diff --git a/std/flash/media/AVURLStream.hx b/std/flash/media/AVURLStream.hx new file mode 100644 index 0000000000000000000000000000000000000000..c416d8c2561462f4cb671e247b64539ee47215d6 --- /dev/null +++ b/std/flash/media/AVURLStream.hx @@ -0,0 +1,6 @@ +package flash.media; + +extern class AVURLStream extends flash.net.URLStream { + var cookieHeader(null,default) : String; + function new() : Void; +} diff --git a/std/flash/media/StageVideoAvailabilityReason.hx b/std/flash/media/StageVideoAvailabilityReason.hx new file mode 100644 index 0000000000000000000000000000000000000000..20ef59e4697b370dc94d9cf3759b663a42f9e64f --- /dev/null +++ b/std/flash/media/StageVideoAvailabilityReason.hx @@ -0,0 +1,10 @@ +package flash.media; + +extern class StageVideoAvailabilityReason { + function new() : Void; + static var DRIVER_TOO_OLD : String; + static var NO_ERROR : String; + static var UNAVAILABLE : String; + static var USER_DISABLED : String; + static var WMODE_INCOMPATIBLE : String; +} diff --git a/std/flash/net/NetStream.hx b/std/flash/net/NetStream.hx index 6bc9798fd9dc3471f353f008e6fc9a38e4a9da3b..1b4e6250f87d0a5821a48d119e14b3a5f0088007 100644 --- a/std/flash/net/NetStream.hx +++ b/std/flash/net/NetStream.hx @@ -63,4 +63,5 @@ extern class NetStream extends flash.events.EventDispatcher { function togglePause() : Void; @:require(flash10) static var CONNECT_TO_FMS : String; @:require(flash10) static var DIRECT_CONNECTIONS : String; + static function resetDRMVouchers() : Void; } diff --git a/std/flash/net/URLRequest.hx b/std/flash/net/URLRequest.hx index 41ece0f81b440c0ef0dc92738588e7862c8d823b..61707bf6455d51b69bff6f203af5e9a99948eada 100644 --- a/std/flash/net/URLRequest.hx +++ b/std/flash/net/URLRequest.hx @@ -8,4 +8,5 @@ package flash.net; var requestHeaders : Array; var url : String; function new(?url : String) : Void; + function useRedirectedURL(sourceRequest : URLRequest, wholeURL : Bool = false, ?pattern : Dynamic, ?replace : String) : Void; } diff --git a/std/flash/net/drm/DRMAddToDeviceGroupContext.hx b/std/flash/net/drm/DRMAddToDeviceGroupContext.hx new file mode 100644 index 0000000000000000000000000000000000000000..1ae481795e4f016e61001c3c34ff2915001da53b --- /dev/null +++ b/std/flash/net/drm/DRMAddToDeviceGroupContext.hx @@ -0,0 +1,6 @@ +package flash.net.drm; + +extern class DRMAddToDeviceGroupContext extends DRMManagerSession { + function new() : Void; + function addToDeviceGroup(deviceGroup : DRMDeviceGroup, forceRefresh : Bool) : Void; +} diff --git a/std/flash/net/drm/DRMDeviceGroup.hx b/std/flash/net/drm/DRMDeviceGroup.hx index 51c92081bd2d3f825b5d0f166201b271f5a8ce2e..fb2784f6b3688fc45a2dd9684ff8d9f0d08a1281 100644 --- a/std/flash/net/drm/DRMDeviceGroup.hx +++ b/std/flash/net/drm/DRMDeviceGroup.hx @@ -3,6 +3,7 @@ package flash.net.drm; @:final extern class DRMDeviceGroup { var authenticationMethod(default,null) : String; var domain(default,null) : String; + var name : String; var serverURL(default,null) : String; function new() : Void; } diff --git a/std/flash/net/drm/DRMManager.hx b/std/flash/net/drm/DRMManager.hx index b02071308fad7a6079dd8a92ef50ee19e0ffe3f1..e21977b61cfa22cc0b43ddd84bd08e8154866121 100644 --- a/std/flash/net/drm/DRMManager.hx +++ b/std/flash/net/drm/DRMManager.hx @@ -2,11 +2,18 @@ package flash.net.drm; extern class DRMManager extends flash.events.EventDispatcher { function new() : Void; + function addToDeviceGroup(deviceGroup : DRMDeviceGroup, forceRefresh : Bool = false) : Void; function authenticate(serverURL : String, domain : String, username : String, password : String) : Void; function loadPreviewVoucher(contentData : DRMContentData) : Void; function loadVoucher(contentData : DRMContentData, setting : String) : Void; + function removeFromDeviceGroup(deviceGroup : DRMDeviceGroup) : Void; + function resetDRMVouchers() : Void; + function resetDRMVouchersInternal(isAutoReset : Bool) : Void; + function returnVoucher(inServerURL : String, immediateCommit : Bool, licenseID : String, policyID : String) : Void; function setAuthenticationToken(serverUrl : String, domain : String, token : flash.utils.ByteArray) : Void; function storeVoucher(voucher : flash.utils.ByteArray) : Void; static var isSupported(default,null) : Bool; + static var networkIdleTimeout : Float; static function getDRMManager() : DRMManager; + static function getDRMManagerInternal() : DRMManager; } diff --git a/std/flash/net/drm/DRMManagerSession.hx b/std/flash/net/drm/DRMManagerSession.hx index 8b0c43402cd24206ed7d39f1439aa57f85c0378a..e8cb8b294edb1eb43c065ad063b60403d0e83be0 100644 --- a/std/flash/net/drm/DRMManagerSession.hx +++ b/std/flash/net/drm/DRMManagerSession.hx @@ -7,8 +7,9 @@ extern class DRMManagerSession extends flash.events.EventDispatcher { function checkStatus() : UInt; function errorCodeToThrow(errorCode : UInt) : Void; function getLastError() : UInt; + function getLastServerErrorString() : String; function getLastSubErrorID() : UInt; - function issueDRMErrorEvent(metadata : DRMContentData, errorID : Int, subErrorID : Int, ?eventType : String) : Void; + function issueDRMErrorEvent(metadata : DRMContentData, errorID : Int, subErrorID : Int, serverErrorString : String) : Void; function issueDRMStatusEvent(inMetadata : DRMContentData, voucher : DRMVoucher) : Dynamic; function onSessionComplete() : Void; function onSessionError() : Void; diff --git a/std/flash/net/drm/DRMRemoveFromDeviceGroupContext.hx b/std/flash/net/drm/DRMRemoveFromDeviceGroupContext.hx new file mode 100644 index 0000000000000000000000000000000000000000..251558f79b832689c59120b71a5016790de7985c --- /dev/null +++ b/std/flash/net/drm/DRMRemoveFromDeviceGroupContext.hx @@ -0,0 +1,6 @@ +package flash.net.drm; + +extern class DRMRemoveFromDeviceGroupContext extends DRMManagerSession { + function new() : Void; + function removeFromDeviceGroup(deviceGroup : DRMDeviceGroup) : Void; +} diff --git a/std/flash/net/drm/DRMResetContext.hx b/std/flash/net/drm/DRMResetContext.hx new file mode 100644 index 0000000000000000000000000000000000000000..b5c647fbbc438c507746bb143c44cad8a2d63d22 --- /dev/null +++ b/std/flash/net/drm/DRMResetContext.hx @@ -0,0 +1,7 @@ +package flash.net.drm; + +extern class DRMResetContext extends DRMManagerSession { + var m_isAutoReset : Bool; + function new(isAutoReset : Bool) : Void; + function doReset() : Void; +} diff --git a/std/flash/net/drm/DRMReturnVoucherContext.hx b/std/flash/net/drm/DRMReturnVoucherContext.hx new file mode 100644 index 0000000000000000000000000000000000000000..45fec93b10fa092ab7e8593ae71b7e9983c2651f --- /dev/null +++ b/std/flash/net/drm/DRMReturnVoucherContext.hx @@ -0,0 +1,6 @@ +package flash.net.drm; + +extern class DRMReturnVoucherContext extends DRMManagerSession { + function new() : Void; + function returnVoucher(inServerURL : String, immediateCommit : Bool, licenseID : String, policyID : String) : Void; +} diff --git a/std/flash/net/drm/DRMURLDownloadContext.hx b/std/flash/net/drm/DRMURLDownloadContext.hx index ec298ef489518d66cddbb16d07a1823f98fb4bb0..9cf8636951baade8865507d3b9b21b37b18d69bc 100644 --- a/std/flash/net/drm/DRMURLDownloadContext.hx +++ b/std/flash/net/drm/DRMURLDownloadContext.hx @@ -3,5 +3,5 @@ package flash.net.drm; extern class DRMURLDownloadContext extends flash.events.EventDispatcher { function new() : Void; function httpGetASync(url : String) : Void; - function httpPostAndReceiveASync(url : String, headerName : String, headerValue : String, data : flash.utils.ByteArray) : Void; + function httpPostAndReceiveASync(url : String, headerName : String, headerValue : String, data : flash.utils.ByteArray, serverType : UInt) : Void; } diff --git a/std/flash/net/drm/DRMVoucher.hx b/std/flash/net/drm/DRMVoucher.hx index e2f9897e435c4ebb934ff23ddfcab653002bf40d..809f83cb2bedc9092283bcf0cc5892c78006c852 100644 --- a/std/flash/net/drm/DRMVoucher.hx +++ b/std/flash/net/drm/DRMVoucher.hx @@ -1,10 +1,13 @@ package flash.net.drm; extern class DRMVoucher { + var licenseID(default,null) : String; var offlineLeaseEndDate(default,null) : Date; var offlineLeaseStartDate(default,null) : Date; var playbackTimeWindow(default,null) : DRMPlaybackTimeWindow; var policies(default,null) : Dynamic; + var policyID(default,null) : String; + var serverURL(default,null) : String; var voucherEndDate(default,null) : Date; var voucherStartDate(default,null) : Date; function new() : Void; diff --git a/std/flash/net/drm/VoucherAccessInfo.hx b/std/flash/net/drm/VoucherAccessInfo.hx index cc2ac76b93d33897333fb126ea9330174c6b5ce6..41c41dd59b7bd5b710670f698e4f927c12d252e7 100644 --- a/std/flash/net/drm/VoucherAccessInfo.hx +++ b/std/flash/net/drm/VoucherAccessInfo.hx @@ -2,7 +2,9 @@ package flash.net.drm; @:final extern class VoucherAccessInfo { var authenticationMethod(default,null) : String; + var deviceGroup(default,null) : DRMDeviceGroup; var displayName(default,null) : String; var domain(default,null) : String; + var policyID(default,null) : String; function new() : Void; } diff --git a/std/flash/system/AuthorizedFeatures.hx b/std/flash/system/AuthorizedFeatures.hx index 7756e87613332cbce6f586ee1cba00722cc384a7..a08f574e3a304803b6cecb0773bf934a8404972f 100644 --- a/std/flash/system/AuthorizedFeatures.hx +++ b/std/flash/system/AuthorizedFeatures.hx @@ -3,6 +3,8 @@ package flash.system; @:final @:require(flash11_3) extern class AuthorizedFeatures { function new() : Void; function createApplicationInstaller(strings : flash.xml.XML, icon : flash.utils.ByteArray) : ApplicationInstaller; + function enableAVURLLoader(loader : flash.media.AVURLLoader) : Bool; + function enableAVURLStream(stream : flash.media.AVURLStream) : Bool; @:require(flash11_4) function enableDiskCache(stream : flash.net.URLStream) : Bool; @:require(flash11_7) function enableHLSPlayback(stream : flash.media.AVStream) : Bool; @:require(flash11_4) function isFeatureEnabled(feature : String, ?data : String) : Bool; diff --git a/std/flash/system/ConnexionsClient.hx b/std/flash/system/ConnexionsClient.hx new file mode 100644 index 0000000000000000000000000000000000000000..923d25cdf5ca85e60a0d85cbe860b59f35703667 --- /dev/null +++ b/std/flash/system/ConnexionsClient.hx @@ -0,0 +1,9 @@ +package flash.system; + +@:final extern class ConnexionsClient { + function new() : Void; + function Connexions() : Dynamic; + function _init(topLocation : String, documentReferrer : String, windowLocation : String, movie : String, userAgent : String, timeout : UInt) : Void; + function autoAdd(port : Int) : Dynamic; + function manualAdd(port : Int) : Dynamic; +} diff --git a/std/flash/ui/GameInput.hx b/std/flash/ui/GameInput.hx index ec91f02b851255105fc7c4e84daba0eb4ca9af22..af19827c9dc91707af2a4fd6fef0917fc037319f 100644 --- a/std/flash/ui/GameInput.hx +++ b/std/flash/ui/GameInput.hx @@ -1,6 +1,6 @@ package flash.ui; -@:require(flash11_2) extern class GameInput extends flash.events.EventDispatcher { +@:require(flash11_8) extern class GameInput extends flash.events.EventDispatcher { static var isSupported(default,null) : Bool; static var numDevices(default,null) : Int; static function getDeviceAt(index : Int) : GameInputDevice; diff --git a/std/flash/ui/GameInputDevice.hx b/std/flash/ui/GameInputDevice.hx index 95b6516cf99e32381afbe4e65ec8ce07b2da2d65..dcca88199eabd977fe0409906bd472f3e0012b4f 100644 --- a/std/flash/ui/GameInputDevice.hx +++ b/std/flash/ui/GameInputDevice.hx @@ -1,6 +1,6 @@ package flash.ui; -@:final @:require(flash11_2) extern class GameInputDevice { +@:final @:require(flash11_8) extern class GameInputDevice { var enabled : Bool; var id(default,null) : String; var name(default,null) : String; diff --git a/std/flash/utils/Telemetry.hx b/std/flash/utils/Telemetry.hx index b88f9e6e48ae3260c482cbdc568e8c1e8c3d0845..7d2c94399c165502024ddf6bf86a8876b0673641 100644 --- a/std/flash/utils/Telemetry.hx +++ b/std/flash/utils/Telemetry.hx @@ -1,15 +1,10 @@ package flash.utils; -@:require(flash11_2) extern class Telemetry extends flash.events.EventDispatcher { - var bufferLength : UInt; - var connected(default,null) : Bool; - function new() : Void; - function enableMetric(metric : String, enable : Bool) : Void; - function flush() : Void; - function isMetricEnabled(metric : String) : Bool; - function registerMethod(functionId : String, f : Dynamic) : Void; - function sendMetric(metric : String, value : Dynamic) : Void; - function sendSpanMetric(metric : String, startMarker : Float) : Void; - static var marker(default,null) : Float; - static var telemetry(default,null) : Telemetry; -} +@:require(flash11_4) @:native("flash.profiler.Telemetry") extern class Telemetry extends flash.events.EventDispatcher { + static var connected(default,null) : Bool; + static var spanMarker(default,null) : Float; + static function registerCommandHandler(commandName : String, handler : Dynamic) : Bool; + static function unregisterCommandHandler(commandName : String) : Bool; + static function sendMetric(metric : String, value : Dynamic) : Void; + static function sendSpanMetric(metric : String, startMarker : Float) : Void; +} \ No newline at end of file diff --git a/std/flash8/Accessibility.hx b/std/flash8/Accessibility.hx deleted file mode 100644 index ddc52d2a1182ba12089d1b3f84235409efde1702..0000000000000000000000000000000000000000 --- a/std/flash8/Accessibility.hx +++ /dev/null @@ -1,13 +0,0 @@ -package flash; - -extern class Accessibility -{ - static function isActive() : Bool; - static function updateProperties() : Void; - // ? not documented ? - static function sendEvent(mc : MovieClip, childID : Dynamic, event : Dynamic, isNonHtml : Bool) : Void; - - private static function __init__() : Void untyped { - flash.Accessibility = _global["Accessibility"]; - } -} diff --git a/std/flash8/Boot.hx b/std/flash8/Boot.hx deleted file mode 100644 index b1911cf79b4f4577d715fb455cc7b75b9658e310..0000000000000000000000000000000000000000 --- a/std/flash8/Boot.hx +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C)2005-2012 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 flash; - -@:keep -class Boot { - - private static var def_color = 0; - private static var exception = null; - - private static function __string_rec(o : Dynamic,s : String) { - untyped { - if( s.length >= 20 ) - return "<...>"; // too much deep recursion - var t = __typeof__(o); - if( t == "movieclip" ) - t = "object"; - else if( t == "function" && (o.__name__ != null || o.__ename__ != null) ) - t = "object"; - switch( t ) { - case "object": - if( __instanceof__(o,Array) ) { - if( o.__enum__ != null ) { - if( o["length"] == 2 ) - return o[0]; - var str = o[0]+"("; - s += " "; - for( i in 2...o["length"] ) { - if( i != 2 ) - str += "," + __string_rec(o[i],s); - else - str += __string_rec(o[i],s); - } - return str + ")"; - } - var l = o["length"]; - var i; - var str = "["; - s += " "; - for( i in 0...l ) - str += (if (i > 0) "," else "")+__string_rec(o[i],s); - str += "]"; - return str; - } - var s2 = o["toString"](); - if( (__typeof__(s2) == "string" || __instanceof__(s2,String)) && s2 != "[object Object]" && s2 != "[type Function]" ) - return s2; - var k; - var str = "{\n"; - if( typeof(o) == "movieclip" ) - str = "MC("+o._name+") "+str; - s += " "; - var keys : Array = __keys__(o); - for( k in keys.iterator() ) { - if( k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" ) - continue; - if( str.length != 2 ) - str += ",\n"; - str += s + k + " : "+__string_rec(o[k],s); - } - s = s.substring(4); - if( str.length != 2 ) - str += "\n"; - str += s + "}"; - return str; - case "function": - return ""; - case "string": - return o; - default: - return String(o); - } - } - } - - private static function __closure(f,o) { - untyped { - var m = o[f]; - if( m == null ) - return null; - var f2 = function() { - var me = __arguments__["callee"]; - return me["f"]["apply"](me["o"],__arguments__); - }; - f2["f"] = m; - f2["o"] = o; - return f2; - } - } - - #if flash6 - private static function __interfLoop(cc : Dynamic,cl : Dynamic) { - if( cc == null ) - return false; - var intf : Array = cc.__interfaces__; - for( i in 0...intf.length ) { - var i = intf[i]; - if( i == cl || __interfLoop(i,cl) ) - return true; - } - return __interfLoop(cc.__super__,cl); - } - #end - - private static function __instanceof(o : Dynamic,cl) { - untyped { - if( !cl ) - return false; - if( __instanceof__(o,cl) ) { - if( cl == Array ) - return ( o[__unprotect__("__enum__")] == null ); - return true; - } - #if flash6 - if( __interfLoop(o[__unprotect__("__class__")],cl) ) - return true; - #end - switch( cast cl ) { - case Int: - return __typeof__(o) == "number" && __physeq__(Math.ceil(o),o%2147483648.0) && !(__physeq__(o,true) || __physeq__(o,false)); - case Float: - return __typeof__(o) == "number"; - case Bool: - return __physeq__(o,true) || __physeq__(o,false); - case String: - return __typeof__(o) == "string"; - case Dynamic: - return true; - default: - return o[__unprotect__("__enum__")] == cl || - (cl == Class && o[__unprotect__("__name__")] != null) || - (cl == Enum && o[__unprotect__("__ename__")] != null); - } - } - } - - private static function getTrace() : flash.TextField untyped { - var root = flash.Lib.current; - var tf : flash.TextField = root.__trace_txt; - if( tf == null ) { - var w = Stage.width, h = Stage.height; - if( w == 0 ) w = 800; - if( h == 0 ) h = 600; - root.createTextField("__trace_txt",1048500,0,0,w,h+30); - tf = root.__trace_txt; - var format = tf.getTextFormat(); - format.font = "_sans"; - tf.setNewTextFormat(format); - tf.selectable = false; - tf.textColor = def_color; - root.__trace_lines = new Array(); - } - return tf; - } - - private static function __set_trace_color( rgb : Int ) { - getTrace().textColor = rgb; - def_color = rgb; - } - - private static function __trace(v,inf : haxe.PosInfos) { - untyped { - var root = flash.Lib.current; - var tf = getTrace(); - var s = inf.fileName+(if( inf.lineNumber == null ) "" else ":"+inf.lineNumber)+": "+__string_rec(v, ""); - if( inf != null && inf.customParams != null ) - for( v in inf.customParams ) - s += "," + __string_rec(v, ""); - var lines : Array = root.__trace_lines["concat"](s.split("\n")); - tf.text = lines.join("\n"); - while( lines.length > 1 && tf.textHeight > Stage.height ) { - lines.shift(); - tf.text = lines.join("\n"); - } - root.__trace_lines = lines; - } - } - - static function __exc(v) { - var s = ""; - #if debug - var a : Array = untyped __eval__("$s"); - for( i in 0...a.length-1 ) - s += "\nCalled from "+a[i]; - var old = a.slice(0,a.length-1); - a.splice(0,a.length); - #end - if( untyped Lib.onerror != null ) - untyped Lib.onerror(__string_rec(v,""),#if debug old #else [] #end); - else - __trace(__string_rec(v,"")+s,cast { fileName : "(uncaught exception)" }); - } - - private static function __clear_trace() { - untyped { - var root = flash.Lib.current; - root.__trace_txt["removeTextField"](); - root.__trace_lines = null; - } - } - - private static function __init(current : Dynamic) untyped { - // only if not set yet - var g : Dynamic = _global; - if( !g.haxeInitDone ) { - g.haxeInitDone = true; - Array.prototype["copy"] = Array.prototype["slice"]; - Array.prototype["insert"] = function(i,x) { - __this__["splice"](i,0,x); - }; - Array.prototype["remove"] = function(obj) { - var i = 0; - var l = __this__["length"]; - while( i < l ) { - if( __this__[i] == obj ) { - __this__["splice"](i,1); - return true; - } - i++; - } - return false; - } - Array.prototype["iterator"] = function() { - return { - cur : 0, - arr : __this__, - hasNext : function() { - return __this__.cur < __this__.arr["length"]; - }, - next : function() { - return __this__.arr[__this__.cur++]; - } - } - }; - Array.prototype["map"] = function(f) { - var ret = []; - var i = 0; - var l = __this__["length"]; - while( i < l ) { - ret.push(f(__this__[i])); - i++; - } - return ret; - }; - Array.prototype["filter"] = function(f) { - var ret = []; - var i = 0; - var l = __this__["length"]; - while ( i < l ) { - if (f(__this__[i])) - ret.push(__this__[i]); - i++; - } - return ret; - }; - _global["ASSetPropFlags"](Array.prototype,null,7); - var cca = String.prototype["charCodeAt"]; - String.prototype["cca"] = cca; - String.prototype["charCodeAt"] = function(i) { - var x = __this__["cca"](i); - if( x <= 0 ) // fast NaN - return null; - return x; - }; - // create flash package (in for FP7 mark support) - if( _global["flash"] == null ) - _global["flash"] = {}; - } - // set the Lib variables - current.flash.Lib._global = _global; - current.flash.Lib._root = _root; - current.flash.Lib.current = current; - // prevent closure creation by setting untyped - current[__unprotect__("@instanceof")] = flash.Boot[__unprotect__("__instanceof")]; - current[__unprotect__("@closure")] = flash.Boot[__unprotect__("__closure")]; - // fix firefox default alignement - if( _global["Stage"]["align"] == "" ) - _global["Stage"]["align"] = "LT"; - #if mt mt.flash.Init.check(); #end - } - -} diff --git a/std/flash8/Button.hx b/std/flash8/Button.hx deleted file mode 100644 index a60d4c22bad7565e4c376e0eb3c06486a7b8705b..0000000000000000000000000000000000000000 --- a/std/flash8/Button.hx +++ /dev/null @@ -1,58 +0,0 @@ -package flash; - -extern class Button #if !flash_strict implements Dynamic #end { - - var _alpha : Float; - var enabled : Bool; - var _focusrect : Bool; - var _height : Float; - var _highquality : Int; //Deprecated - var menu : ContextMenu; - var _name : String; - var _parent : MovieClip; - var _quality : String; - var _rotation : Float; - var _soundbuftime : Float; - var tabEnabled : Bool; - var tabIndex : Int; - var _target : String; - var trackAsMenu : Bool; - var _url : String; - var useHandCursor : Bool; - var _visible : Bool; - var _width : Float; - var _x : Float; - var _xmouse : Float; - var _xscale : Float; - var _y : Float; - var _ymouse : Float; - var _yscale : Float; - - dynamic function onDragOut() : Void; - dynamic function onDragOver() : Void; - dynamic function onKeyDown() : Void; - dynamic function onKeyUp() : Void; - dynamic function onKillFocus(newFocus : Dynamic) : Void; - dynamic function onPress() : Void; - dynamic function onRelease() : Void; - dynamic function onReleaseOutside() : Void; - dynamic function onRollOut() : Void; - dynamic function onRollOver() : Void; - dynamic function onSetFocus(oldFocus : Dynamic) : Void; - - function getDepth() : Int; - -#if flash8 - var filters : Array; - var blendMode : Dynamic; - var cacheAsBitmap : Bool; - var scale9Grid : flash.geom.Rectangle; -#end - - private static function __init__() : Void untyped { - flash.Button = _global["Button"]; - } - -} - - diff --git a/std/flash8/Camera.hx b/std/flash8/Camera.hx deleted file mode 100644 index f4ccdd7c9dadb59e0014ceefbaffa02f6d202b1f..0000000000000000000000000000000000000000 --- a/std/flash8/Camera.hx +++ /dev/null @@ -1,42 +0,0 @@ -package flash; - -extern class Camera { - - static var names(default,null) : Array; - static function get( ?index : Int ) : Camera; - - var bandwidth(default,null) : Int; - - var fps(default,null) : Float; - var currentFps(default,null) : Float; - - var width(default,null) : Int; - var height(default,null) : Int; - - var index(default,null) : Int; - - var activityLevel(default,null) : Float; - var motionLevel(default,null) : Float; - - var muted(default,null) : Bool; - var name(default,null) : String; - - var quality(default,null) : Int; - var keyFrameInterval(default,null) : Int; - var loopback(default,null) : Bool; - var motionTimeOut(default,null) : Float; - - function setMode( width:Int, height:Int, ?fps:Float, ?favorArea:Bool ):Void; - function setMotionLevel( motionLevel:Float , ?timeOut:Float ):Void; - function setQuality( bandwidth:Int, ?quality:Int ):Void; - function setKeyFrameInterval(keyFrameInterval:Int):Void; - function setLoopback(compress:Bool):Void; - - dynamic function onActivity( active:Bool ):Void; - dynamic function onStatus( infoObject:Dynamic ):Void; - - private static function __init__() : Void untyped { - flash.Camera = _global["Camera"]; - } - -} diff --git a/std/flash8/Color.hx b/std/flash8/Color.hx deleted file mode 100644 index 963ffffe043604368f0b101325124ab26bc58c72..0000000000000000000000000000000000000000 --- a/std/flash8/Color.hx +++ /dev/null @@ -1,35 +0,0 @@ -package flash; - -#if flash_strict -typedef ColorTransform = { - var ra : Float; - var rb : Float; - var ga : Float; - var gb : Float; - var ba : Float; - var bb : Float; - var aa : Float; - var ab : Float; -} -#end - -extern class Color { - - function new(target : MovieClip) : Void; - - function setRGB(color:Int):Void; - function getRGB():Int; - -#if flash_strict - function setTransform(transformObject:ColorTransform):Void; - function getTransform():ColorTransform; -#else - function setTransform(transformObject:Dynamic):Void; - function getTransform() : { ra : Float, rb : Float, ga : Float, gb : Float, ba : Float, bb : Float, aa : Float, ab : Float }; -#end - - private static function __init__() : Void untyped { - flash.Color = _global["Color"]; - } - -} diff --git a/std/flash8/ContextMenu.hx b/std/flash8/ContextMenu.hx deleted file mode 100644 index 383769d69b569b6af1e227277423b743740c7775..0000000000000000000000000000000000000000 --- a/std/flash8/ContextMenu.hx +++ /dev/null @@ -1,15 +0,0 @@ -package flash; - -extern class ContextMenu { - function new( ?callb:Dynamic->ContextMenu->Void ) : Void; - function hideBuiltInItems():Void; - function copy() : ContextMenu; - - var customItems:Array; - var builtInItems:Dynamic; - dynamic function onSelect( v : Dynamic, c : ContextMenu ) : Void; - - private static function __init__() : Void untyped { - flash.ContextMenu = _global["ContextMenu"]; - } -} diff --git a/std/flash8/ContextMenuItem.hx b/std/flash8/ContextMenuItem.hx deleted file mode 100644 index 1f1395643b53c92af6496ea76b332660190d4912..0000000000000000000000000000000000000000 --- a/std/flash8/ContextMenuItem.hx +++ /dev/null @@ -1,18 +0,0 @@ -package flash; - -extern class ContextMenuItem { - function new(caption:String, callb:Dynamic->ContextMenuItem->Void, ?separatorBefore:Bool, ?enabled:Bool, ?visible:Bool) : Void; - function copy() : ContextMenuItem; - - dynamic function onSelect( v : Dynamic, c : ContextMenuItem ) : Void; - - var enabled:Bool; - var visible:Bool; - var caption:String; - var separatorBefore:Bool; - - private static function __init__() : Void untyped { - flash.ContextMenuItem = _global["ContextMenuItem"]; - } -} - diff --git a/std/flash8/ExtendedKey.hx b/std/flash8/ExtendedKey.hx deleted file mode 100644 index 5f5df0402f7530d4d60418262492b6ab74bd6b9d..0000000000000000000000000000000000000000 --- a/std/flash8/ExtendedKey.hx +++ /dev/null @@ -1,29 +0,0 @@ -package flash; - -#if flash_lite - -/** flash lite only **/ -extern class ExtendedKey { - - static var SOFT1 : String; - static var SOFT2 : String; - static var SOFT3 : String; - static var SOFT4 : String; - static var SOFT5 : String; - static var SOFT6 : String; - static var SOFT7 : String; - static var SOFT8 : String; - static var SOFT9 : String; - static var SOFT10 : String; - static var SOFT11 : String; - static var SOFT12 : String; - - private static function __init__() : Void untyped { - flash.ExtendedKey = _global["ExtendedKey"]; - } - -} - -#else - #error -#end diff --git a/std/flash8/Key.hx b/std/flash8/Key.hx deleted file mode 100644 index 9bd809bb637f047ba2305c25536b87cf095c25a0..0000000000000000000000000000000000000000 --- a/std/flash8/Key.hx +++ /dev/null @@ -1,58 +0,0 @@ -package flash; - -#if flash_strict -typedef KeyListener = { - function onKeyDown() : Void; - function onKeyUp() : Void; -} -#end - -extern class Key -{ - static inline var ALT : Int = 18; - static inline var ENTER : Int = 13; - static inline var SPACE : Int = 32; - static inline var UP : Int = 38; - static inline var DOWN : Int = 40; - static inline var LEFT : Int = 37; - static inline var RIGHT : Int = 39; - static inline var PGUP : Int = 33; - static inline var PGDN : Int = 34; - static inline var HOME : Int = 36; - static inline var END : Int = 35; - static inline var TAB : Int = 9; - static inline var CONTROL : Int = 17; - static inline var SHIFT : Int = 16; - static inline var ESCAPE : Int = 27; - static inline var INSERT : Int = 45; - static inline var DELETEKEY : Int = 46; - static inline var BACKSPACE : Int = 8; - static inline var CAPSLOCK : Int = 20; - - // hide : static property _listeners(default,null) : Array; - - static function getAscii():Int; - static function getCode():Int; -#if flash8 - static function isAccessible():Bool; -#end - static function isDown(code:Int):Bool; - static function isToggled(code:Int):Bool; - - static dynamic function onKeyDown() : Void; - static dynamic function onKeyUp() : Void; - -#if flash_strict - static function addListener(listener:KeyListener):Void; - static function removeListener(listener:KeyListener):Bool; -#else - static function addListener(listener:Dynamic):Void; - static function removeListener(listener:Dynamic):Bool; -#end - - private static function __init__() : Void untyped { - flash.Key = _global["Key"]; - flash.Key.addListener(flash.Key); - } - -} diff --git a/std/flash8/Lib.hx b/std/flash8/Lib.hx deleted file mode 100644 index 193f24ea7a360ca3ee367fde7dfe587bf51f484a..0000000000000000000000000000000000000000 --- a/std/flash8/Lib.hx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C)2005-2012 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 flash; - -class Lib { - - public static var _global : Dynamic; - public static var _root : MovieClip; - public static var current : MovieClip; - static var onerror : String -> Array -> Void; - - public static function trace( str : String ) { - untyped __trace__(str); - } - - public static function eval( str : String ) : Dynamic { - return untyped __eval__(str); - } - - public static function getURL( url : String, ?target : String ) { - untyped __geturl__(url,if( target == null ) "_self" else target); - } - - public static function fscommand( cmd : String, ?param : Dynamic ) { - untyped __geturl__("FSCommand:"+cmd,if( param == null ) "" else param); - } - - public static function print( cmd : String, ?kind : String ) { - kind = if (kind == "bframe" || kind == "bmax") "print:#"+kind else "print:"; - untyped __geturl__(kind,cmd); - } - - public inline static function getTimer() : Int { - return untyped __gettimer__(); - } - - public static function getVersion() : String { - return untyped _root["$version"]; - } - - public static function registerClass( name : String, cl : {} ) { - untyped _global["Object"]["registerClass"](name,cl); - } - - public static function keys( v : Dynamic ) : Array { - return untyped __keys__(v); - } - - public static function setErrorHandler(f) { - onerror = f; - } - -} - - diff --git a/std/flash8/LoadVars.hx b/std/flash8/LoadVars.hx deleted file mode 100644 index dd6733b81608153fde4b8cce905f6fa81e10bc2f..0000000000000000000000000000000000000000 --- a/std/flash8/LoadVars.hx +++ /dev/null @@ -1,34 +0,0 @@ -package flash; - -extern class LoadVars implements Dynamic -{ - var contentType:String; - var loaded:Bool; - - function new() : Void; - - function addRequestHeader(header:String, headerValue:String):Void; - // don't allow : function addRequestHeader( headers : Array ) : Void; - - function load(url:String):Bool; - function send(url:String,target:String,?method:String):Bool; - function sendAndLoad(url:String,targetObject:Dynamic,?method:String):Bool; - function getBytesLoaded():Int; - function getBytesTotal():Int; - function decode(queryString:String):Void; - function toString():String; - - dynamic function onLoad(success:Bool):Void; - dynamic function onData(src:String):Void; - - #if flash8 - dynamic function onHTTPStatus( status : Int ) : Void; - #end - - // undocumented var _customHeaders:Array; - - private static function __init__() : Void untyped { - flash.LoadVars = _global["LoadVars"]; - } - -} diff --git a/std/flash8/LocalConnection.hx b/std/flash8/LocalConnection.hx deleted file mode 100644 index b61d78f89144083e1d5d4e69aa5a96b10d0c7381..0000000000000000000000000000000000000000 --- a/std/flash8/LocalConnection.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash; - -extern class LocalConnection #if !flash_strict implements Dynamic #end { - - function new() : Void; - - function connect(connectionName:String):Bool; - function send(connectionName:String, methodName:String, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic, ?p6 : Dynamic ):Bool; - - function close():Void; - function domain():String; - dynamic function allowDomain(domain:String):Bool; - dynamic function allowInsecureDomain(domain:String):Bool; - dynamic function onStatus(infoObject:Dynamic):Void; - - private static function __init__() : Void untyped { - flash.LocalConnection = _global["LocalConnection"]; - } - -} diff --git a/std/flash8/Microphone.hx b/std/flash8/Microphone.hx deleted file mode 100644 index 0da16b990ef824823c59b7988360e7c45740d2cc..0000000000000000000000000000000000000000 --- a/std/flash8/Microphone.hx +++ /dev/null @@ -1,31 +0,0 @@ -package flash; - -extern class Microphone -{ - - static var names(default,null) : Array; - static function get(?index:Int) : Microphone; - - var activityLevel(default,null) : Float; - var gain(default,null) : Float; - var index(default,null) : Int; - var muted(default,null) : Bool; - var name(default,null) : String; - var silenceLevel(default,null) : Int; - var silenceTimeOut(default,null) : Float; - var rate(default,null) : Float; - var useEchoSuppression(default,null) : Bool; - - function setSilenceLevel(silenceLevel:Int,?timeOut:Float):Void; - function setRate(rate:Float):Void; - function setGain(gain:Float):Void; - function setUseEchoSuppression(useEchoSuppression:Bool):Void; - - dynamic function onActivity(active:Bool):Void; - dynamic function onStatus(infoObject:Dynamic):Void; - - private static function __init__() : Void untyped { - flash.Microphone = _global["Microphone"]; - } - -} diff --git a/std/flash8/Mouse.hx b/std/flash8/Mouse.hx deleted file mode 100644 index beffaf7eca78125a41592af9afd84960041f55b3..0000000000000000000000000000000000000000 --- a/std/flash8/Mouse.hx +++ /dev/null @@ -1,33 +0,0 @@ -package flash; - -#if flash_strict -typedef MouseListener = { - function onMouseDown() : Void; - function onMouseMove() : Void; - function onMouseUp() : Void; - function onMouseWheel( delta : Float, scrollTarget : String ) : Void; -} -#end - -extern class Mouse -{ - static function show():Int; - static function hide():Int; - static dynamic function onMouseDown() : Void; - static dynamic function onMouseMove() : Void; - static dynamic function onMouseUp() : Void; - -#if flash_strict - static function addListener(listener:MouseListener):Void; - static function removeListener(listener:MouseListener):Bool; -#else - static function addListener(listener:Dynamic):Void; - static function removeListener(listener:Dynamic):Bool; -#end - - private static function __init__() : Void untyped { - flash.Mouse = _global["Mouse"]; - flash.Mouse.addListener(cast flash.Mouse); - } - -} diff --git a/std/flash8/MovieClip.hx b/std/flash8/MovieClip.hx deleted file mode 100644 index 35ab2bc8f3072429ce6b00937de7f9b8ea339804..0000000000000000000000000000000000000000 --- a/std/flash8/MovieClip.hx +++ /dev/null @@ -1,181 +0,0 @@ -package flash; - -private extern class MCBounds { - var xMin : Float; - var xMax : Float; - var yMin : Float; - var yMax : Float; -} - -extern class MovieClip -#if !flash_strict -implements Dynamic -#end -{ - var useHandCursor : Bool; - var enabled : Bool; - var focusEnabled : Bool; - //var menu : ContextMenu; rare, and we don't want to add __init__ for ContextMenu all the time - var tabChildren : Bool; - var tabEnabled : Bool; - var tabIndex : Int; - var hitArea : MovieClip; - var trackAsMenu : Bool; - - var _x : Float; - var _y : Float; - var _xmouse : Float; - var _ymouse : Float; - var _xscale : Float; - var _yscale : Float; - var _width : Float; - var _height : Float; - var _alpha : Float; - var _lockroot : Bool; - var _visible : Bool; - var _target : String; - var _rotation : Float; - var _name : String; - var _droptarget(default,null) : String; - var _currentframe(default,null) : Int; - var _totalframes(default,null) : Int; - var _framesloaded(default,null) : Int; - var _quality : String; - var _focusrect : Bool; - var _soundbuftime : Float; - var _url : String; - var _parent : MovieClip; - - function getURL( url : String, ?window : String, ?method : String ) : Void; - function unloadMovie() : Void; - function loadVariables( url : String, ?method : String ) : Void; - function loadMovie( url : String, ?method : String ) : Void; - function attachMovie(id : String, name : String, depth : Int, ?initObject : Dynamic) : MovieClip; - - #if flash_strict - function swapDepths( depth : Int ) : Void; - #else - function swapDepths(mc : Dynamic) : Void; - #end - // function swapDepths( mc : String ) : Void; - // function swapDepths( mc : MovieClip ) : Void; - // function swapDepths( depth : Int ) : Void; - - function localToGlobal(pt : { x : Float, y : Float } ) : Void; - function globalToLocal(pt : { x : Float, y : Float } ) : Void; - - // optional param problem if called with a second Bool parameter - function hitTest( x_or_mc : Dynamic, ?y : Float, ?shape : Bool ) : Bool; - - // function hitTest( x : Float, y : Float, shape : Bool ) : Bool; - // function hitTest( mc : MovieClip ) : Bool; - function getBounds(bounds : MovieClip) : MCBounds; - // don't allow function getBounds( bounds : String ) - function getBytesLoaded() : Int; - function getBytesTotal() : Int; - function attachAudio(id : Dynamic) : Void; - function attachVideo(id : Dynamic) : Void; - function getDepth() : Int; - - function setMask(mc : MovieClip) : Void; - // don't allow setMask( mc : String ) : Void - function play() : Void; - function stop() : Void; - function nextFrame() : Void; - function prevFrame() : Void; - function gotoAndPlay(frame : Dynamic) : Void; - // frame : String | Int - function gotoAndStop(frame : Dynamic) : Void; - // frame : String | Int - function duplicateMovieClip(name : String, depth : Int, ?initObject : Dynamic) : MovieClip; - function removeMovieClip() : Void; - function startDrag( lockCenter : Bool, ?left : Float, ?top : Float, ?right : Float, ?bottom : Float ) : Void; - function stopDrag() : Void; - function createEmptyMovieClip(name : String, depth : Int) : MovieClip; - function beginFill(rgb : Int, ?alpha : Float) : Void; - -#if !flash6 - function getInstanceAtDepth(depth : Int) : MovieClip; - function getNextHighestDepth() : Int; -#end - -#if flash8 - function beginGradientFill(fillType : String, colors : Array, alphas : Array, ratios : Array, matrix : Dynamic, ?spreadMethod : String, ?interpolationMethod : String, ?focalPointRatio : Float ) : Void; -#else - function beginGradientFill(fillType : String, colors : Array, alphas : Array, ratios : Array, matrix : Dynamic) : Void; -#end - // matrix : flash.geom.Matrix | Anonymous object a...i | Anonymous object (matrixType x,y,w,h,r) - - function moveTo(x : Float, y : Float) : Void; - function lineTo(x : Float, y : Float) : Void; - function curveTo(controlX : Float, controlY : Float, anchorX : Float, anchorY : Float) : Void; -#if flash8 - function lineStyle( ?thickness : Float, ?rgb : Int, ?alpha : Float, ?pixelHinting : Bool, ?noScale : String, ?capsStyle : String, ?jointStyle : String, ?miterLimit : Float) : Void; -#else - function lineStyle( ?thickness : Float, ?rgb : Int, ?alpha : Float) : Void; -#end - function endFill() : Void; - function clear() : Void; - -#if flash8 - function createTextField(instanceName : String, depth : Int, x : Float, y : Float, width : Float, height : Float) : TextField; -#else - function createTextField(instanceName : String, depth : Int, x : Float, y : Float, width : Float, height : Float) : Void; -#end - function getTextSnapshot() : TextSnapshot; - function getSWFVersion() : Int; - - dynamic function onData() : Void; - dynamic function onDragOut() : Void; - dynamic function onDragOver() : Void; - dynamic function onEnterFrame() : Void; - dynamic function onKeyDown() : Void; - dynamic function onKeyUp() : Void; - dynamic function onKillFocus(newFocus : Dynamic) : Void; - dynamic function onLoad() : Void; - dynamic function onMouseDown() : Void; - dynamic function onMouseMove() : Void; - dynamic function onMouseUp() : Void; - dynamic function onPress() : Void; - dynamic function onRelease() : Void; - dynamic function onReleaseOutside() : Void; - dynamic function onRollOut() : Void; - dynamic function onRollOver() : Void; - dynamic function onSetFocus(oldFocus : Dynamic) : Void; - dynamic function onUnload() : Void; - -#if flash8 - var filters : Array; - var blendMode : Dynamic; - var cacheAsBitmap : Bool; - var opaqueBackground : Int; - var scrollRect : Dynamic; - var transform : flash.geom.Transform; - var scale9Grid : flash.geom.Rectangle; - - function getRect( bounds : MovieClip ) : MCBounds; - // don't allow bounds : String - - - function attachBitmap( bmp : flash.display.BitmapData, depth : Int, ?pixelSnapping : String, ?smoothing : Bool ) : Void; - function beginBitmapFill( bmp : flash.display.BitmapData , ?matrix:flash.geom.Matrix, ?repeat:Bool, ?smoothing:Bool ) : Void; - function lineGradientStyle( fillType:String, colors:Array, alphas:Array, ratios:Array, matrix:Dynamic, ?spreadMethod : String, ?interpolationMethod:String, ?focalPointRatio:Float ) : Void; - -#end - - - /** FP9 only **/ - var forceSmoothing : Bool; - - -// MT extension -#if flash_strict - var smc : flash.MovieClip; -#end - private static function __init__() : Void untyped { - flash.MovieClip = _global["MovieClip"]; - } - -} - - diff --git a/std/flash8/MovieClipLoader.hx b/std/flash8/MovieClipLoader.hx deleted file mode 100644 index c8dc8d2bfb537a46952e0a882034f1f5c8533ebb..0000000000000000000000000000000000000000 --- a/std/flash8/MovieClipLoader.hx +++ /dev/null @@ -1,46 +0,0 @@ -package flash; - -#if flash_strict -typedef MclListener = { - - function onLoadInit(target:MovieClip) : Void; - function onLoadStart(target:MovieClip) : Void; - function onLoadProgress(target:MovieClip, loaded : Int, total : Int) : Void; - function onLoadComplete(target:MovieClip, httpStatus : Int) : Void; - function onLoadError(target:MovieClip, error:String, httpStatus : Int) : Void; - -} -#end - -extern class MovieClipLoader -{ - // don't allow target : String - // and target : Int (_levelX ?) - - function new() : Void; - function getProgress(target:MovieClip): { bytesLoaded : Int, bytesTotal : Int }; - function loadClip(url:String, target:MovieClip):Bool; - function unloadClip(target:MovieClip):Bool; - - dynamic function onLoadInit(target:MovieClip) : Void; - dynamic function onLoadStart(target:MovieClip) : Void; - dynamic function onLoadProgress(target:MovieClip, loaded : Int, total : Int) : Void; - dynamic function onLoadComplete(target:MovieClip) : Void; - dynamic function onLoadError(target:MovieClip, error:String) : Void; - -#if flash_strict - function addListener(listener:MclListener):Bool; - function removeListener(listener:MclListener):Bool; -#else - function addListener(listener:Dynamic):Bool; - function removeListener(listener:Dynamic):Bool; -#end - - /** in FP 9 **/ - var checkPolicyFile : Bool; - - private static function __init__() : Void untyped { - flash.MovieClipLoader = _global["MovieClipLoader"]; - } - -} diff --git a/std/flash8/NetConnection.hx b/std/flash8/NetConnection.hx deleted file mode 100644 index d5f01aa4b47ebb5a228647c7708a79a970651233..0000000000000000000000000000000000000000 --- a/std/flash8/NetConnection.hx +++ /dev/null @@ -1,21 +0,0 @@ -package flash; - -extern class NetConnection #if !flash_strict implements Dynamic #end { - - var isConnected(default,null) : Bool; - var uri(default,null) : String; - - function new() : Void; - function connect( targetURI : String, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic ) : Bool; - function call( remoteMethod : String, resultObject : Dynamic, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic, ?p6 : Dynamic ) : Void; - function addHeader( header : String, mustUnderstand : Bool, object : Dynamic ) : Void; - function close() : Void; - - // events - dynamic function onStatus(infoObject : Dynamic) : Void; - dynamic function onResult(infoObject : Dynamic) : Void; - - private static function __init__() : Void untyped { - flash.NetConnection = _global["NetConnection"]; - } -} diff --git a/std/flash8/NetStream.hx b/std/flash8/NetStream.hx deleted file mode 100644 index 75799dc79fb494d770da0ccb28763d79cf95452d..0000000000000000000000000000000000000000 --- a/std/flash8/NetStream.hx +++ /dev/null @@ -1,39 +0,0 @@ -package flash; - -extern class NetStream -{ - var bufferLength(default,null) : Float; - var bufferTime(default,null) : Float; - var bytesLoaded(default,null) : Int; - var bytesTotal(default,null) : Int; - var time(default,null) : Float; - var currentFps(default,null) : Float; - var liveDelay(default,null) : Float; - - /** FP9 only **/ - var checkPolicyFile : Bool; - - function new( connection : NetConnection ) : Void; - dynamic function onMetaData( info : Dynamic ) : Void; - dynamic function onStatus( info : Dynamic ) : Void; - function publish( name : Dynamic, ?type : String ) : Void; - function play( name : String, ?start : Float, ?len : Float, ?reset : Dynamic ) : Void; - function receiveAudio( flag : Bool ) : Void; - function receiveVideo( flag : Dynamic ) : Void; - function pause( ?flag : Bool ) : Void; - function seek( offset : Float ) : Void; - function close() : Void; - function attachAudio( theMicrophone : Microphone ) : Void; - function attachVideo( theCamera : Camera, ?snapshotMilliseconds : Float ) : Void; - function send( handlerName : String, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic ) : Void; - function setBufferTime( bufferTime : Float ) : Void; - -#if flash8 - dynamic function onCuePoint( info : Dynamic ) : Void; -#end - - private static function __init__() : Void untyped { - flash.NetStream = _global["NetStream"]; - } - -} diff --git a/std/flash8/PrintJob.hx b/std/flash8/PrintJob.hx deleted file mode 100644 index 0db3578edd1a139007c9c9b30f5a35c2fb6b6925..0000000000000000000000000000000000000000 --- a/std/flash8/PrintJob.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash; - -extern class PrintJob -{ - function new() : Void; - function start():Bool; - function addPage(target:Dynamic, ?printArea:Dynamic, ?options:Dynamic, ?frameNum:Float):Bool; - function send():Void; - - var paperWidth(default,null) : Float; - var paperHeight(default,null) : Float; - var pageWidth(default,null) : Float; - var pageHeight(default,null) : Float; - var orientation(default,null) : String; - - private static function __init__() : Void untyped { - flash.PrintJob = _global["PrintJob"]; - } - -} diff --git a/std/flash8/Selection.hx b/std/flash8/Selection.hx deleted file mode 100644 index ced969ca8761f85ec56d900f3bd13668a719de63..0000000000000000000000000000000000000000 --- a/std/flash8/Selection.hx +++ /dev/null @@ -1,22 +0,0 @@ -package flash; - -typedef SelectionListener = { - var onSetFocus: TextField -> TextField -> Void; -} - -extern class Selection -{ - static function getBeginIndex():Int; - static function getEndIndex():Int; - static function getCaretIndex():Int; - static function getFocus():String; - static function setFocus(newFocus:Dynamic):Bool; - static function setSelection(beginIndex:Int, endIndex:Int):Void; - static function addListener(listener:SelectionListener):Void; - static function removeListener(listener:SelectionListener):Bool; - - private static function __init__() : Void untyped { - flash.Selection = _global["Selection"]; - } - -} diff --git a/std/flash8/SharedObject.hx b/std/flash8/SharedObject.hx deleted file mode 100644 index cc9f57992501a6a69c8eab42933b9df381fcff6e..0000000000000000000000000000000000000000 --- a/std/flash8/SharedObject.hx +++ /dev/null @@ -1,45 +0,0 @@ -package flash; - -extern class SharedObject -{ - #if flash8 - static function getLocal(name:String,?localPath:String,?secure:Bool):SharedObject; - #else - static function getLocal(name:String,?localPath:String):SharedObject; - #end - - static function getRemote(name:String,remotePath:String,?persistence:Dynamic):SharedObject; - static function deleteAll(url:String) : Void; - static function getDiskUsage(url:String) : Int; - - function send( handler : String, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic ) : Void; - function flush(?minDiskSpace:Float):Dynamic; - function connect( cnx : NetConnection ) : Bool; - function close():Void; - function getSize():Float; - function setFps(updatesPerSecond:Float):Bool; - - dynamic function onStatus(infoObject:Dynamic):Void; - dynamic function onSync(objArray:Array):Void; - - function clear() : Void; - - - #if flash_lite - /** flash lite only **/ - static function getMaxSize():Float; - - /** flash lite only **/ - static function addListener():Void; - - /** flash lite only **/ - static function removeListener(soName:String):Void; - #end - - var data:Dynamic; - - private static function __init__() : Void untyped { - flash.SharedObject = _global["SharedObject"]; - } - -} diff --git a/std/flash8/Sound.hx b/std/flash8/Sound.hx deleted file mode 100644 index a7b4f966126cd48f84b6eed31ab0b4dd4bff42a5..0000000000000000000000000000000000000000 --- a/std/flash8/Sound.hx +++ /dev/null @@ -1,35 +0,0 @@ -package flash; - -extern class Sound -{ - var duration(default,null):Float; - var id3(default,null):Dynamic; - var position(default,null):Float; - - /** FP9 only **/ - var checkPolicyFile : Bool; - - function new( ?target:Dynamic ) : Void; - - dynamic function onLoad(success:Bool):Void; - dynamic function onSoundComplete():Void; - dynamic function onID3():Void; - - function getPan():Float; - function getTransform():Dynamic; - function getVolume():Float; - function setPan(value:Float):Void; - function setTransform(transformObject:Dynamic):Void; - function setVolume(value:Float):Void; - function stop(?linkageID:String):Void; - function attachSound(id:String):Void; - function start(?secondOffset:Float, ?loops:Float):Void; - function loadSound(url:String, isStreaming:Bool):Void; - function getBytesLoaded():Float; - function getBytesTotal():Float; - - private static function __init__() : Void untyped { - flash.Sound = _global["Sound"]; - } - -} diff --git a/std/flash8/Stage.hx b/std/flash8/Stage.hx deleted file mode 100644 index 602a6a9e59767e2b911a1db0f0bd84855c110f49..0000000000000000000000000000000000000000 --- a/std/flash8/Stage.hx +++ /dev/null @@ -1,28 +0,0 @@ -package flash; - -extern class Stage -{ - static var width:Float; - static var height:Float; - static var scaleMode:String; - static var align:String; - static var showMenu:Bool; - static function addListener(listener:Dynamic):Void; - static function removeListener(listener:Dynamic):Void; - - #if flash8 - /** - Set to "fullScreen" in order to set Flash to fullscreen - (can only be done in Mouse/Keyboard event listener). - Don't forget allowfullscreen="true" in your SWF parameters. - **/ - static var displayState : String; - static var fullScreenSourceRect : flash.geom.Rectangle; - static dynamic function onFullScreen( full : Bool ) : Void; - #end - - private static function __init__() : Void untyped { - flash.Stage = _global["Stage"]; - } - -} diff --git a/std/flash8/System.hx b/std/flash8/System.hx deleted file mode 100644 index b3b52fa18c730815a293d72159511e6542c73acd..0000000000000000000000000000000000000000 --- a/std/flash8/System.hx +++ /dev/null @@ -1,15 +0,0 @@ -package flash; - -extern class System -{ - static var useCodepage:Bool; - static var exactSettings:Bool; - static function showSettings(?tabID:Float):Void; - static function setClipboard(text:String):Void; - static dynamic function onStatus(infoObject:Dynamic):Void; - - private static function __init__() : Void untyped { - flash.System = _global["System"]; - } - -} diff --git a/std/flash8/TextField.hx b/std/flash8/TextField.hx deleted file mode 100644 index c0451e0a5907154e159bd179fa1078ef57dbcfcf..0000000000000000000000000000000000000000 --- a/std/flash8/TextField.hx +++ /dev/null @@ -1,93 +0,0 @@ -package flash; - -extern class TextField -{ - var _x:Float; - var _y:Float; - var _xmouse:Float; - var _ymouse:Float; - var _xscale:Float; - var _yscale:Float; - var _width:Float; - var _height:Float; - var _alpha:Float; - var _visible:Bool; - var _target:String; - var _rotation:Float; - var _name:String; - var _framesloaded:Int; - var _droptarget:String; - var _currentframe:Int; - var _totalframes:Int; - var _quality:String; - var _focusrect:Bool; - var _soundbuftime:Float; - var _url:String; - var _parent:MovieClip; - - var autoSize:Dynamic; - var background:Bool; - var backgroundColor:Int; - var border:Bool; - var borderColor:Int; - var bottomScroll:Float; - var condenseWhite:Bool; - var embedFonts:Bool; - var hscroll:Float; - var html:Bool; - var htmlText:String; - var length:Int; - var maxChars:Int; - var maxhscroll:Float; - var maxscroll:Float; - var multiline:Bool; - var password:Bool; - var restrict:String; - var scroll:Float; - var selectable:Bool; - var tabEnabled:Bool; - var tabIndex:Int; - var text:String; - var textColor:Int; - var textHeight:Float; - var textWidth:Float; - var type:String; - var variable:String; - var wordWrap:Bool; - var mouseWheelEnabled:Bool; - -#if flash8 - var antiAliasType:String; - var gridFitType:String; - var sharpness:Float; - var filters : Array; - var thickness:Float; -#end - - var styleSheet:flash.text.StyleSheet; - - function replaceText(beginIndex:Int,endIndex:Int,newText:String):Void; - function replaceSel(newText:String):Void; - function getTextFormat(?beginIndex:Int,?endIndex:Int):TextFormat; - - // wtf ?? optional first argument ! - // if beginIndex and endIndex are null, does it works ? - function setTextFormat( begin : Dynamic, ?end : Dynamic, ?tf : TextFormat ):Void; - function removeTextField():Void; - function getNewTextFormat():TextFormat; - function setNewTextFormat(tf:TextFormat):Void; - function getDepth():Int; - function addListener(listener:Dynamic):Bool; - function removeListener(listener:Dynamic):Bool; - static function getFontList():Array; - - dynamic function onChanged(changedField:TextField):Void; - dynamic function onKillFocus(newFocus:Dynamic):Void; - dynamic function onScroller(scrolledField:TextField):Void; - dynamic function onSetFocus(oldFocus:Dynamic):Void; - - private static function __init__() : Void untyped { - flash.TextField = _global["TextField"]; - } - -} diff --git a/std/flash8/TextFormat.hx b/std/flash8/TextFormat.hx deleted file mode 100644 index b4162aa19496681944039178b711491a46d03958..0000000000000000000000000000000000000000 --- a/std/flash8/TextFormat.hx +++ /dev/null @@ -1,40 +0,0 @@ -package flash; - -extern class TextFormat -{ - var font:String; - var size:Float; - var color:Int; - var url:String; - var target:String; - var bold:Bool; - var italic:Bool; - var underline:Bool; - var align:String; - var leftMargin:Float; - var rightMargin:Float; - var indent:Float; - var leading:Float; - var blockIndent:Float; - var tabStops:Array; - var bullet:Bool; - - function new( ?font:String, ?size:Float, ?textColor:Int, - ?bold:Bool, ?italic:Bool, ?underline:Bool, - ?url:String, ?window:String, ?align:String, - ?leftMargin:Float, ?rightMargin:Float, ?indent:Float, - ?leading:Float ) : Void; - - function getTextExtent(text:String, ?width : Float) : Dynamic; - - #if flash8 - var kerning : Bool; - var letterSpacing : Float; - var display : String; - #end - - private static function __init__() : Void untyped { - flash.TextFormat = _global["TextFormat"]; - } - -} diff --git a/std/flash8/TextSnapshot.hx b/std/flash8/TextSnapshot.hx deleted file mode 100644 index f8bb5e241d2c67b72ba553908bc59796efdae3bc..0000000000000000000000000000000000000000 --- a/std/flash8/TextSnapshot.hx +++ /dev/null @@ -1,18 +0,0 @@ -package flash; - -extern class TextSnapshot -{ - function findText(startIndex:Int, textToFind:String, caseSensitive:Bool):Float; - function getCount():Int; - function getSelected(start:Int, ?end:Int):Bool; - function getSelectedText(?includeLineEndings:Bool):String; - function getText(start:Int, end:Int, ?includeLineEndings:Bool):String; - function hitTestTextNearPos(x:Float, y:Float, ?closeDist:Float):Float; - function setSelectColor(color:Int):Void; - function setSelected(start:Int, end:Int, select:Bool):Void; - - private static function __init__() : Void untyped { - flash.TextSnapshot = _global["TextSnapshot"]; - } - -} diff --git a/std/flash8/Video.hx b/std/flash8/Video.hx deleted file mode 100644 index 8075c1726b71d190a4e7859f71b35b9c1396ab95..0000000000000000000000000000000000000000 --- a/std/flash8/Video.hx +++ /dev/null @@ -1,30 +0,0 @@ -package flash; - -extern class Video -{ - var deblocking : Float; - var height : Float; - var smoothing : Bool; - var width : Float; - - function attachVideo( source : Dynamic ) : Void; - function clear() : Void; - - #if flash_lite - /** flash lite only **/ - function play():Bool; - /** flash lite only **/ - function close():Void; - /** flash lite only **/ - function stop():Void; - /** flash lite only **/ - function pause():Void; - /** flash lite only **/ - function resume():Void; - #end - - private static function __init__() : Void untyped { - flash.Video = _global["Video"]; - } - -} diff --git a/std/flash8/XMLRequest.hx b/std/flash8/XMLRequest.hx deleted file mode 100644 index 7608aad533000cd94ce02c117467030dcd1d89c7..0000000000000000000000000000000000000000 --- a/std/flash8/XMLRequest.hx +++ /dev/null @@ -1,19 +0,0 @@ -package flash; - -class XMLRequest { - - public static function send( url : String, xml : Xml, ?target : String, ?post : Bool, ?content : String ) { - var x : Dynamic = untyped xml.__x; - x.contentType = if( content == null ) "text/xml" else content; - x.send(url,if( target == null ) "_self" else target,if( post ) "POST" else "GET"); - } - - public static function load( url : String, xml : Xml, onData : Null -> Void, ?post : Bool, ?content : String ) { - var x : Dynamic = untyped xml.__x; - var recv = untyped __new__(_global["XML"]); - recv.onData = onData; - x.contentType = if( content == null ) "text/xml" else content; - x.sendAndLoad(url,recv); - } - -} \ No newline at end of file diff --git a/std/flash8/XMLSocket.hx b/std/flash8/XMLSocket.hx deleted file mode 100644 index f648fb778d2ae13145c9d7b5570a2e7be5a12a42..0000000000000000000000000000000000000000 --- a/std/flash8/XMLSocket.hx +++ /dev/null @@ -1,18 +0,0 @@ -package flash; - -extern class XMLSocket { - - function new() : Void; - function connect( url : String, port : Int ) : Void; - function send( data : Dynamic ) : Bool; - function close() : Bool; - dynamic function onData( src : String ) : Void; - //dynamic function onXML( src : Xml ) : Void; - dynamic function onConnect( success : Bool ) : Void; - dynamic function onClose() : Void; - - private static function __init__() : Void untyped { - flash.XMLSocket = _global["XMLSocket"]; - } - -} diff --git a/std/flash8/_std/Reflect.hx b/std/flash8/_std/Reflect.hx deleted file mode 100644 index 9579a4e1b802f0c53331a52988c4bc7754434cd8..0000000000000000000000000000000000000000 --- a/std/flash8/_std/Reflect.hx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C)2005-2012 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 Reflect { - - public inline static function hasField( o : Dynamic, field : String ) : Bool untyped { - return __this__["hasOwnProperty"]["call"](o,field); - } - - public inline static function field( o : Dynamic, field : String ) : Dynamic untyped { - return o[field]; - } - - public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped { - o[field] = value; - } - - static function findAccessor( c : Class, name : String ):Dynamic untyped { - do { - var getter = c.__properties__[name]; - if (getter != null) - return getter; - c = c.__super__; - } while (c != null); - return null; - } - - public static function getProperty( o : Dynamic, field : String ) : Dynamic untyped { - var getter = findAccessor( Std.is(o,Class) ? o : o.__class__, "get_" +field); - return if (getter != null) - o[getter]["apply"](o, [field]); - else - Reflect.field(o, field); - } - - public static inline function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void untyped { - var setter = findAccessor( Std.is(o,Class) ? o : o.__class__, "set_" +field); - return if (setter != null) - o[setter]["apply"](o, [value]); - else - Reflect.setField(o, field, value); - } - - public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic untyped { - return func["apply"](o,args); - } - - public static function fields( o : Dynamic ) : Array untyped { - if( o == null ) return new Array(); - var a : Array = __keys__(o); - var i = 0; - while( i < a.length ) { - if( a[i] == "__id__" || !a["hasOwnProperty"]["call"](o,a[i]) ) - a.splice(i,1); - else - ++i; - } - return a; - } - - public static function isFunction( f : Dynamic ) : Bool untyped { - return __typeof__(f) == "function" && f.__name__ == null; - } - - public static function compare( a : T, b : T ) : Int { - return ( a == b ) ? 0 : (((cast a) > (cast b)) ? 1 : -1); - } - - public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool { - return untyped f1 == f2 || (f1["f"] == f2["f"] && f1["o"] == f2["o"] && f1["f"] != null); - } - - public static function isObject( v : Dynamic ) : Bool untyped { - var t = __typeof__(v); - return (t == "string" || (t == "object" && v.__enum__ == null) || (t == "function" && v.__name__ != null)); - } - - public static function isEnumValue( v : Dynamic ) : Bool { - return v.__enum__ != null; - } - - public static function deleteField( o : Dynamic, field : String ) : Bool untyped { - if( __this__["hasOwnProperty"]["call"](o,field) != true ) return false; - __delete__(o,field); - return true; - } - - public static function copy( o : T ) : T { - var o2 : Dynamic = {}; - for( f in Reflect.fields(o) ) - Reflect.setField(o2,f,Reflect.field(o,f)); - return o2; - } - - @:overload(function( f : Array -> Void ) : Dynamic {}) - public static function makeVarArgs( f : Array -> Dynamic ) : Dynamic { - return function() { return f(untyped __arguments__); }; - } - -} diff --git a/std/flash8/_std/Std.hx b/std/flash8/_std/Std.hx deleted file mode 100644 index 028d5b93c0631e1d361b764f54b1c0abada387ef..0000000000000000000000000000000000000000 --- a/std/flash8/_std/Std.hx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C)2005-2012 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 Std { - - @:ifFeature("typed_cast") - public static function is( v : Dynamic, t : Dynamic ) : Bool { - return untyped flash.Boot.__instanceof(v,t); - } - - public static function string( s : Dynamic ) : String { - return untyped flash.Boot.__string_rec(s,""); - } - - public static inline function int( x : Float ) : Int { - return (cast x) | 0; - } - - public static function parseInt( x : String ) : Null untyped { - var v; - if( x.charCodeAt(1) == 'x'.code || x.charCodeAt(1) == 'X'.code) - v = _global["parseInt"](x); - else - v = _global["parseInt"](x, 10); - if( _global["isNaN"](v) ) - return null; - return v; - } - - public static function parseFloat( x : String ) : Float { - return untyped _global["parseFloat"](x); - } - - public static function random( x : Int ) : Int { - return untyped __random__(x); - } - - static function __init__() : Void untyped { - var g : Dynamic = _global; - g["Int"] = { __name__ : ["Int"] }; - g["Bool"] = { __ename__ : ["Bool"] }; - g.Dynamic = { __name__ : [__unprotect__("Dynamic")] }; - g.Class = { __name__ : [__unprotect__("Class")] }; - g.Enum = {}; - g.Void = { __ename__ : [__unprotect__("Void")] }; - g["Float"] = _global["Number"]; - g["Float"][__unprotect__("__name__")] = ["Float"]; - Array.prototype[__unprotect__("__class__")] = Array; - Array[__unprotect__("__name__")] = ["Array"]; - String.prototype[__unprotect__("__class__")] = String; - String[__unprotect__("__name__")] = ["String"]; - g["ASSetPropFlags"](Array.prototype,null,7); - } - -} diff --git a/std/flash8/_std/Type.hx b/std/flash8/_std/Type.hx deleted file mode 100644 index dd16ceb8051855dceb5ba841ec234c1c0defe9d2..0000000000000000000000000000000000000000 --- a/std/flash8/_std/Type.hx +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -enum ValueType { - TNull; - TInt; - TFloat; - TBool; - TObject; - TFunction; - TClass( c : Class ); - TEnum( e : Enum ); - TUnknown; -} - -@:coreApi class Type { - - public static function getClass( o : T ) : Class untyped { - if( o.__enum__ != null ) - return null; - return o.__class__; - } - - public static function getEnum( o : EnumValue ) : Enum untyped { - return o.__enum__; - } - - public static function getSuperClass( c : Class ) : Class untyped { - return c.__super__; - } - - - public static function getClassName( c : Class ) : String { - if( c == null ) - return null; - var a : Array = untyped c.__name__; - return a.join("."); - } - - public static function getEnumName( e : Enum ) : String { - var a : Array = untyped e.__ename__; - return a.join("."); - } - - public static function resolveClass( name : String ) : Class untyped { - var cl : Class = untyped __eval__(name); - // ensure that this is a class - if( cl == null || cl.__name__ == null ) - return null; - return cl; - } - - - public static function resolveEnum( name : String ) : Enum untyped { - var e : Enum = untyped __eval__(name); - // ensure that this is an enum - if( e == null || e.__ename__ == null ) - return null; - return e; - } - - public static function createInstance( cl : Class, args : Array ) : T untyped { - if( cl == Array ) return new Array(); - var o = { __constructor__ : cl, __proto__ : cl.prototype }; - cl["apply"](o,args); - return o; - } - - public static function createEmptyInstance( cl : Class ) : T untyped { - if( cl == Array ) return new Array(); - var o : Dynamic = __new__(_global["Object"]); - o.__proto__ = cl.prototype; - return o; - } - - public static function createEnum( e : Enum, constr : String, ?params : Array ) : T { - var f = Reflect.field(e,constr); - if( f == null ) throw "No such constructor "+constr; - if( Reflect.isFunction(f) ) { - if( params == null ) throw "Constructor "+constr+" need parameters"; - return Reflect.callMethod(e,f,params); - } - if( params != null && params.length != 0 ) - throw "Constructor "+constr+" does not need parameters"; - return f; - } - - public static function createEnumIndex( e : Enum, index : Int, ?params : Array ) : T { - var c : String = (untyped e.__constructs__)[index]; - if( c == null ) throw index+" is not a valid enum constructor index"; - return createEnum(e,c,params); - } - - public static function getInstanceFields( c : Class ) : Array { - var a = Reflect.fields(untyped c.prototype); - a.remove("__class__"); - c = untyped c.__super__; - while( c != null ) { - for( f in Reflect.fields(untyped c.prototype) ) { - a.remove(f); - a.push(f); - } - c = untyped c.__super__; - } - a.remove("__class__"); - return a; - } - - public static function getClassFields( c : Class ) : Array { - var a = Reflect.fields(c); - a.remove(__unprotect__("__name__")); - a.remove(__unprotect__("__interfaces__")); - a.remove(__unprotect__("__super__")); - a.remove(__unprotect__("__properties__")); - return a; - } - - public static function getEnumConstructs( e : Enum ) : Array { - var a : Array = untyped e.__constructs__; - return a.copy(); - } - - public static function typeof( v : Dynamic ) : ValueType { - switch( untyped __typeof__(v) ) { - case "null": return TNull; - case "boolean": return TBool; - case "string": return TClass(String); - case "number": - // this should handle all cases : NaN, +/-Inf and Floats outside range - if( Math.ceil(v) == v%2147483648.0 ) - return TInt; - return TFloat; - case "object": - var e = v.__enum__; - if( e != null ) - return TEnum(e); - var c = v.__class__; - if( c != null ) - return TClass(c); - return TObject; - case "function": - if( v.__name__ != null ) - return TObject; - return TFunction; - case "undefined": - return TNull; - default: - return TUnknown; - } - } - - public static function enumEq( a : T, b : T ) : Bool untyped { - if( a == b ) - return true; - if( a[0] != b[0] ) - return false; - for( i in 2...a.length ) - if( !enumEq(a[i],b[i]) ) - return false; - var e = a.__enum__; - if( e != b.__enum__ || e == null ) - return false; - return true; - } - - public static function enumConstructor( e : EnumValue ) : String { - return untyped e[0]; - } - - public static function enumParameters( e : EnumValue ) : Array { - return untyped e["slice"](2); - } - - public inline static function enumIndex( e : EnumValue ) : Int { - return untyped e[1]; - } - - public static function allEnums( e : Enum ) : Array { - var all = []; - var cst : Array = untyped e.__constructs__; - for( c in cst ) { - var v = Reflect.field(e,c); - if( !Reflect.isFunction(v) ) - all.push(v); - } - return all; - } - -} - diff --git a/std/flash8/_std/Xml.hx b/std/flash8/_std/Xml.hx deleted file mode 100644 index 26c04b40f8afd133d24741dd8db6185c433351ab..0000000000000000000000000000000000000000 --- a/std/flash8/_std/Xml.hx +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -enum XmlType { -} - -@:coreApi class Xml { - - public static var Element(default,null) : XmlType; - public static var PCData(default,null) : XmlType; - public static var CData(default,null) : XmlType; - public static var Comment(default,null) : XmlType; - public static var DocType(default,null) : XmlType; - public static var ProcessingInstruction(default,null) : XmlType; - public static var Document(default,null) : XmlType; - - - public var nodeName(get,set) : String; - public var nodeValue(get,set) : String; - public var parent(get,null) : Xml; - public var nodeType(default,null) : XmlType; - - private var __x : Dynamic; - - private static function convert( o : Dynamic ) : Xml { - if( o == null ) return null; - if( o.__w != null ) return o.__w; - - var r = new Xml(); - r.__x = o; - o.__w = r; - - r.nodeType = switch( untyped o["nodeType"] ) { - case 1: - Xml.Element; - case 3: - Xml.PCData; - default: - throw "unknow nodeType: "+untyped o["nodeType"]; - } - - return untyped r; - } - - public static function parse( str : String ) : Xml untyped { - var x = __new__(_global["XML"]); - x["parseXML"](str); - if( x["status"] != 0 ) - throw ("Xml parse error #"+x["status"]); - - var r = convert(x); - r.nodeType = Xml.Document; - return r; - } - - public static function createDocument() : Xml { - var o = untyped __new__(_global["XML"])["createElement"]( "#document" ); - - var r = convert(o); - r.nodeType = Xml.Document; - return r; - } - - public static function createCData( data : String ) : Xml { - var o = untyped __new__(_global["XML"])["createTextNode"]( data ); - var x = convert(o); - x.nodeType = Xml.CData; - return x; - } - - public static function createPCData( data : String ) : Xml { - var o = untyped __new__(_global["XML"])["createTextNode"]( data ); - return convert(o); - } - - public static function createElement( name : String ) : Xml { - var o = untyped __new__(_global["XML"])["createElement"]( name ); - return convert(o); - } - - public static function createComment( data : String ) : Xml { - throw "not implemented"; - return null; - } - - public static function createDocType( data : String ) : Xml { - var x = createPCData(""); - x.nodeType = Xml.DocType; - x.nodeValue = data; - return x; - } - - public static function createProcessingInstruction( data : String ) : Xml { - var x = createPCData(""); - x.nodeType = Xml.ProcessingInstruction; - x.nodeValue = data; - return x; - } - - private function new() : Void { - } - - public function firstChild() : Xml { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - return convert(this.__x[untyped "firstChild"]); - } - - public function firstElement() : Xml { - if( nodeType != Xml.Element && nodeType != Xml.Document ) - throw "bad nodeType"; - var e : Dynamic = __x[untyped "firstChild"]; - while( e != null && e[untyped "nodeType"] != 1 ) - e = e[untyped "nextSibling"]; - return convert(e); - } - - private function set_nodeName( n : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return __x[untyped "nodeName"] = n; - } - - private function set_nodeValue( v : String ) : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return __x[untyped "nodeValue"] = v; - } - - private function get_nodeName() : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return __x[untyped "nodeName"]; - } - - private function get_nodeValue() : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return __x[untyped "nodeValue"]; - } - - private function get_parent() : Xml { - return convert(__x[untyped "parentNode"]); - } - - public function iterator() : Iterator { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - return untyped { - cur: this.__x[untyped "firstChild"], - hasNext : function(){ - return __this__.cur != null; - }, - next : function(){ - var r = convert(__this__.cur); - __this__.cur = __this__.cur["nextSibling"]; - return r; - } - } - } - - public function elements() : Iterator { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - return untyped { - cur: this.__x[untyped "firstChild"], - hasNext : function() { - var r = __this__.cur; - while( r != null && r["nodeType"] != 1 ) - r = r["nextSibling"]; - __this__.cur = r; - return r != null; - }, - next : function(){ - var r = __this__.cur; - while( r != null && r["nodeType"] != 1 ) - r = r["nextSibling"]; - if( r == null ) { - __this__.cur = null; - return null; - } - __this__.cur = r["nextSibling"]; - return convert(r); - } - } - } - - public function elementsNamed( name : String ) : Iterator { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - return untyped { - cur: this.__x[untyped "firstChild"], - hasNext : function() { - var r = __this__.cur; - while( r != null && (r["nodeType"] != 1 || r["nodeName"] != name) ) - r = r["nextSibling"]; - __this__.cur = r; - return r != null; - }, - next : function(){ - var r = __this__.cur; - while( r != null && (r["nodeType"] != 1 || r["nodeName"] != name) ) - r = r["nextSibling"]; - if( r == null ) { - __this__.cur = null; - return null; - } - __this__.cur = r["nextSibling"]; - return convert(r); - } - } - } - - public function get( att : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return Reflect.field(__x[untyped "attributes"],att); - } - - public function set( att : String, value : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return Reflect.setField(__x[untyped "attributes"],att,value); - } - - public function exists( att : String ) : Bool { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return Reflect.hasField(__x[untyped "attributes"],att); - } - - public function remove( att : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - Reflect.deleteField(__x[untyped "attributes"],att); - } - - public function attributes() : Iterator { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return untyped __keys__(__x["attributes"])["iterator"](); - } - - public function addChild( x : Xml ) : Void { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - untyped __x[untyped "appendChild"](x.__x); - } - - public function removeChild( x : Xml ) : Bool { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - untyped if( x.__x["parentNode"] != __x ) - return false; - untyped x.__x["removeNode"](); - return true; - } - - public function insertChild( x : Xml, pos : Int ) : Void { - if( nodeType != Xml.Document && nodeType != Xml.Element ) - throw "bad nodeType"; - var c : Array = __x[untyped "childNodes"]; - if( pos <= c.length ) - __x[untyped "insertBefore"](untyped x.__x,c[pos]); - } - - public function toString() : String { - if( nodeType == Xml.Document ){ - var s = ""; - for( c in iterator() ) - s += c.toString(); - return s; - } - // only works for toplevel elements - if( nodeType == Xml.CData ) - return ""; - if( nodeType == Xml.ProcessingInstruction ) - return ""; - if( nodeType == Xml.DocType ) - return ""; - var s : String = __x.toString(); - return s.split(" />").join("/>"); - } - - static function __init__() : Void untyped { - Xml.Element = "element"; - Xml.PCData = "pcdata"; - Xml.CData = "cdata"; - Xml.Comment = "comment"; - Xml.DocType = "doctype"; - Xml.ProcessingInstruction = "processingInstruction"; - Xml.Document = "document"; - #if swf_mark - flash.Lib.current["Xml"] = Xml; - #end - } - -} diff --git a/std/flash8/_std/haxe/ds/ObjectMap.hx b/std/flash8/_std/haxe/ds/ObjectMap.hx deleted file mode 100644 index b0d92356b9ef0de927ee1fefdcdb1447542cc5d9..0000000000000000000000000000000000000000 --- a/std/flash8/_std/haxe/ds/ObjectMap.hx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C)2005-2013 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of h 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 h 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 ObjectMap implements Map.IMap { - - static var count = 0; - - static inline function assignId(obj: { } ):Int { - return untyped obj.__id__ = ++count; - } - - static inline function getId(obj: { } ):Int { - return untyped obj.__id__; - } - - var h: { }; - - public function new():Void { - h = untyped __new__(_global["Object"]); - untyped h.__keys__ = untyped __new__(_global["Object"]); - } - - public function set(key:K, value:V):Void untyped { - var id = "$" + (key.__id__ != null ? key.__id__ : assignId(key)); - h[id] = value; - h.__keys__[id] = key; - } - - public inline function get(key:K):Null { - return untyped h["$" +getId(key)]; - } - - public inline function exists(key:K):Bool { - return untyped h["hasOwnProperty"]("$" +getId(key)); - } - - public function remove( key : K ) : Bool { - var key = "$" + getId(key); - if( untyped !h["hasOwnProperty"](key) ) return false; - untyped __delete__(h,key); - untyped __delete__(h.__keys__,key); - return true; - } - - public function keys() : Iterator { - var a = []; - untyped { - var keys:Iterator = __hkeys__(h.__keys__)["iterator"](); - for (key in keys) { - if( h.hasOwnProperty("$" +key) ) - a.push(h.__keys__["$" +key]); - } - } - return a.iterator(); - } - - public function iterator() : Iterator { - return untyped { - ref : h, - it : __hkeys__(h.__keys__)["iterator"](), - hasNext : function() { return __this__.it[__unprotect__("hasNext")](); }, - next : function() { var i = __this__.it[__unprotect__("next")](); return __this__.ref["$" +i]; } - }; - } - - public function toString() : String { - var s = new StringBuf(); - s.add("{"); - var it = keys(); - for( i in it ) { - s.add(Std.string(i)); - s.add(" => "); - s.add(Std.string(get(i))); - if( it.hasNext() ) - s.add(", "); - } - s.add("}"); - return s.toString(); - } -} \ No newline at end of file diff --git a/std/flash8/display/BitmapData.hx b/std/flash8/display/BitmapData.hx deleted file mode 100644 index 0411adbc9aec8f74ef0cab5a3bfabdaff3e6c585..0000000000000000000000000000000000000000 --- a/std/flash8/display/BitmapData.hx +++ /dev/null @@ -1,50 +0,0 @@ -package flash.display; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -import flash.geom.Rectangle; -import flash.geom.Point; - -extern class BitmapData { - - static function loadBitmap( id : String ) : BitmapData; - - var width : Int; - var height : Int; - var rectangle : Rectangle; - var transparent : Bool; - - function new( width : Int, height : Int, ?transparent : Bool, ?fillcolor : Int ) : Void; - - function getPixel( x : Int, y : Int ) : Int; - function setPixel( x : Int, y : Int, color : Int ) : Void; - function getPixel32( x : Int, y : Int ) : Int; - function setPixel32( x : Int, y : Int, color : Int ) : Void; - - function fillRect( r : Rectangle, color : Int ) : Void; - function copyPixels( src : BitmapData, srcRect : Rectangle, dst : Point, ?alpha : BitmapData, ?alphaPos : Point, ?mergeAlpha : Bool ) : Void; - function applyFilter( source : BitmapData, sourceRect : Rectangle, dest : Point, filter : flash.filters.BitmapFilter ) : Int; - function scroll( dx : Int, dy : Int ) : Void; - function threshold( src : BitmapData , srcRect : Rectangle, dstPoint : Point, op : String, threshold : Int, ?color : Int, ?mask : Int, ?copy : Bool ) : Int; - function draw( source : Dynamic, ?matrix : flash.geom.Matrix, ?colortrans : flash.geom.ColorTransform, ?blendMode : Dynamic, ?clipRect : Rectangle, ?smooth : Bool) : Void; - function pixelDissolve( src : BitmapData, srcRect : Rectangle, dst : Point, ?seed : Int, ?npixels : Int, ?fillColor : Int ) : Int; - function floodFill( x : Int, y : Int, color : Int ) : Void; - function getColorBoundsRect( mask : Int, color : Int, ?fillColor : Bool ) : Rectangle; - function perlinNoise( x : Int, y : Int, num : Int, seed : Int, stitch : Bool, noise : Bool, ?channels : Int, ?gray : Bool, ?offsets : Array> ) : Void; - function colorTransform( r : Rectangle, trans : flash.geom.ColorTransform ) : Void; - function hitTest( firstPoint : Point, firstAlpha : Int, object : Dynamic, ?secondPoint : Point, ?secondAlpha : Int ) : Bool; - function paletteMap( source : BitmapData, srcRect : Rectangle, dst : Point, ?reds : Array, ?greens : Array, ?blues : Array, ?alphas : Array ) : Void; - function merge( src : BitmapData, srcRect : Rectangle, dst : Point, redMult : Int, greenMult : Int, blueMult : Int, alphaMult : Int ) : Void; - function noise( seed : Int, ?low : Int, ?high : Int, ?channels : Int, ?gray : Bool ) : Void; - function copyChannel( source : BitmapData, sourceRect : Rectangle, dest : Point, sourceChannel : Int, destChannel : Int ) : Void; - function clone() : BitmapData; - function dispose() : Void; - function generateFilterRect(sourceRect : Rectangle, filter : flash.filters.BitmapFilter ) : Rectangle; - - /** FP9 only **/ - function compare( b : BitmapData ) : BitmapData; // WTF ? - -} - diff --git a/std/flash8/external/ExternalInterface.hx b/std/flash8/external/ExternalInterface.hx deleted file mode 100644 index d8dd937dad7f6fea479a7f2f6d6f005a17d4257f..0000000000000000000000000000000000000000 --- a/std/flash8/external/ExternalInterface.hx +++ /dev/null @@ -1,10 +0,0 @@ -package flash.external; - -extern class ExternalInterface { - - static var available : Bool; - static var marshallExceptions : Bool; - static function addCallback( methodName : String, instance : Dynamic, method : Dynamic ) : Bool; - static function call( methodName : String, ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic, ?p6 : Dynamic, ?p7 : Dynamic, ?p8 : Dynamic, ?p9 : Dynamic ) : Dynamic; - -} \ No newline at end of file diff --git a/std/flash8/filters/BevelFilter.hx b/std/flash8/filters/BevelFilter.hx deleted file mode 100644 index 1a258ea8e16f49c674654e1e12ae82b6cc7b3e0c..0000000000000000000000000000000000000000 --- a/std/flash8/filters/BevelFilter.hx +++ /dev/null @@ -1,21 +0,0 @@ -package flash.filters; - -extern class BevelFilter extends BitmapFilter { - - var type : String; - var blurX : Float; - var blurY : Float; - var knockout : Bool; - var strength : Float; - var quality : Float; - var shadowAlpha : Float; - var shadowColor : Float; - var highlightAlpha : Float; - var highlightColor : Float; - var angle : Float; - var distance : Float; - - function new( ?distance : Float, ?angle : Float, ?highlightColor : Float, ?highlightAlpha : Float, ?shadowColor : Float, ?shadowAlpha : Float, ?blurX : Float, ?blurY : Float, ?strength : Float, ?quality : Float, ?type : String, ?knockout : Bool) : Void; - function clone() : BevelFilter; - -} diff --git a/std/flash8/filters/BitmapFilter.hx b/std/flash8/filters/BitmapFilter.hx deleted file mode 100644 index 907068898ff21b086513f95a12fb9f9bc08fa313..0000000000000000000000000000000000000000 --- a/std/flash8/filters/BitmapFilter.hx +++ /dev/null @@ -1,9 +0,0 @@ -package flash.filters; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class BitmapFilter { - -} diff --git a/std/flash8/filters/BlurFilter.hx b/std/flash8/filters/BlurFilter.hx deleted file mode 100644 index 954f46f92fdc8a22686e709d958a0827f87363d4..0000000000000000000000000000000000000000 --- a/std/flash8/filters/BlurFilter.hx +++ /dev/null @@ -1,12 +0,0 @@ -package flash.filters; - -extern class BlurFilter extends BitmapFilter { - - var quality : Float; - var blurX : Float; - var blurY : Float; - - function new( ?blurX : Float, ?blurY : Float, ?quality : Float ) : Void; - function clone() : BlurFilter; - -} diff --git a/std/flash8/filters/ColorMatrixFilter.hx b/std/flash8/filters/ColorMatrixFilter.hx deleted file mode 100644 index 483454ff17a51c6c262b42bcc2a7542ec4710105..0000000000000000000000000000000000000000 --- a/std/flash8/filters/ColorMatrixFilter.hx +++ /dev/null @@ -1,10 +0,0 @@ -package flash.filters; - -extern class ColorMatrixFilter extends BitmapFilter { - - var matrix : Array; // 20 Numbers - - function new( ?matrix : Array ) : Void; - function clone() : ColorMatrixFilter; - -} diff --git a/std/flash8/filters/ConvolutionFilter.hx b/std/flash8/filters/ConvolutionFilter.hx deleted file mode 100644 index 290ba41b15ff728322e71fd3bcf64597cf226477..0000000000000000000000000000000000000000 --- a/std/flash8/filters/ConvolutionFilter.hx +++ /dev/null @@ -1,18 +0,0 @@ -package flash.filters; - -extern class ConvolutionFilter extends BitmapFilter { - - var alpha : Float; - var color : Float; - var clamp : Bool; - var preserveAlpha : Bool; - var bias : Float; - var divisor : Float; - var matrix : Array; - var matrixX : Float; - var matrixY : Float; - - function new( ?matrixX : Float, ?matrixY : Float, ?matrix : Array, ?divisor : Float, ?bias : Float, ?preserveAlpha : Bool, ?clamp : Bool, ?color : Float, ?alpha : Float) : Void; - function clone() : ConvolutionFilter; - -} \ No newline at end of file diff --git a/std/flash8/filters/DisplacementMapFilter.hx b/std/flash8/filters/DisplacementMapFilter.hx deleted file mode 100644 index 8fddb89005bc75f609ca8f4aec5955659a53abf8..0000000000000000000000000000000000000000 --- a/std/flash8/filters/DisplacementMapFilter.hx +++ /dev/null @@ -1,18 +0,0 @@ -package flash.filters; - -extern class DisplacementMapFilter extends BitmapFilter { - - var alpha : Float; - var color : Float; - var mode : String; - var scaleX : Float; - var scaleY : Float; - var componentX : Float; - var componentY : Float; - var mapPoint : flash.geom.Point; - var mapBitmap : flash.display.BitmapData; - - function new( ?mapBitmap : flash.display.BitmapData, ?mapPoint : flash.geom.Point, ?componentX : Float, ?componentY : Float, ?scaleX : Float, ?scaleY : Float, ?mode : String, ?color : Float, ?alpha : Float ) : Void; - function clone() : DisplacementMapFilter; - -} \ No newline at end of file diff --git a/std/flash8/filters/DropShadowFilter.hx b/std/flash8/filters/DropShadowFilter.hx deleted file mode 100644 index 2d8881833246c932038e54cda6730489cffc6636..0000000000000000000000000000000000000000 --- a/std/flash8/filters/DropShadowFilter.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash.filters; - -extern class DropShadowFilter extends BitmapFilter { - - var hideObject : Bool; - var blurX : Float; - var blurY : Float; - var knockout : Bool; - var strength : Float; - var inner : Bool; - var quality : Float; - var alpha : Float; - var color : Float; - var angle : Float; - var distance : Float; - - function new( ?distance : Float, ?angle : Float, ?color : Float, ?alpha : Float, ?blurX : Float, ?blurY : Float, ?strength : Float, ?quality : Float, ?inner : Bool, ?knockout : Bool, ?hideObject : Bool ) : Void; - function clone() : DropShadowFilter; - -} diff --git a/std/flash8/filters/GlowFilter.hx b/std/flash8/filters/GlowFilter.hx deleted file mode 100644 index 3ffae83a89f2ded98ce72cc15ba9c63804f06ab8..0000000000000000000000000000000000000000 --- a/std/flash8/filters/GlowFilter.hx +++ /dev/null @@ -1,17 +0,0 @@ -package flash.filters; - -extern class GlowFilter extends BitmapFilter { - - var blurX : Float; - var blurY : Float; - var knockout : Bool; - var strength : Float; - var quality : Float; - var inner : Bool; - var alpha : Float; - var color : Float; - - function new( ?color : Float, ?alpha : Float, ?blurX : Float, ?blurY : Float, ?strength : Float, ?quality : Float, ?inner : Bool, ?knockout : Bool ) : Void; - function clone() : GlowFilter; - -} diff --git a/std/flash8/filters/GradientBevelFilter.hx b/std/flash8/filters/GradientBevelFilter.hx deleted file mode 100644 index 9fdf3b0b01242899da4c7d130a5da03dc6303d6d..0000000000000000000000000000000000000000 --- a/std/flash8/filters/GradientBevelFilter.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash.filters; - -extern class GradientBevelFilter extends BitmapFilter { - - var type : String; - var knockout : Bool; - var strength : Float; - var quality : Float; - var blurX : Float; - var blurY : Float; - var ratios : Array; - var alphas : Array; - var colors : Array; - var angle : Float; - var distance : Float; - - function new( ?distance : Float, ?angle : Float, ?colors : Array, ?alphas : Array, ?ratios : Array, ?blurX : Float, ?blurY : Float, ?strength : Float, ?quality : Float, ?type : String, ?knockout : Bool ) : Void; - function clone() : GradientBevelFilter; - -} \ No newline at end of file diff --git a/std/flash8/filters/GradientGlowFilter.hx b/std/flash8/filters/GradientGlowFilter.hx deleted file mode 100644 index a91030cf44a4dd007b43d85ffe040ab0d9491f39..0000000000000000000000000000000000000000 --- a/std/flash8/filters/GradientGlowFilter.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash.filters; - -extern class GradientGlowFilter extends BitmapFilter { - - var type : String; - var knockout : Bool; - var strength : Float; - var quality : Float; - var blurX : Float; - var blurY : Float; - var ratios : Array; - var alphas : Array; - var colors : Array; - var angle : Float; - var distance : Float; - - function new( ?distance : Float, ?angle : Float, ?colors : Array, ?alphas : Array, ?ratios : Array, ?blurX : Float, ?blurY : Float, ?strength : Float, ?quality : Float, ?type : String, ?knockout : Bool ) : Void; - function clone() : GradientGlowFilter; - -} \ No newline at end of file diff --git a/std/flash8/geom/ColorTransform.hx b/std/flash8/geom/ColorTransform.hx deleted file mode 100644 index 85959c4bea438b271379724c78f79fc726c4414c..0000000000000000000000000000000000000000 --- a/std/flash8/geom/ColorTransform.hx +++ /dev/null @@ -1,23 +0,0 @@ -package flash.geom; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class ColorTransform { - - var rgb : Float; - var blueOffset : Float; - var greenOffset : Float; - var redOffset : Float; - var alphaOffset : Float; - var blueMultiplier : Float; - var greenMultiplier : Float; - var redMultiplier : Float; - var alphaMultiplier : Float; - - function new( ?rm : Float, ?gm : Float, ?bm : Float, ?am : Float, ?ro : Float, ?go : Float, ?bo : Float, ?ao : Float ) : Void; - function toString() : String; - function concat( c : ColorTransform ) : Void; - -} \ No newline at end of file diff --git a/std/flash8/geom/Matrix.hx b/std/flash8/geom/Matrix.hx deleted file mode 100644 index fa2c9d3a20812c5dcc65c83fc824ab7495909c37..0000000000000000000000000000000000000000 --- a/std/flash8/geom/Matrix.hx +++ /dev/null @@ -1,34 +0,0 @@ -package flash.geom; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class Matrix { - - // 3x2 affine 2D matrix - var a : Float; - var b : Float; - var c : Float; - var d : Float; - var tx : Float; - var ty : Float; - - function new( ?a : Float, ?b : Float, ?c : Float, ?d : Float, ?tx : Float, ?ty : Float) : Void; - - function transformPoint( p : Point ) : Point; - function deltaTransformPoint( p : Point ) : Point; - function toString() : String; - function scale( sx : Float, sy : Float ) : Void; - function translate( tx : Float, ty : Float ) : Void; - function rotate( r : Float ) : Void; - function identity() : Void; - function invert() : Void; - function concat( m : Matrix ) : Void; - function clone() : Matrix; - - function createGradientBox( width : Float, height : Float, ?rot : Float, ?tx : Float, ?ty : Float ) : Void; - function createBox( scalex : Float, scaley : Float, ?rot : Float, ?tx : Float, ?ty : Float ) : Void; - - -} \ No newline at end of file diff --git a/std/flash8/geom/Point.hx b/std/flash8/geom/Point.hx deleted file mode 100644 index 93426da3af9faa982807ac458598788d0a7f27bb..0000000000000000000000000000000000000000 --- a/std/flash8/geom/Point.hx +++ /dev/null @@ -1,27 +0,0 @@ -package flash.geom; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class Point { - - var x : T; - var y : T; - var length : Float; - - function new( x : T, y : T ) : Void; - - function normalize( length : T ) : Void; - function add( p : Point ) : Point; - function subtract( p : Point ) : Point; - function equals( p : Point ) : Bool; - function offset( dx : T, dy : T ) : Void; - function clone() : Point; - function toString() : String; - - static function distance( p1 : Point, p2 : Point ) : T; - static function interpolate( p1 : Point, p2 : Point, f : T ) : Point; - static function polar( dist : T, angle : T ) : Point; - -} \ No newline at end of file diff --git a/std/flash8/geom/Rectangle.hx b/std/flash8/geom/Rectangle.hx deleted file mode 100644 index 1669f3a812bbfc8cb081dc273de05c878bc46641..0000000000000000000000000000000000000000 --- a/std/flash8/geom/Rectangle.hx +++ /dev/null @@ -1,45 +0,0 @@ -package flash.geom; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class Rectangle { - - var left : T; - var top : T; - var right : T; - var bottom : T; - - // OR - var x : T; - var y : T; - var width : T; - var height : T; - - // OR - var size : Point; - var bottomRight : Point; - var topLeft : Point; - - function new( x : T, y : T, w : T, h : T ) : Void; - - function equals( r : Rectangle ) : Bool; - function union( r : Rectangle ) : Rectangle; - function intersects( r : Rectangle ) : Bool; - function intersection( r : Rectangle ) : Rectangle; - function containsRectangle( r : Rectangle ) : Bool; - function containsPoint( p : Point ) : Bool; - function contains( x : Float, y : Float ) : Bool; - function offsetPoint( p : Point ) : Void; - function offset( x : T, y : T ) : Void; - - function inflatePoint( p : Point ) : Void; - function inflate( x : T, y : T ) : Void; - function isEmpty() : Bool; - function setEmpty() : Void; - function clone() : Rectangle; - - function toString() : String; - -} \ No newline at end of file diff --git a/std/flash8/geom/Transform.hx b/std/flash8/geom/Transform.hx deleted file mode 100644 index d800b9a0c033d6d3c4f8a8cd8c2764a8143c6731..0000000000000000000000000000000000000000 --- a/std/flash8/geom/Transform.hx +++ /dev/null @@ -1,17 +0,0 @@ -package flash.geom; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class Transform { - - var matrix : Matrix; - var concatenatedMatrix : Matrix; - var colorTransform : ColorTransform; - var concatenatedColorTransform : ColorTransform; - var pixelBounds : Rectangle; - - function new( mc : flash.MovieClip ) : Void; - -} \ No newline at end of file diff --git a/std/flash8/net/FileReference.hx b/std/flash8/net/FileReference.hx deleted file mode 100644 index 0d62d72283684087c6b118fa010f4174f5bad570..0000000000000000000000000000000000000000 --- a/std/flash8/net/FileReference.hx +++ /dev/null @@ -1,27 +0,0 @@ -package flash.net; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class FileReference { - - var creator : String; - var creationDate : Date; - var modificationDate : Date; - var size : Float; - var type : String; - var name : String; - var postData : String; - - function new() : Void; - - function browse( ?typeList : Array ) : Bool; - function upload( url : String ) : Bool; - function download( url : String, ?defaultName : String ) : Bool; - function cancel() : Void; - - function addListener( listener : Dynamic ) : Void; - function removeListener( listener : Dynamic ) : Bool; - -} \ No newline at end of file diff --git a/std/flash8/net/FileReferenceList.hx b/std/flash8/net/FileReferenceList.hx deleted file mode 100644 index c156097f52be4aae83cb7b9f4ff3d6da8a045241..0000000000000000000000000000000000000000 --- a/std/flash8/net/FileReferenceList.hx +++ /dev/null @@ -1,17 +0,0 @@ -package flash.net; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class FileReferenceList { - - var fileList : Array; - - function new() : Void; - - function browse( ?typeList : Array ) : Bool; - function addListener( listener : Dynamic ) : Void; - function removeListener( listener : Dynamic ) : Bool; - -} \ No newline at end of file diff --git a/std/flash8/system/Capabilities.hx b/std/flash8/system/Capabilities.hx deleted file mode 100644 index c802e40a757b205620140b98e30efe4f0118100d..0000000000000000000000000000000000000000 --- a/std/flash8/system/Capabilities.hx +++ /dev/null @@ -1,61 +0,0 @@ -package flash.system; - -extern class Capabilities -{ - static var hasAudio:Bool; - static var hasMP3:Bool; - static var hasAudioEncoder:Bool; - static var hasVideoEncoder:Bool; - static var screenResolutionX:Float; - static var screenResolutionY:Float; - static var screenDPI:Float; - static var screenColor:String; - static var pixelAspectRatio:Float; - static var hasAccessibility:Bool; - static var input:String; - static var isDebugger:Bool; - static var language:String; - static var manufacturer:String; - static var os:String; - static var serverString:String; - static var version:String; - static var hasPrinting:Bool; - static var playerType:String; - static var hasStreamingAudio:Bool; - static var hasScreenBroadcast:Bool; - static var hasScreenPlayback:Bool; - static var hasStreamingVideo:Bool; - static var hasEmbeddedVideo:Bool; - static var avHardwareDisable:Bool; - static var localFileReadDisable:Bool; - static var windowlessDisable:Bool; - - #if flash_lite - static var hasCompoundSound:Bool; - static var hasEmail:Bool; - static var hasMMS:Bool; - static var hasSMS:Bool; - static var hasMFI:Bool; - static var hasMIDI:Bool; - static var hasSMAF:Bool; - static var hasDataLoading:Bool; - static var has4WayKeyAS:Bool; - static var hasMouse:Bool; - static var hasMappableSoftKeys:Bool; - static var hasCMIDI:Bool; - static var hasStylus:Bool; - static var screenOrientation:String; - static var hasSharedObjects:Bool; - static var hasQWERTYKeyboard:Bool; - static var softKeyCount:Float; - static var audioMIMETypes:Array; - static var imageMIMETypes:Array; - static var videoMIMETypes:Array; - static var MIMETypes:String; - #end - - private static function __init__() : Void untyped { - flash.system.Capabilities = _global["System"]["capabilities"]; - } - -} diff --git a/std/flash8/system/IME.hx b/std/flash8/system/IME.hx deleted file mode 100644 index 17e44a0aaeb4318824466d81d37a86b8850d73d9..0000000000000000000000000000000000000000 --- a/std/flash8/system/IME.hx +++ /dev/null @@ -1,27 +0,0 @@ -package flash.system; - -extern class IME { - - static var ALPHANUMERIC_FULL : String; - static var ALPHANUMERIC_HALF : String; - static var CHINESE : String; - static var JAPANESE_HIRAGANA : String; - static var JAPANESE_KATAKANA_FULL : String; - static var JAPANESE_KATAKANA_HALF : String; - static var KOREAN : String; - static var UNKNOWN : String; - - static function getEnabled() : Bool; - static function setEnabled(enabled:Bool) : Bool; - static function getConversionMode() : String; - static function setConversionMode(mode:String) : Bool; - static function setCompositionString (composition:String) : Bool; - static function doConversion() : Bool; - static function addListener(listener:Dynamic) : Void; - static function removeListener(listener:Dynamic) : Bool; - - private static function __init__() : Void untyped { - flash.system.IME = _global["System"]["IME"]; - } - -} diff --git a/std/flash8/system/Security.hx b/std/flash8/system/Security.hx deleted file mode 100644 index 5ffeb6c63fbcb46cf0d2ff872c74198f20b8b487..0000000000000000000000000000000000000000 --- a/std/flash8/system/Security.hx +++ /dev/null @@ -1,17 +0,0 @@ -package flash.system; - -extern class Security -{ - static function allowDomain( domain : String ):Void; - static function allowInsecureDomain( domain : String ):Void; - static function loadPolicyFile(url:String):Void; - - #if flash8 - static var sandboxType(default,null) : String; - #end - - private static function __init__() : Void untyped { - flash.system.Security = _global["System"]["security"]; - } - -} diff --git a/std/flash8/text/StyleSheet.hx b/std/flash8/text/StyleSheet.hx deleted file mode 100644 index b4582a06b99dc9b90c57b94f87ee93dbb9031a45..0000000000000000000000000000000000000000 --- a/std/flash8/text/StyleSheet.hx +++ /dev/null @@ -1,20 +0,0 @@ -package flash.text; - -extern class StyleSheet -{ - function new() : Void; - function getStyle(name:String):Dynamic; - function setStyle(name:String,style:Dynamic):Void; - function clear():Void; - function getStyleNames():Array; - function transform(style:Dynamic):flash.TextFormat; - function parseCSS(cssText:String):Bool; - function parse(cssText:String):Bool; - function load(url:String):Bool; - dynamic function onLoad(success:Bool):Void; - - private static function __init__() : Void untyped { - flash.text.StyleSheet = _global["TextField"]["StyleSheet"]; - } - -} diff --git a/std/flash8/text/TextRenderer.hx b/std/flash8/text/TextRenderer.hx deleted file mode 100644 index ca2ac039870fbb2dd15198fc366de8e8aed04c4e..0000000000000000000000000000000000000000 --- a/std/flash8/text/TextRenderer.hx +++ /dev/null @@ -1,12 +0,0 @@ -package flash.text; - -#if !flash8 -"This class is only accesible in Flash8" -#end - -extern class TextRenderer { - - static var maxLevel : Float; - static function setAdvancedAntialiasingTable( fontName : String, fontStyle: String, colorType : String, advancedAntialiasingTable : Array ) : Void; - -} \ No newline at end of file diff --git a/std/haxe/CallStack.hx b/std/haxe/CallStack.hx index ec276c7e290926cb88562fb08d40ce562b6c0027..6ec69a678f7de71eec8cfa1a3816804bee683f3e 100644 --- a/std/haxe/CallStack.hx +++ b/std/haxe/CallStack.hx @@ -22,20 +22,54 @@ package haxe; /** - Elements return by [Stack] methods. + Elements return by `CallStack` methods. **/ enum StackItem { CFunction; Module( m : String ); FilePos( s : Null, file : String, line : Int ); Method( classname : String, method : String ); - Lambda( v : Int ); + LocalFunction( ?v : Int ); } /** Get informations about the call stack. **/ class CallStack { + #if js + static var lastException:js.Error; + + static function getStack(e:js.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); + } + } + stack.push(FilePos(method, site.getFileName(), site.getLineNumber())); + } + 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 /** Return the call stack elements, or an empty array if not available. @@ -45,41 +79,53 @@ class CallStack { var a = makeStack(untyped __dollar__callstack()); a.shift(); // remove Stack.callStack() return a; - #elseif flash9 + #elseif flash var a = makeStack( new flash.errors.Error().getStackTrace() ); a.shift(); // remove Stack.callStack() return a; - #elseif flash - return makeStack("$s"); #elseif php return makeStack("%s"); #elseif cpp var s:Array = untyped __global__.__hxcpp_get_call_stack(true); return makeStack(s); #elseif js - // 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) { - 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); - } - } - stack.push(FilePos(method, site.getFileName(), site.getLineNumber())); + try { + throw new js.Error(); + } catch( e : Dynamic ) { + var a = getStack(e); + 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 ); } - return stack; } - var a = makeStack(untyped __new__("Error").stack); - a.shift(); // remove Stack.callStack() - (untyped Error).prepareStackTrace = oldValue; - return a; + 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(null, elem._1, elem._2)); + return stack; #else return []; // Unsupported #end @@ -96,7 +142,7 @@ class CallStack { return makeStack(untyped __dollar__excstack()); #elseif as3 return new Array(); - #elseif flash9 + #elseif flash var err : flash.errors.Error = untyped flash.Boot.lastError; if( err == null ) return new Array(); var a = makeStack( err.getStackTrace() ); @@ -110,13 +156,45 @@ class CallStack { i--; } return a; - #elseif flash - return makeStack("$e"); #elseif php return makeStack("%e"); #elseif cpp var s:Array = untyped __global__.__hxcpp_get_exception_stack(); return makeStack(s); + #elseif java + var stack = []; + for ( el in java.internal.Exceptions.currentException().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(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(null, elem._1, elem._2)); + } + return stack; + #elseif js + return untyped __define_feature__("haxe.CallStack.exceptionStack", getStack(lastException)); #else return []; // Unsupported #end @@ -154,14 +232,14 @@ class CallStack { b.add(cname); b.add("."); b.add(meth); - case Lambda(n): + case LocalFunction(n): b.add("local function #"); b.add(n); } } #if cpp @:noStack #end /* Do not mess up the exception stack */ - private static function makeStack(s) { + private static function makeStack(s #if cs : cs.system.diagnostics.StackTrace #end) { #if neko var a = new Array(); var l = untyped __dollar__asize(s); @@ -176,7 +254,7 @@ class CallStack { a.unshift(FilePos(null,new String(untyped x[0]),untyped x[1])); } return a; - #elseif flash9 + #elseif flash var a = new Array(); var r = ~/at ([^\/]+?)\$?(\/[^\(]+)?\(\)(\[(.*?):([0-9]+)\])?/; var rlambda = ~/^MethodInfo-([0-9]+)$/g; @@ -186,7 +264,7 @@ class CallStack { var item; if( meth == null ) { if( rlambda.match(cl) ) - item = Lambda(Std.parseInt(rlambda.matched(1))); + item = LocalFunction(Std.parseInt(rlambda.matched(1))); else item = Method(cl,"new"); } else @@ -197,14 +275,6 @@ class CallStack { s = r.matchedRight(); } return a; - #elseif flash - var a : Array = untyped __eval__(s); - var m = new Array(); - for( i in 0...a.length - if(s == "$s") 2 else 0 ) { - var d = a[i].split("::"); - m.unshift(Method(d[0],d[1])); - } - return m; #elseif php if (!untyped __call__("isset", __var__("GLOBALS", s))) return []; @@ -221,25 +291,54 @@ class CallStack { for(func in stack) { var words = func.split("::"); if (words.length==0) - m.unshift(CFunction) + m.push(CFunction) else if (words.length==2) - m.unshift(Method(words[0],words[1])); + m.push(Method(words[0],words[1])); else if (words.length==4) - m.unshift(FilePos( Method(words[0],words[1]),words[2],Std.parseInt(words[3]))); + m.push(FilePos( Method(words[0],words[1]),words[2],Std.parseInt(words[3]))); } return m; #elseif js - if ((untyped __js__("typeof"))(s) == "string") { + if (s == null) { + return []; + } else if ((untyped __js__("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 ) { - m.push(Module(line)); // A little weird, but better than nothing + 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)); + m.push(FilePos( meth == "Anonymous function" ? LocalFunction() : meth == "Global code" ? null : Method(path.join("."),meth), file, line )); + } 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(); + + 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; #else return null; #end diff --git a/std/js/html/CSSKeyframesRule.hx b/std/haxe/Constraints.hx similarity index 59% rename from std/js/html/CSSKeyframesRule.hx rename to std/haxe/Constraints.hx index 6c6f18472a8c26074d5f7de8760fff9fbca2721f..28dad93968664c700ebd865ecea162933bd67e26 100644 --- a/std/js/html/CSSKeyframesRule.hx +++ b/std/haxe/Constraints.hx @@ -20,20 +20,32 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html; +package haxe; -@:native("CSSKeyframesRule") -extern class CSSKeyframesRule extends CSSRule -{ - var cssRules(default,null) : CSSRuleList; +/** + This type unifies with any function type. - var name : String; + It is intended to be used as a type parameter constraint. If used as a real + type, the underlying type will be `Dynamic`. +**/ +@:callable +abstract Function(Dynamic) { } - function deleteRule( key : String ) : Void; +/** + This type unifies with an enum instance if all constructors of the enum + require no arguments. - function findRule( key : String ) : CSSKeyframeRule; + It is intended to be used as a type parameter constraint. If used as a real + type, the underlying type will be `Dynamic`. +**/ +abstract FlatEnum(Dynamic) { } - function insertRule( rule : String ) : Void; - -} +interface IMap { + public function get(k:K):Null; + public function set(k:K, v:V):Void; + public function exists(k:K):Bool; + public function remove(k:K):Bool; + public function keys():Iterator; + public function iterator():Iterator; + public function toString():String; +} \ No newline at end of file diff --git a/std/haxe/DynamicAccess.hx b/std/haxe/DynamicAccess.hx new file mode 100644 index 0000000000000000000000000000000000000000..e45d7775e1f929b1278aa9796b6b1ce2bc8a7f20 --- /dev/null +++ b/std/haxe/DynamicAccess.hx @@ -0,0 +1,94 @@ +/* + * Copyright (C)2005-2014 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; + +/** + DynamicAccess is an abstract type for working with anonymous structures + that are intended to hold collections of objects by the string key. + + For example, these types of structures are often created from JSON. + + Basically, it wraps `Reflect` calls in a `Map`-like interface. +**/ +abstract DynamicAccess(Dynamic) from Dynamic to Dynamic { + + /** + Creates a new structure. + **/ + public inline function new() this = {}; + + /** + Returns a value by specified `key`. + + If the structure does not contain the given key, null is returned. + + If `key` is null, the result is unspecified. + **/ + @:arrayAccess + public inline function get(key:String):Null { + #if js + return untyped this[key]; // we know it's an object, so we don't need a check + #else + return Reflect.field(this, key); + #end + } + + /** + Sets a `value` for a specified `key`. + + If the structure contains the given key, its value will be overwritten. + + Returns the given value. + + If `key` is null, the result is unspecified. + **/ + @:arrayAccess + public inline function set(key:String, value:T):T { + #if js + return untyped this[key] = value; + #else + Reflect.setField(this, key, value); + return value; + #end + } + + /** + Tells if the structure contains a specified `key`. + + If `key` is null, the result is unspecified. + **/ + public inline function exists(key:String):Bool return Reflect.hasField(this, key); + + /** + Removes a specified `key` from the structure. + + Returns true, if `key` was present in structure, or false otherwise. + + If `key` is null, the result is unspecified. + **/ + public inline function remove(key:String):Bool return Reflect.deleteField(this, key); + + /** + Returns an array of `keys` in a structure. + **/ + public inline function keys():Array return Reflect.fields(this); +} diff --git a/std/haxe/EnumFlags.hx b/std/haxe/EnumFlags.hx index 0cc6b95508bd60604fa0c87dc1c82642580568c4..5e2feb342dcfd4dc369b62ab3501a71feb2abda0 100644 --- a/std/haxe/EnumFlags.hx +++ b/std/haxe/EnumFlags.hx @@ -1,94 +1,94 @@ -/* - * Copyright (C)2005-2012 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; - -/** - A typed interface for bit flags. This is not a real object, only a typed - interface for an actual Int. Each flag can be tested/set with the - corresponding enum instance. Up to 32 flags can be stored that way. - - Enum constructor indices are preserved from haxe syntax, so the first - declared is index 0, the next index 1 etc. The methods are optimized if the - enum instance is passed directly, e.g. as has(EnumCtor). Otherwise - Type.enumIndex() reflection is used. -**/ -abstract EnumFlags(Int) { - - /** - Initializes the bitflags to [i]. - **/ - public inline function new(i = 0) { - this = i; - } - - /** - Checks if the index of enum instance [v] is set. - - This method is optimized if [v] is an enum instance expression such as - SomeEnum.SomeCtor. - - If [v] is null, the result is unspecified. - **/ - public inline function has( v : T ) : Bool { - return this & (1 << Type.enumIndex(v)) != 0; - } - - /** - Sets the index of enum instance [v]. - - This method is optimized if [v] is an enum instance expression such as - SomeEnum.SomeCtor. - - If [v] is null, the result is unspecified. - **/ - public inline function set( v : T ) : Void { - this |= 1 << Type.enumIndex(v); - } - - /** - Unsets the index of enum instance [v]. - - This method is optimized if [v] is an enum instance expression such as - SomeEnum.SomeCtor. - - If [v] is null, the result is unspecified. - **/ - public inline function unset( v : T ) : Void { - this &= 0xFFFFFFF - (1 << Type.enumIndex(v)); - } - - /** - Convert a integer bitflag into a typed one (this is a no-op, it does not - have any impact on speed). - **/ - @:from public inline static function ofInt( i : Int ) : EnumFlags { - return new EnumFlags(i); - } - - /** - Convert the typed bitflag into the corresponding int value (this is a - no-op, it doesn't have any impact on speed). - **/ - @:to public inline function toInt() : Int { - return this; - } -} +/* + * Copyright (C)2005-2012 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; + +/** + A typed interface for bit flags. This is not a real object, only a typed + interface for an actual Int. Each flag can be tested/set with the + corresponding enum instance. Up to 32 flags can be stored that way. + + Enum constructor indices are preserved from haxe syntax, so the first + declared is index 0, the next index 1 etc. The methods are optimized if the + enum instance is passed directly, e.g. as has(EnumCtor). Otherwise + Type.enumIndex() reflection is used. +**/ +abstract EnumFlags(Int) { + + /** + Initializes the bitflags to `i`. + **/ + public inline function new(i = 0) { + this = i; + } + + /** + Checks if the index of enum instance `v` is set. + + This method is optimized if `v` is an enum instance expression such as + SomeEnum.SomeCtor. + + If `v` is null, the result is unspecified. + **/ + public inline function has( v : T ) : Bool { + return this & (1 << Type.enumIndex(v)) != 0; + } + + /** + Sets the index of enum instance `v`. + + This method is optimized if `v` is an enum instance expression such as + SomeEnum.SomeCtor. + + If `v` is null, the result is unspecified. + **/ + public inline function set( v : T ) : Void { + this |= 1 << Type.enumIndex(v); + } + + /** + Unsets the index of enum instance `v`. + + This method is optimized if `v` is an enum instance expression such as + SomeEnum.SomeCtor. + + If `v` is null, the result is unspecified. + **/ + public inline function unset( v : T ) : Void { + this &= 0xFFFFFFF - (1 << Type.enumIndex(v)); + } + + /** + Convert a integer bitflag into a typed one (this is a no-op, it does not + have any impact on speed). + **/ + public inline static function ofInt( i : Int ) : EnumFlags { + return new EnumFlags(i); + } + + /** + Convert the typed bitflag into the corresponding int value (this is a + no-op, it doesn't have any impact on speed). + **/ + public inline function toInt() : Int { + return this; + } +} diff --git a/std/haxe/EnumTools.hx b/std/haxe/EnumTools.hx index 51042e708432d9567e9c1838712c74c65e1040a8..caa6c90845fef929875d609b3bc6d8e89ec6e55b 100644 --- a/std/haxe/EnumTools.hx +++ b/std/haxe/EnumTools.hx @@ -1,154 +1,186 @@ -/* - * Copyright (C)2005-2013 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; - -extern class EnumTools { - /** - Returns the name of enum [e], including its path. - - If [e] is inside a package, the package structure is returned dot- - separated, with another dot separating the enum name: - pack1.pack2.(...).packN.EnumName - If [e] is a sub-type of a haxe module, that module is not part of the - package structure. - - If [e] has no package, the enum name is returned. - - If [e] is null, the result is unspecified. - - The enum name does not include any type parameters. - **/ - static public inline function getName(e:Enum):String { - return Type.getEnumName(e); - } - - /** - Creates an instance of enum [e] by calling its constructor [constr] with - arguments [params]. - - If [e] or [constr] is null, or if enum [e] has no constructor named - [constr], or if the number of elements in [params] 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 createByName(e:Enum, constr:String, ?params:Array):T { - return Type.createEnum(e, constr, params); - } - - /** - Creates an instance of enum [e] by calling its constructor number - [index] with arguments [params]. - - The constructor indices are preserved from haxe syntax, so the first - declared is index 0, the next index 1 etc. - - If [e] or [constr] is null, or if enum [e] has no constructor named - [constr], or if the number of elements in [params] 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 { - return Type.createEnumIndex(e, index, params); - } - - /** - Returns a list of all constructors of enum [e] that require no - arguments. - - This may return the empty Array [] if all constructors of [e] require - arguments. - - Otherwise an instance of [e] constructed through each of its non- - argument constructors is returned, in the order of the constructor - declaration. - - If [e] is null, the result is unspecified. - **/ - static public inline function createAll(e:Enum):Array { - return Type.allEnums(e); - } - - /** - Returns a list of the names of all constructors of enum [e]. - - The order of the constructor names in the returned Array is preserved - from the original syntax. - - If [c] is null, the result is unspecified. - **/ - static public inline function getConstructors(e:Enum):Array { - return Type.getEnumConstructs(e); - } -} - -extern class EnumValueTools { - - /** - Recursively compares two enum instances [a] and [b] by value. - - Unlike [a] == [b], this function performs a deep equality check on the - arguments of the constructors, if exists. - - If [a] or [b] are null, the result is unspecified. - **/ - static public inline function equals(a:T, b:T):Bool { - return Type.enumEq(a, b); - } - - /** - Returns the constructor name of enum instance [e]. - - The result String does not contain any constructor arguments. - - If [e] is null, the result is unspecified. - **/ - static public inline function getName(e:EnumValue):String { - return Type.enumConstructor(e); - } - - /** - Returns a list of the constructor arguments of enum instance [e]. - - If [e] has no arguments, the result is []. - - Otherwise the result are the values that were used as arguments to [e], - in the order of their declaration. - - If [e] is null, the result is unspecified. - **/ - static public inline function getParameters(e:EnumValue):Array { - return Type.enumParameters(e); - } - - /** - Returns the index of enum instance [e]. - - This corresponds to the original syntactic position of [e]. The index of - the first declared constructor is 0, the next one is 1 etc. - - If [e] is null, the result is unspecified. - **/ - static public inline function getIndex(e:EnumValue):Int { - return Type.enumIndex(e); - } +/* + * Copyright (C)2005-2013 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; + +extern class EnumTools { + /** + Returns the name of enum `e`, including its path. + + If `e` is inside a package, the package structure is returned dot- + separated, with another dot separating the enum name: + pack1.pack2.(...).packN.EnumName + If `e` is a sub-type of a haxe module, that module is not part of the + package structure. + + If `e` has no package, the enum name is returned. + + If `e` is null, the result is unspecified. + + The enum name does not include any type parameters. + **/ + static public inline function getName(e:Enum):String { + return Type.getEnumName(e); + } + + /** + Creates an instance of enum `e` by calling its constructor `constr` with + arguments `params`. + + If `e` or `constr` is null, or if enum `e` has no constructor named + `constr`, or if the number of elements in `params` 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 createByName(e:Enum, constr:String, ?params:Array):T { + return Type.createEnum(e, constr, params); + } + + /** + Creates an instance of enum `e` by calling its constructor number + `index` with arguments `params`. + + The constructor indices are preserved from haxe syntax, so the first + declared is index 0, the next index 1 etc. + + If `e` or `index` is null, or if enum `e` has no constructor + corresponding to index `index`, or if the number of elements in `params` + 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 { + return Type.createEnumIndex(e, index, params); + } + + /** + Returns a list of all constructors of enum `e` that require no + arguments. + + This may return the empty Array [] if all constructors of `e` require + arguments. + + Otherwise an instance of `e` constructed through each of its non- + argument constructors is returned, in the order of the constructor + declaration. + + If `e` is null, the result is unspecified. + **/ + static public inline function createAll(e:Enum):Array { + return Type.allEnums(e); + } + + /** + Returns a list of the names of all constructors of enum `e`. + + The order of the constructor names in the returned Array is preserved + from the original syntax. + + If `c` is null, the result is unspecified. + **/ + static public inline function getConstructors(e:Enum):Array { + return Type.getEnumConstructs(e); + } +} + +extern class EnumValueTools { + + /** + Recursively compares two enum instances `a` and `b` by value. + + Unlike `a == b`, this function performs a deep equality check on the + arguments of the constructors, if exists. + + If `a` or `b` are null, the result is unspecified. + **/ + static public inline function equals(a:T, b:T):Bool { + return Type.enumEq(a, b); + } + + /** + Returns the constructor name of enum instance `e`. + + The result String does not contain any constructor arguments. + + If `e` is null, the result is unspecified. + **/ + static public inline function getName(e:EnumValue):String { + return Type.enumConstructor(e); + } + + /** + Returns a list of the constructor arguments of enum instance `e`. + + If `e` has no arguments, the result is []. + + Otherwise the result are the values that were used as arguments to `e`, + in the order of their declaration. + + If `e` is null, the result is unspecified. + **/ + static public inline function getParameters(e:EnumValue):Array { + return Type.enumParameters(e); + } + + /** + Returns the index of enum instance `e`. + + This corresponds to the original syntactic position of `e`. The index of + the first declared constructor is 0, the next one is 1 etc. + + If `e` is null, the result is unspecified. + **/ + static public inline function getIndex(e:EnumValue):Int { + return Type.enumIndex(e); + } + + /** + Matches enum instance `e` against pattern `pattern`, returning true if + matching succeeded and false otherwise. + + Example usage: + + ``` + if (e.match(pattern)) { + // codeIfTrue + } else { + // codeIfFalse + } + ``` + + This is equivalent to the following code: + + ``` + switch (e) { + case pattern: + // codeIfTrue + case _: + // codeIfFalse + } + ``` + + This method is implemented in the compiler. This definition exists only + for documentation. + **/ + static public function match(e:EnumValue, pattern:Dynamic):Bool { + return false; + } } \ No newline at end of file diff --git a/std/haxe/Http.hx b/std/haxe/Http.hx index 0c293884ef97d57a706596729fa7f072448280ca..ac3633004cd16a47e89aecd43bc99e69ed802765 100644 --- a/std/haxe/Http.hx +++ b/std/haxe/Http.hx @@ -41,15 +41,16 @@ private typedef AbstractSocket = { /** This class can be used to handle Http requests consistently across platforms. There are two intended usages: + - call haxe.Http.requestUrl(url) and receive the result as a String (not - available on flash) + available on flash) - create a new haxe.Http(url), register your callbacks for onData, onError - and onStatus, then call request(). + and onStatus, then call request(). **/ class Http { /** - The url of [this] request. It is used only by the request() method and + The url of `this` request. It is used only by the request() method and can be changed in order to send the same request to different target Urls. **/ @@ -58,27 +59,27 @@ class Http { #if sys public var noShutdown : Bool; public var cnxTimeout : Float; - public var responseHeaders : haxe.ds.StringMap; + public var responseHeaders : Map; var chunk_size : Null; var chunk_buf : haxe.io.Bytes; - var file : { param : String, filename : String, io : haxe.io.Input, size : Int }; + var file : { param : String, filename : String, io : haxe.io.Input, size : Int, mimeType : String }; #elseif js public var async : Bool; #end var postData : String; - var headers : haxe.ds.StringMap; - var params : haxe.ds.StringMap; + var headers : List<{ header:String, value:String }>; + var params : List<{ param:String, value:String }>; #if sys public static var PROXY : { host : String, port : Int, auth : { user : String, pass : String } } = null; #end /** - Creates a new Http instance with [url] as parameter. + Creates a new Http instance with `url` as parameter. This does not do a request until request() is called. - If [url] is null, the field url must be set to a value before making the + If `url` is null, the field url must be set to a value before making the call to request(), or the result is unspecified. (Php) Https (SSL) connections are allowed only if the OpenSSL extension @@ -86,8 +87,9 @@ class Http { **/ public function new( url : String ) { this.url = url; - headers = new haxe.ds.StringMap(); - params = new haxe.ds.StringMap(); + headers = new List<{ header:String, value:String }>(); + params = new List<{ param:String, value:String }>(); + #if js async = true; #elseif sys @@ -99,37 +101,48 @@ class Http { } /** - Sets the header identified as [header] to value [value]. + Sets the header identified as `header` to value `value`. - If [header] or [value] are null, the result is unspecified. + If `header` or `value` are null, the result is unspecified. This method provides a fluent interface. **/ public function setHeader( header : String, value : String ):Http { - headers.set(header, value); + headers = Lambda.filter(headers, function(h) return h.header != header); + headers.push({ header:header, value:value }); + return this; + } + + public function addHeader( header : String, value : String ):Http { + headers.push({ header:header, value:value }); return this; } /** - Sets the parameter identified as [param] to value [value]. + Sets the parameter identified as `param` to value `value`. - If [header] or [value] are null, the result is unspecified. + If `header` or `value` are null, the result is unspecified. This method provides a fluent interface. **/ public function setParameter( param : String, value : String ):Http { - params.set(param, value); + params = Lambda.filter(params, function(p) return p.param != param); + params.push({ param:param, value:value }); + return this; + } + + public function addParameter( param : String, value : String ):Http { + params.push({ param:param, value:value }); return this; } - #if !flash8 /** - Sets the post data of [this] Http request to [data]. + Sets the post data of `this` Http request to `data`. There can only be one post data per request. Subsequent calls overwrite the previously set value. - If [data] is null, the post data is considered to be absent. + If `data` is null, the post data is considered to be absent. This method provides a fluent interface. **/ @@ -137,48 +150,87 @@ class Http { postData = data; return this; } + + #if (js || flash) + + #if js + var req:js.html.XMLHttpRequest; + #elseif flash + var req:flash.net.URLLoader; + #end + + /** + Cancels `this` Http request if `request` has been called and a response + has not yet been received. + **/ + public function cancel() + { + if (req == null) return; + #if js + req.abort(); + #elseif flash + req.close(); + #end + req = null; + } #end /** - Sends [this] Http request to the Url specified by [this].url. + Sends `this` Http request to the Url specified by `this.url`. - If [post] is true, the request is sent as POST request, otherwise it is + If `post` is true, the request is sent as POST request, otherwise it is sent as GET request. Depending on the outcome of the request, this method calls the onStatus(), onError() or onData() callback functions. - If [this].url is null, the result is unspecified. + If `this.url` is null, the result is unspecified. - If [this].url is an invalid or inaccessible Url, the onError() callback + If `this.url` is an invalid or inaccessible Url, the onError() callback function is called. - (Js) If [this].async is false, the callback functions are called before + (Js) If `this.async` is false, the callback functions are called before this method returns. **/ public function request( ?post : Bool ) : Void { var me = this; #if js me.responseData = null; - var r = js.Browser.createXMLHttpRequest(); + var r = req = js.Browser.createXMLHttpRequest(); var onreadystatechange = function(_) { if( r.readyState != 4 ) return; var s = try r.status catch( e : Dynamic ) null; + if ( s != 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):$/; + var isLocal = rlocalProtocol.match( protocol ); + if ( isLocal ) { + s = r.responseText != null ? 200 : 404; + } + } if( s == untyped __js__("undefined") ) s = null; if( s != null ) me.onStatus(s); - if( s != null && s >= 200 && s < 400 ) + if( s != null && s >= 200 && s < 400 ) { + me.req = null; me.onData(me.responseData = r.responseText); - else if ( s == null ) - me.onError("Failed to connect or resolve host") + } + else if ( s == null ) { + me.req = null; + me.onError("Failed to connect or resolve host"); + } else switch( s ) { case 12029: + me.req = null; me.onError("Failed to connect to host"); case 12007: + me.req = null; me.onError("Unknown host"); default: + me.req = null; me.responseData = r.responseText; me.onError("Http Error #"+r.status); } @@ -188,12 +240,12 @@ class Http { var uri = postData; if( uri != null ) post = true; - else for( p in params.keys() ) { + else for( p in params ) { if( uri == null ) uri = ""; else uri += "&"; - uri += StringTools.urlEncode(p)+"="+StringTools.urlEncode(params.get(p)); + uri += StringTools.urlEncode(p.param)+"="+StringTools.urlEncode(p.value); } try { if( post ) @@ -205,21 +257,23 @@ class Http { } else r.open("GET",url,async); } catch( e : Dynamic ) { + me.req = null; onError(e.toString()); return; } - if( headers.get("Content-Type") == null && post && postData == null ) + if( !Lambda.exists(headers, function(h) return h.header == "Content-Type") && post && postData == null ) r.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); - for( h in headers.keys() ) - r.setRequestHeader(h,headers.get(h)); + for( h in headers ) + r.setRequestHeader(h.header,h.value); r.send(uri); if( !async ) onreadystatechange(null); - #elseif flash9 + #elseif flash me.responseData = null; - var loader = new flash.net.URLLoader(); + var loader = req = new flash.net.URLLoader(); loader.addEventListener( "complete", function(e) { + me.req = null; me.responseData = loader.data; me.onData( loader.data ); }); @@ -228,20 +282,22 @@ class Http { if( e.status != 0 ) me.onStatus( e.status ); }); - loader.addEventListener( "ioError", function(e:flash.events.IOErrorEvent) { + loader.addEventListener( "ioError", function(e:flash.events.IOErrorEvent){ + me.req = null; me.responseData = loader.data; me.onError(e.text); }); loader.addEventListener( "securityError", function(e:flash.events.SecurityErrorEvent){ + me.req = null; me.onError(e.text); }); // headers var param = false; var vars = new flash.net.URLVariables(); - for( k in params.keys() ){ + for( p in params ){ param = true; - Reflect.setField(vars,k,params.get(k)); + Reflect.setField(vars,p.param,p.value); } var small_url = url; if( param && !post ){ @@ -255,8 +311,8 @@ class Http { var bug = small_url.split("xxx"); var request = new flash.net.URLRequest( small_url ); - for( k in headers.keys() ) - request.requestHeaders.push( new flash.net.URLRequestHeader(k,headers.get(k)) ); + for( h in headers ) + request.requestHeaders.push( new flash.net.URLRequestHeader(h.header,h.value) ); if( postData != null ) { request.data = postData; @@ -269,46 +325,9 @@ class Http { try { loader.load( request ); }catch( e : Dynamic ){ + me.req = null; onError("Exception: "+Std.string(e)); } - #elseif flash - me.responseData = null; - var r = new flash.LoadVars(); - // on Firefox 1.5, onData is not called if host/port invalid (!) - r.onData = function(data) { - if( data == null ) { - me.onError("Failed to retrieve url"); - return; - } - me.responseData = data; - me.onData(data); - }; - #if flash8 - r.onHTTPStatus = function(status) { - // on Firefox 1.5, Flash calls onHTTPStatus with 0 (!??) - if( status != 0 ) - me.onStatus(status); - }; - untyped ASSetPropFlags(r,"onHTTPStatus",7); - #end - untyped ASSetPropFlags(r,"onData",7); - for( h in headers.keys() ) - r.addRequestHeader(h,headers.get(h)); - var param = false; - for( p in params.keys() ) { - param = true; - Reflect.setField(r,p,params.get(p)); - } - var small_url = url; - if( param && !post ) { - var k = url.split("?"); - if( k.length > 1 ) { - small_url = k.shift(); - r.decode(k.join("?")); - } - } - if( !r.sendAndLoad(small_url,r,if( param ) { if( post ) "POST" else "GET"; } else null) ) - onError("Failed to initialize Connection"); #elseif sys var me = this; var output = new haxe.io.BytesOutput(); @@ -321,7 +340,9 @@ class Http { me.responseData = output.getBytes().toString(); #end err = true; - old(e); + // Resetting back onError before calling it allows for a second "retry" request to be sent without onError being wrapped twice + onError = old; + onError(e); } customRequest(post,output); if( !err ) @@ -335,13 +356,21 @@ class Http { #if sys - public function fileTransfert( argname : String, filename : String, file : haxe.io.Input, size : Int ) { - this.file = { param : argname, filename : filename, io : file, size : size }; + /** + Note: Deprecated in 4.0 + **/ + @:noCompletion + inline public function fileTransfert( argname : String, filename : String, file : haxe.io.Input, size : Int, mimeType = "application/octet-stream" ) { + fileTransfer(argname, filename, file, size, mimeType); + } + + public function fileTransfer( argname : String, filename : String, file : haxe.io.Input, size : Int, mimeType = "application/octet-stream" ) { + this.file = { param : argname, filename : filename, io : file, size : size, mimeType : mimeType }; } public function customRequest( post : Bool, api : haxe.io.Output, ?sock : AbstractSocket, ?method : String ) { this.responseData = null; - var url_regexp = ~/^(https?:\/\/)?([a-zA-Z\.0-9-]+)(:[0-9]+)?(.*)$/; + var url_regexp = ~/^(https?:\/\/)?([a-zA-Z\.0-9_-]+)(:[0-9]+)?(.*)$/; if( !url_regexp.match(url) ) { onError("Invalid URL"); return; @@ -351,9 +380,15 @@ class Http { if( secure ) { #if php sock = new php.net.SslSocket(); + #elseif java + sock = new java.net.SslSocket(); #elseif hxssl + #if neko sock = new neko.tls.Socket(); #else + sock = new sys.ssl.Socket(); + #end + #else throw "Https is only supported with -lib hxssl"; #end } else @@ -376,16 +411,16 @@ class Http { while( boundary.length < 38 ) boundary = "-" + boundary; var b = new StringBuf(); - for( p in params.keys() ) { + for( p in params ) { b.add("--"); b.add(boundary); b.add("\r\n"); b.add('Content-Disposition: form-data; name="'); - b.add(p); + b.add(p.param); b.add('"'); b.add("\r\n"); b.add("\r\n"); - b.add(params.get(p)); + b.add(p.value); b.add("\r\n"); } b.add("--"); @@ -397,15 +432,15 @@ class Http { b.add(file.filename); b.add('"'); b.add("\r\n"); - b.add("Content-Type: "+"application/octet-stream"+"\r\n"+"\r\n"); + b.add("Content-Type: "+file.mimeType+"\r\n"+"\r\n"); uri = b.toString(); } else { - for( p in params.keys() ) { + for( p in params ) { if( uri == null ) uri = ""; else uri += "&"; - uri += StringTools.urlEncode(p)+"="+StringTools.urlEncode(params.get(p)); + uri += StringTools.urlEncode(p.param)+"="+StringTools.urlEncode(p.value); } } @@ -439,7 +474,7 @@ class Http { if( postData != null ) b.add("Content-Length: "+postData.length+"\r\n"); else if( post && uri != null ) { - if( multipart || headers.get("Content-Type") == null ) { + if( multipart || !Lambda.exists(headers, function(h) return h.header == "Content-Type") ) { b.add("Content-Type: "); if( multipart ) { b.add("multipart/form-data"); @@ -454,10 +489,10 @@ class Http { else b.add("Content-Length: "+uri.length+"\r\n"); } - for( h in headers.keys() ) { - b.add(h); + for( h in headers ) { + b.add(h.header); b.add(": "); - b.add(headers.get(h)); + b.add(h.value); b.add("\r\n"); } b.add("\r\n"); @@ -580,6 +615,7 @@ class Http { var a = hline.split(": "); var hname = a.shift(); var hval = if( a.length == 1 ) a[0] else a.join(": "); + hval = StringTools.ltrim( StringTools.rtrim( hval ) ); responseHeaders.set(hname, hval); switch(hname.toLowerCase()) { @@ -625,7 +661,7 @@ class Http { size -= len; } } catch( e : haxe.io.Eof ) { - throw "Transfert aborted"; + throw "Transfer aborted"; } } if( chunked && (chunk_size != null || chunk_buf != null) ) @@ -695,43 +731,43 @@ class Http { #end /** - This method is called upon a successful request, with [data] containing + This method is called upon a successful request, with `data` containing the result String. The intended usage is to bind it to a custom function: - httpInstance.onData = function(data) { // handle result } + `httpInstance.onData = function(data) { // handle result }` **/ public dynamic function onData( data : String ) { } /** - This method is called upon a request error, with [msg] containing the + This method is called upon a request error, with `msg` containing the error description. The intended usage is to bind it to a custom function: - httpInstance.onError = function(msg) { // handle error } + `httpInstance.onError = function(msg) { // handle error }` **/ public dynamic function onError( msg : String ) { } /** - This method is called upon a Http status change, with [status] being the + This method is called upon a Http status change, with `status` being the new status. The intended usage is to bind it to a custom function: - httpInstance.onStatus = function(status) { // handle status } + `httpInstance.onStatus = function(status) { // handle status }` **/ public dynamic function onStatus( status : Int ) { } #if !flash /** - 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. - 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); diff --git a/std/haxe/Int32.hx b/std/haxe/Int32.hx new file mode 100644 index 0000000000000000000000000000000000000000..8cce274a6c8cad5177e3c83e02908cd35907a21e --- /dev/null +++ b/std/haxe/Int32.hx @@ -0,0 +1,200 @@ +/* + * Copyright (C)2005-2013 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; + + /** + Int32 provides a 32-bit integer with consistent overflow behavior across + all platforms. + **/ +abstract Int32(Int) from Int to Int { + @:op(-A) private function negate():Int32; + + @:op(++A) private inline function preIncrement():Int32 + return this = clamp(++this); + + @:op(A++) private inline function postIncrement():Int32 { + var ret = this++; + this = clamp(this); + return ret; + } + + @:op(--A) private inline function preDecrement():Int32 + return this = clamp(--this); + + @:op(A--) private inline function postDecrement():Int32 { + var ret = this--; + this = clamp(this); + return ret; + } + + @:op(A + B) private static inline function add(a:Int32, b:Int32):Int32 + return clamp( (a : Int) + (b : Int) ); + + @:op(A + B) @:commutative private static inline function addInt(a:Int32, b:Int):Int32 + return clamp( (a : Int) + (b : Int) ); + + @:op(A + B) @:commutative private static function addFloat(a:Int32, b:Float):Float; + + @:op(A - B) private static inline function sub(a:Int32, b:Int32):Int32 + return clamp( (a : Int) - (b : Int) ); + + @:op(A - B) private static inline function subInt(a:Int32, b:Int):Int32 + return clamp( (a : Int) - (b : Int) ); + + @:op(A - B) private static inline function intSub(a:Int, b:Int32):Int32 + return clamp( (a : Int) - (b : Int) ); + + @:op(A - B) private static function subFloat(a:Int32, b:Float):Float; + + @:op(A - B) public static function floatSub(a:Float, b:Int32):Float; + + #if (as3 || js || php || python) + + @:op(A * B) private static function mul(a:Int32, b:Int32):Int32 + return clamp( (a : Int) * ((b : Int) & 0xFFFF) + clamp( (a : Int) * ((b : Int) >>> 16) << 16 ) ); + + @:op(A * B) @:commutative private static inline function mulInt(a:Int32, b:Int):Int32 + return mul(a, b); + + #else + + @:op(A * B) private static function mul(a:Int32, b:Int32):Int32; + @:op(A * B) @:commutative private static function mulInt(a:Int32, b:Int):Int32; + + #end + + @:op(A * B) @:commutative private static function mulFloat(a:Int32, b:Float):Float; + + @:op(A / B) private static function div(a:Int32, b:Int32):Float; + @:op(A / B) private static function divInt(a:Int32, b:Int):Float; + @:op(A / B) private static function intDiv(a:Int, b:Int32):Float; + @:op(A / B) private static function divFloat(a:Int32, b:Float):Float; + @:op(A / B) private static function floatDiv(a:Float, b:Int32):Float; + + @:op(A % B) private static function mod(a:Int32, b:Int32):Int32; + @:op(A % B) private static function modInt(a:Int32, b:Int):Int; + @:op(A % B) private static function intMod(a:Int, b:Int32):Int; + @:op(A % B) private static function modFloat(a:Int32, b:Float):Float; + @:op(A % B) private static function floatMod(a:Float, b:Int32):Float; + + @:op(A == B) private static function eq(a:Int32, b:Int32):Bool; + @:op(A == B) @:commutative private static function eqInt(a:Int32, b:Int):Bool; + @:op(A == B) @:commutative private static function eqFloat(a:Int32, b:Float):Bool; + + @:op(A != B) private static function neq(a:Int32, b:Int32):Bool; + @:op(A != B) @:commutative private static function neqInt(a:Int32, b:Int):Bool; + @:op(A != B) @:commutative private static function neqFloat(a:Int32, b:Float):Bool; + + @:op(A < B) private static function lt(a:Int32, b:Int32):Bool; + @:op(A < B) private static function ltInt(a:Int32, b:Int):Bool; + @:op(A < B) private static function intLt(a:Int, b:Int32):Bool; + @:op(A < B) private static function ltFloat(a:Int32, b:Float):Bool; + @:op(A < B) private static function floatLt(a:Float, b:Int32):Bool; + + @:op(A <= B) private static function lte(a:Int32, b:Int32):Bool; + @:op(A <= B) private static function lteInt(a:Int32, b:Int):Bool; + @:op(A <= B) private static function intLte(a:Int, b:Int32):Bool; + @:op(A <= B) private static function lteFloat(a:Int32, b:Float):Bool; + @:op(A <= B) private static function floatLte(a:Float, b:Int32):Bool; + + @:op(A > B) private static function gt(a:Int32, b:Int32):Bool; + @:op(A > B) private static function gtInt(a:Int32, b:Int):Bool; + @:op(A > B) private static function intGt(a:Int, b:Int32):Bool; + @:op(A > B) private static function gtFloat(a:Int32, b:Float):Bool; + @:op(A > B) private static function floatGt(a:Float, b:Int32):Bool; + + @:op(A >= B) private static function gte(a:Int32, b:Int32):Bool; + @:op(A >= B) private static function gteInt(a:Int32, b:Int):Bool; + @:op(A >= B) private static function intGte(a:Int, b:Int32):Bool; + @:op(A >= B) private static function gteFloat(a:Int32, b:Float):Bool; + @:op(A >= B) private static function floatGte(a:Float, b:Int32):Bool; + + @:op(~A) private function complement():Int32; + + @:op(A & B) private static function and(a:Int32, b:Int32):Int32; + @:op(A & B) @:commutative private static function andInt(a:Int32, b:Int):Int32; + + @:op(A | B) private static function or(a:Int32, b:Int32):Int32; + @:op(A | B) @:commutative private static function orInt(a:Int32, b:Int):Int32; + + @:op(A ^ B) private static function xor(a:Int32, b:Int32):Int32; + @:op(A ^ B) @:commutative private static function xorInt(a:Int32, b:Int):Int32; + + + @:op(A >> B) private static function shr(a:Int32, b:Int32):Int32; + @:op(A >> B) private static function shrInt(a:Int32, b:Int):Int32; + @:op(A >> B) private static function intShr(a:Int, b:Int32):Int32; + + @:op(A >>> B) private static function ushr(a:Int32, b:Int32):Int32; + @:op(A >>> B) private static function ushrInt(a:Int32, b:Int):Int32; + @:op(A >>> B) private static function intUshr(a:Int, b:Int32):Int32; + + #if (php || python) + + // PHP may be 64-bit, so shifts must be clamped + @:op(A << B) private static inline function shl(a:Int32, b:Int32):Int32 + return clamp( (a : Int) << (b : Int) ); + + @:op(A << B) private static inline function shlInt(a:Int32, b:Int):Int32 + return clamp( (a : Int) << b ); + + @:op(A << B) private static inline function intShl(a:Int, b:Int32):Int32 + return clamp( a << (b : Int) ); + + #else + + @:op(A << B) private static function shl(a:Int32, b:Int32):Int32; + @:op(A << B) private static function shlInt(a:Int32, b:Int):Int32; + @:op(A << B) private static function intShl(a:Int, b:Int32):Int32; + + #end + + @:to private inline function toFloat():Float + return this; + + /** + Compare `a` and `b` in unsigned mode. + **/ + public static function ucompare( a : Int32, b : Int32 ) : Int { + if( a < 0 ) + return b < 0 ? ( ~b - ~a ) : 1; + return b < 0 ? -1 : (a - b); + } + + #if php + static var extraBits : Int = untyped __php__("PHP_INT_SIZE") * 8 - 32; + #end + + static inline function clamp( x : Int ) : Int { + // force to-int conversion on platforms that require it + #if (as3 || js) + return x | 0; + #elseif php + // we might be on 64-bit php, so sign extend from 32-bit + return (x << extraBits) >> extraBits; + #elseif python + return python.Syntax.pythonCode("{0} % {1}", (x + python.Syntax.opPow(2, 31)), python.Syntax.opPow(2, 32)) - python.Syntax.opPow(2, 31); + #else + return (x); + #end + } +} diff --git a/std/haxe/Int64.hx b/std/haxe/Int64.hx index 88c1a5c400b41dcc0a9d98ba00894a9cb43b259c..a50454701701724f40f97976e57ebc681ddb07c5 100644 --- a/std/haxe/Int64.hx +++ b/std/haxe/Int64.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2012 Haxe Foundation + * Copyright (C)2005-2013 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -21,48 +21,123 @@ */ package haxe; -class Int64 { +using haxe.Int64; - var high : Int; - var low : Int; + /** + A cross-platform signed 64-bit integer. + Int64 instances can be created from two 32-bit words using `Int64.make()`. + **/ +#if flash +@:notNull +#end +abstract Int64(__Int64) from __Int64 to __Int64 +{ + private inline function new( x : __Int64 ) + this = x; - inline function new(high, low) { - this.high = i32(high); - this.low = i32(low); + /** + Makes a copy of `this` Int64. + **/ + public inline function copy():Int64 + return make( high, low ); + + /** + Construct an Int64 from two 32-bit words `high` and `low`. + **/ + public static inline function make( high:Int32, low:Int32 ) : Int64 + return new Int64( new __Int64(high, low) ); + + /** + Returns an Int64 with the value of the Int `x`. + `x` is sign-extended to fill 64 bits. + **/ + @:from public static inline function ofInt( x : Int ) : Int64 + return make( x >> 31, x ); + + /** + Returns an Int with the value of the Int64 `x`. + Throws an exception if `x` cannot be represented in 32 bits. + **/ + public static inline function toInt( x : Int64 ) : Int { + if( x.high != x.low >> 31 ) + throw "Overflow"; + + return x.low; } - @:extern static inline function i32(i) { - #if (php || js || flash8) - return i | 0; - #else - return i; - #end + /** + Returns whether the value `val` is of type `haxe.Int64` + **/ + inline public static function is( val : Dynamic ) : Bool + return Std.is(val,__Int64); + + /** + Returns the high 32-bit word of `x`. + **/ + @:deprecated("Use high instead") + public static inline function getHigh( x : Int64 ) : Int32 + return x.high; + + /** + Returns the low 32-bit word of `x`. + **/ + @:deprecated("Use low instead") + public static inline function getLow( x : Int64 ) : Int32 + return x.low; + + /** + Returns `true` if `x` is less than zero. + **/ + public static inline function isNeg( x : Int64) : Bool + return x.high < 0; + + /** + Returns `true` if `x` is exactly zero. + **/ + public static inline function isZero( x : Int64 ) : Bool + return x == 0; + + /** + Compares `a` and `b` in signed mode. + Returns a negative value if `a < b`, positive if `a > b`, + or 0 if `a == b`. + **/ + public static inline function compare( a : Int64, b : Int64 ) : Int { + var v = a.high - b.high; + v = if( v != 0 ) v else Int32.ucompare(a.low, b.low); + return a.high < 0 ? (b.high < 0 ? v : -1) : (b.high >= 0 ? v : 1); } - @:extern static inline function i32mul(a:Int,b:Int) { - #if (php || js || flash8) - /* - We can't simply use i32(a*b) since we might overflow (52 bits precision in doubles) - */ - return i32(i32((a * (b >>> 16)) << 16) + (a * (b&0xFFFF))); - #else - return a * b; - #end + /** + Compares `a` and `b` in unsigned mode. + Returns a negative value if `a < b`, positive if `a > b`, + or 0 if `a == b`. + **/ + public static inline function ucompare( a : Int64, b : Int64 ) : Int { + var v = Int32.ucompare(a.high, b.high); + return if( v != 0 ) v else Int32.ucompare(a.low, b.low); } - - #if as3 public #end function toString() { - if ((high|low) == 0 ) + + /** + Returns a signed decimal `String` representation of `x`. + **/ + public static inline function toStr(x:Int64) : String + return x.toString(); + + #if as3 public #else private #end function toString() : String + { + var i : Int64 = cast this; + if ( i == 0 ) return "0"; var str = ""; var neg = false; - var i = this; - if( isNeg(i) ) { + if( i.isNeg() ) { neg = true; - i = Int64.neg(i); + i = -i; } - var ten = ofInt(10); - while( !isZero(i) ) { - var r = divMod(i, ten); + var ten : Int64 = 10; + while( i != 0 ) { + var r = i.divMod( ten ); str = r.modulus.low + str; i = r.quotient; } @@ -70,48 +145,122 @@ class Int64 { return str; } - public static inline function make( high : Int, low : Int ) : Int64 { - return new Int64(high, low); + /** + Performs signed integer divison of `dividend` by `divisor`. + Returns `{ quotient : Int64, modulus : Int64 }`. + **/ + public static function divMod( dividend : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } + { + // Handle special cases of 0 and 1 + if( divisor.high == 0 ) + { + switch( divisor.low ) { + case 0: throw "divide by zero"; + case 1: return { quotient : dividend.copy(), modulus : 0 }; + } + } + + var divSign = dividend.isNeg() != divisor.isNeg(); + + var modulus = dividend.isNeg() ? -dividend : dividend.copy(); + divisor = divisor.isNeg() ? -divisor : divisor; + + var quotient : Int64 = 0; + var mask : Int64 = 1; + + while( !divisor.isNeg() ) { + var cmp = ucompare( divisor, modulus ); + divisor <<= 1; + mask <<= 1; + if( cmp >= 0 ) break; + } + + while( mask != 0 ) { + if( ucompare(modulus, divisor) >= 0 ) { + quotient |= mask; + modulus -= divisor; + } + mask >>>= 1; + divisor >>>= 1; + } + + if( divSign ) quotient = -quotient; + if( dividend.isNeg() ) modulus = -modulus; + + return { + quotient : quotient, + modulus : modulus + }; + } + + /** + Returns the negative of `x`. + **/ + @:op(-A) public static inline function neg( x : Int64 ) : Int64 { + var high = ~x.high; + var low = -x.low; + if( low == 0 ) + high++; + return make( high, low ); } - public static inline function ofInt( x : Int ) : Int64 { - return new Int64(x >> 31,x); + @:op(++A) private inline function preIncrement() : Int64 { + this.low++; + if( this.low == 0 ) this.high++; + return cast this; } - public static function toInt( x : Int64 ) : Int { - if( x.high != 0 ) { - if( x.high < 0 ) - return -toInt(neg(x)); - throw "Overflow"; - } - return x.low; + @:op(A++) private inline function postIncrement() : Int64 { + var ret = copy(); + preIncrement(); + return ret; } - public static function getLow( x : Int64 ) : Int { - return x.low; + @:op(--A) private inline function preDecrement() : Int64 { + if( this.low == 0 ) this.high--; + this.low--; + return cast this; } - public static function getHigh( x : Int64 ) : Int { - return x.high; + @:op(A--) private inline function postDecrement() : Int64 { + var ret = copy(); + preDecrement(); + return ret; } - public static function add( a : Int64, b : Int64 ) : Int64 { - var high = i32(a.high + b.high); - var low = i32(a.low + b.low); - if( uicompare(low,a.low) < 0 ) - high++; - return new Int64(high, low); + /** + Returns the sum of `a` and `b`. + **/ + @:op(A + B) public static inline function add( a : Int64, b : Int64 ) : Int64 { + var high = a.high + b.high; + var low = a.low + b.low; + if( Int32.ucompare( low, a.low ) < 0 ) high++; + return make( high, low ); } - public static function sub( a : Int64, b : Int64 ) : Int64 { + @:op(A + B) @:commutative private static inline function addInt( a : Int64, b : Int ) : Int64 + return add( a, b ); + + /** + Returns `a` minus `b`. + **/ + @:op(A - B) public static inline function sub( a : Int64, b : Int64 ) : Int64 { var high = a.high - b.high; var low = a.low - b.low; - if( uicompare(a.low,b.low) < 0 ) - high--; - return new Int64(high, low); + if( Int32.ucompare( a.low, b.low ) < 0 ) high--; + return make( high, low ); } - public static function mul( a : Int64, b : Int64 ) : Int64 { + @:op(A - B) private static inline function subInt( a : Int64, b : Int ) : Int64 + return sub( a, b ); + + @:op(A - B) private static inline function intSub( a : Int, b : Int64 ) : Int64 + return sub( a, b ); + + /** + Returns the product of `a` and `b`. + **/ + @:op(A * B) public static inline function mul( a : Int64, b : Int64 ) : Int64 { var mask = 0xFFFF; var al = a.low & mask, ah = a.low >>> 16; var bl = b.low & mask, bh = b.low >>> 16; @@ -120,116 +269,184 @@ class Int64 { var p01 = al * bh; var p11 = ah * bh; var low = p00; - var high = i32(p11 + (p01 >>> 16) + (p10 >>> 16)); - p01 = i32(p01 << 16); low = i32(low + p01); if( uicompare(low, p01) < 0 ) high = i32(high + 1); - p10 = i32(p10 << 16); low = i32(low + p10); if( uicompare(low, p10) < 0 ) high = i32(high + 1); - high = i32(high + i32mul(a.low,b.high)); - high = i32(high + i32mul(a.high,b.low)); - return new Int64(high, low); - } - - static function divMod( modulus : Int64, divisor : Int64 ) { - var quotient = new Int64(0, 0); - var mask = new Int64(0, 1); - divisor = new Int64(divisor.high, divisor.low); - while( divisor.high >= 0 ) { - var cmp = ucompare(divisor, modulus); - divisor.high = (divisor.high << 1) | (divisor.low >>> 31); - divisor.low <<= 1; - mask.high = (mask.high << 1) | (mask.low >>> 31); - mask.low <<= 1; - if( cmp >= 0 ) break; - } - while( (mask.low | mask.high) != 0 ) { - if( ucompare(modulus, divisor) >= 0 ) { - quotient.high |= mask.high; - quotient.low |= mask.low; - modulus = sub(modulus,divisor); - } - mask.low = (mask.low >>> 1) | (mask.high << 31); - mask.high >>>= 1; - - divisor.low = (divisor.low >>> 1) | (divisor.high << 31); - divisor.high >>>= 1; - } - return { quotient : quotient, modulus : modulus }; + var high = p11 + (p01 >>> 16) + (p10 >>> 16); + p01 <<= 16; + low += p01; + if( Int32.ucompare(low, p01) < 0 ) high++; + p10 <<= 16; + low += p10; + if( Int32.ucompare(low, p10) < 0 ) high++; + high += a.low * b.high + a.high * b.low; + return make( high, low ); } - public static inline function div( a : Int64, b : Int64 ) : Int64 { - var sign = (a.high | b.high) < 0; - if( a.high < 0 ) a = neg(a); - if( b.high < 0 ) b = neg(b); - var q = divMod(a, b).quotient; - return sign ? neg(q) : q; - } + @:op(A * B) @:commutative private static inline function mulInt( a : Int64, b : Int ) : Int64 + return mul( a, b ); - public static inline function mod( a : Int64, b : Int64 ) : Int64 { - var sign = (a.high | b.high) < 0; - if( a.high < 0 ) a = neg(a); - if( b.high < 0 ) b = neg(b); - var m = divMod(a, b).modulus; - return sign ? neg(m) : m; - } + /** + Returns the quotient of `a` divided by `b`. + **/ + @:op(A / B) public static inline function div( a : Int64, b : Int64 ) : Int64 + return divMod(a, b).quotient; - public static inline function shl( a : Int64, b : Int ) : Int64 { - return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( (a.high << b) | (a.low >>> (32-(b&63))), a.low << b ) else new Int64( a.low << (b - 32), 0 ); - } + @:op(A / B) private static inline function divInt( a : Int64, b : Int ) : Int64 + return div( a, b ); - public static inline function shr( a : Int64, b : Int ) : Int64 { - return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( a.high >> b, (a.low >>> b) | (a.high << (32 - (b&63))) ) else new Int64( a.high >> 31, a.high >> (b - 32) ); - } + @:op(A / B) private static inline function intDiv( a : Int, b : Int64 ) : Int64 + return div( a, b ).toInt(); - public static inline function ushr( a : Int64, b : Int ) : Int64 { - return if( b & 63 == 0 ) a else if( b & 63 < 32 ) new Int64( a.high >>> b, (a.low >>> b) | (a.high << (32 - (b&63))) ) else new Int64( 0, a.high >>> b - 32 ); - } + /** + Returns the modulus of `a` divided by `b`. + **/ + @:op(A % B) public static inline function mod( a : Int64, b : Int64 ) : Int64 + return divMod(a, b).modulus; - public static inline function and( a : Int64, b : Int64 ) : Int64 { - return new Int64( a.high & b.high, a.low & b.low ); - } + @:op(A % B) private static inline function modInt( a : Int64, b : Int ) : Int64 + return mod( a, b ).toInt(); - public static inline function or( a : Int64, b : Int64 ) : Int64 { - return new Int64( a.high | b.high, a.low | b.low ); - } + @:op(A % B) private static inline function intMod( a : Int, b : Int64 ) : Int64 + return mod( a, b ).toInt(); - public static inline function xor( a : Int64, b : Int64 ) : Int64 { - return new Int64( a.high ^ b.high, a.low ^ b.low ); - } + /** + Returns `true` if `a` is equal to `b`. + **/ + @:op(A == B) public static inline function eq( a : Int64, b : Int64 ) : Bool + return a.high == b.high && a.low == b.low; - public static inline function neg( a : Int64 ) : Int64 { - var high = ~a.high; - var low = -a.low; - if( low == 0 ) - high++; - return new Int64(high,low); - } + @:op(A == B) @:commutative private static inline function eqInt( a : Int64, b : Int ) : Bool + return eq( a, b ); - public static inline function isNeg( a : Int64 ) : Bool { - return a.high < 0; - } + /** + Returns `true` if `a` is not equal to `b`. + **/ + @:op(A != B) public static inline function neq( a : Int64, b : Int64 ) : Bool + return a.high != b.high || a.low != b.low; - public static inline function isZero( a : Int64 ) : Bool { - return (a.high | a.low) == 0; - } + @:op(A != B) @:commutative private static inline function neqInt( a : Int64, b : Int ) : Bool + return neq(a, b); + + @:op(A < B) private static inline function lt( a : Int64, b : Int64 ) : Bool + return compare(a, b) < 0; + + @:op(A < B) private static inline function ltInt( a : Int64, b : Int ) : Bool + return lt(a, b); - static function uicompare( a : Int, b : Int ) { - return a < 0 ? (b < 0 ? ~b - ~a : 1) : (b < 0 ? -1 : a - b); + @:op(A < B) private static inline function intLt( a : Int, b : Int64 ) : Bool + return lt(a, b); + + @:op(A <= B) private static inline function lte( a : Int64, b : Int64 ) : Bool + return compare(a, b) <= 0; + + @:op(A <= B) private static inline function lteInt( a : Int64, b : Int ) : Bool + return lte(a, b); + + @:op(A <= B) private static inline function intLte( a : Int, b : Int64 ) : Bool + return lte(a, b); + + @:op(A > B) private static inline function gt( a : Int64, b : Int64 ) : Bool + return compare(a, b) > 0; + + @:op(A > B) private static inline function gtInt( a : Int64, b : Int ) : Bool + return gt(a, b); + + @:op(A > B) private static inline function intGt( a : Int, b : Int64 ) : Bool + return gt( a, b ); + + @:op(A >= B) private static inline function gte( a : Int64, b : Int64 ) : Bool + return compare(a, b) >= 0; + + @:op(A >= B) private static inline function gteInt( a : Int64, b : Int ) : Bool + return gte(a, b); + + @:op(A >= B) private static inline function intGte( a : Int, b : Int64 ) : Bool + return gte(a, b); + + /** + Returns the bitwise NOT of `a`. + **/ + @:op(~A) private static inline function complement( a : Int64 ) : Int64 + return make( ~a.high, ~a.low ); + + /** + Returns the bitwise AND of `a` and `b`. + **/ + @:op(A & B) public static inline function and( a : Int64, b : Int64 ) : Int64 + return make( a.high & b.high, a.low & b.low ); + + /** + Returns the bitwise OR of `a` and `b`. + **/ + @:op(A | B) public static inline function or( a : Int64, b : Int64 ) : Int64 + return make( a.high | b.high, a.low | b.low ); + + /** + Returns the bitwise XOR of `a` and `b`. + **/ + @:op(A ^ B) public static inline function xor( a : Int64, b : Int64 ) : Int64 + return make( a.high ^ b.high, a.low ^ b.low ); + + /** + Returns `a` left-shifted by `b` bits. + **/ + @:op(A << B) public static inline function shl( a : Int64, b : Int ) : Int64 { + b &= 63; + return if( b == 0 ) a.copy() + else if( b < 32 ) make( (a.high << b) | (a.low >>> (32-b)), a.low << b) + else make( a.low << (b-32), 0 ); } - public static inline function compare( a : Int64, b : Int64 ) : Int { - var v = a.high - b.high; - return if( v != 0 ) v else uicompare(a.low,b.low); + /** + Returns `a` right-shifted by `b` bits in signed mode. + `a` is sign-extended. + **/ + @:op(A >> B) public static inline function shr( a : Int64, b : Int) : Int64 { + b &= 63; + return if( b == 0 ) a.copy() + else if( b < 32 ) make( a.high >> b, (a.high << (32-b)) | (a.low >>> b) ) + else make( a.high >> 31, a.high >> (b - 32) ); } /** - Compare two Int64 in unsigned mode. + Returns `a` right-shifted by `b` bits in unsigned mode. + `a` is padded with zeroes. **/ - public static inline function ucompare( a : Int64, b : Int64 ) : Int { - var v = uicompare(a.high,b.high); - return if( v != 0 ) v else uicompare(a.low, b.low); + @:op(A >>> B) public static inline function ushr( a : Int64, b : Int ) : Int64 { + b &= 63; + return if( b == 0 ) a.copy() + else if( b < 32 ) make( a.high >>> b, (a.high << (32-b)) | (a.low >>> b) ) + else make( 0, a.high >>> (b - 32) ); } - public static inline function toStr( a : Int64 ) : String { - return a.toString(); + public var high(get, never) : Int32; + private inline function get_high() return this.high; + private inline function set_high(x) return this.high = x; + + public var low(get, never) : Int32; + private inline function get_low() return this.low; + private inline function set_low(x) return this.low = x; +} + +/** + * This typedef will fool @:coreApi into thinking that we are using + * the same underlying type, even though it might be different on + * specific platforms. + */ +private typedef __Int64 = ___Int64; + +private class ___Int64 { + public var high : Int32; + public var low : Int32; + + public inline function new( high, low ) { + this.high = high; + this.low = low; } + /** + We also define toString here to ensure we always get a pretty string + when tracing or calling Std.string. This tends not to happen when + toString is only in the abstract. + **/ + public function toString() : String + return Int64.toStr( cast this ); } diff --git a/std/haxe/Json.hx b/std/haxe/Json.hx index e9162e94f4214ad7506ca40253a85ca8b450dbc2..98e7385ba838390c8cdd2c59feee28630c3bbea2 100644 --- a/std/haxe/Json.hx +++ b/std/haxe/Json.hx @@ -1,483 +1,57 @@ -/* - * Copyright (C)2005-2012 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; - -/** - Crossplatform JSON API : it will automatically use the optimized native API if available. - Use -D haxeJSON to force usage of the haXe implementation even if a native API is found : this will provide - extra encoding features such as enums (replaced by their index), Hashs and Iterable. -**/ -#if (flash11 && !haxeJSON) -@:native('JSON') extern -#end -class Json { - -#if (haxeJSON || !flash11) - var buf : #if flash9 flash.utils.ByteArray #else StringBuf #end; - var str : String; - var pos : Int; - - function new() { - } - - @:extern inline function addChar(c:Int) { - #if flash9 - buf.writeByte(c); - #else - buf.addChar(c); - #end - } - - @:extern inline function add(v:String) { - #if flash9 - // argument is not always a string but will be automatically casted - buf.writeUTFBytes(v); - #else - buf.add(v); - #end - } - - var replacer:Dynamic -> Dynamic -> Dynamic; - - function toString(v:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic) { - #if flash9 - buf = new flash.utils.ByteArray(); - buf.endian = flash.utils.Endian.BIG_ENDIAN; - buf.position = 0; - #else - buf = new StringBuf(); - #end - this.replacer = replacer; - toStringRec("", v); - return buf.toString(); - } - - function fieldsString( v : Dynamic, fields : Array ) - { - var first = true; - addChar('{'.code); - for( f in fields ) { - var value = Reflect.field(v,f); - if( Reflect.isFunction(value) ) continue; - if( first ) first = false else addChar(','.code); - quote(f); - addChar(':'.code); - toStringRec(f, value); - } - addChar('}'.code); - } - - #if flash9 - function classString ( v : Dynamic ) { - fieldsString(v,Type.getInstanceFields(Type.getClass(v))); - } - #end - - function objString( v : Dynamic ) { - fieldsString(v,Reflect.fields(v)); - } - - function toStringRec(k:Dynamic, v:Dynamic) { - if (replacer != null) v = replacer(k, v); - switch( Type.typeof(v) ) { - case TUnknown: - add('"???"'); - case TObject: - objString(v); - case TInt: - add(v); - case TFloat: - add(Math.isFinite(v) ? v : 'null'); - case TFunction: - add('""'); - case TClass(c): - if( c == String ) - quote(v); - else if( c == Array ) { - var v : Array = v; - addChar('['.code); - var len = v.length; - if( len > 0 ) { - toStringRec(0, v[0]); - var i = 1; - while( i < len ) { - addChar(','.code); - toStringRec(i, v[i++]); - } - } - addChar(']'.code); - } else if( c == haxe.ds.StringMap ) { - var v : haxe.ds.StringMap = v; - var o = {}; - for( k in v.keys() ) - Reflect.setField(o,k,v.get(k)); - objString(o); - } else - #if flash9 - classString(v); - #else - objString(v); - #end - case TEnum(_): - var i : Dynamic = Type.enumIndex(v); - add(i); - case TBool: - add(#if php (v ? 'true' : 'false') #else v #end); - case TNull: - add('null'); - } - } - - function quote( s : String ) { - #if (neko || php || cpp) - if( s.length != haxe.Utf8.length(s) ) { - quoteUtf8(s); - return; - } - #end - addChar('"'.code); - var i = 0; - while( true ) { - var c = StringTools.fastCodeAt(s,i++); - if( StringTools.isEof(c) ) break; - switch( c ) { - case '"'.code: add('\\"'); - case '\\'.code: add('\\\\'); - case '\n'.code: add('\\n'); - case '\r'.code: add('\\r'); - case '\t'.code: add('\\t'); - case 8: add('\\b'); - case 12: add('\\f'); - default: addChar(c); - } - } - addChar('"'.code); - } - - #if (neko || php || cpp) - function quoteUtf8( s : String ) { - var u = new haxe.Utf8(); - haxe.Utf8.iter(s,function(c) { - switch( c ) { - case '\\'.code, '"'.code: u.addChar('\\'.code); u.addChar(c); - case '\n'.code: u.addChar('\\'.code); u.addChar('n'.code); - case '\r'.code: u.addChar('\\'.code); u.addChar('r'.code); - case '\t'.code: u.addChar('\\'.code); u.addChar('t'.code); - case 8: u.addChar('\\'.code); u.addChar('b'.code); - case 12: u.addChar('\\'.code); u.addChar('f'.code); - default: u.addChar(c); - } - }); - buf.add('"'); - buf.add(u.toString()); - buf.add('"'); - } - #end - - function doParse( str : String ) { - this.str = str; - this.pos = 0; - return parseRec(); - } - - function invalidChar() { - pos--; // rewind - throw "Invalid char "+StringTools.fastCodeAt(str,pos)+" at position "+pos; - } - - inline function nextChar() { - return StringTools.fastCodeAt(str,pos++); - } - - function parseRec() : Dynamic { - while( true ) { - var c = nextChar(); - switch( c ) { - case ' '.code, '\r'.code, '\n'.code, '\t'.code: - // loop - case '{'.code: - var obj = {}, field = null, comma : Null = null; - while( true ) { - var c = nextChar(); - switch( c ) { - case ' '.code, '\r'.code, '\n'.code, '\t'.code: - // loop - case '}'.code: - if( field != null || comma == false ) - invalidChar(); - return obj; - case ':'.code: - if( field == null ) - invalidChar(); - Reflect.setField(obj,field,parseRec()); - field = null; - comma = true; - case ','.code: - if( comma ) comma = false else invalidChar(); - case '"'.code: - if( comma ) invalidChar(); - field = parseString(); - default: - invalidChar(); - } - } - case '['.code: - var arr = [], comma : Null = null; - while( true ) { - var c = nextChar(); - switch( c ) { - case ' '.code, '\r'.code, '\n'.code, '\t'.code: - // loop - case ']'.code: - if( comma == false ) invalidChar(); - return arr; - case ','.code: - if( comma ) comma = false else invalidChar(); - default: - if( comma ) invalidChar(); - pos--; - arr.push(parseRec()); - comma = true; - } - } - case 't'.code: - var save = pos; - if( nextChar() != 'r'.code || nextChar() != 'u'.code || nextChar() != 'e'.code ) { - pos = save; - invalidChar(); - } - return true; - case 'f'.code: - var save = pos; - if( nextChar() != 'a'.code || nextChar() != 'l'.code || nextChar() != 's'.code || nextChar() != 'e'.code ) { - pos = save; - invalidChar(); - } - return false; - case 'n'.code: - var save = pos; - if( nextChar() != 'u'.code || nextChar() != 'l'.code || nextChar() != 'l'.code ) { - pos = save; - invalidChar(); - } - return null; - case '"'.code: - return parseString(); - case '0'.code, '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code,'-'.code: - return parseNumber(c); - default: - invalidChar(); - } - } - } - - function parseString() { - var start = pos; - var buf = new StringBuf(); - while( true ) { - var c = nextChar(); - if( c == '"'.code ) - break; - if( c == '\\'.code ) { - buf.addSub(str,start, pos - start - 1); - c = nextChar(); - switch( c ) { - case "r".code: buf.addChar("\r".code); - case "n".code: buf.addChar("\n".code); - case "t".code: buf.addChar("\t".code); - case "b".code: buf.addChar(8); - case "f".code: buf.addChar(12); - case "/".code, '\\'.code, '"'.code: buf.addChar(c); - case 'u'.code: - var uc = Std.parseInt("0x" + str.substr(pos, 4)); - pos += 4; - #if (neko || php || cpp) - if( uc <= 0x7F ) - buf.addChar(uc); - else if( uc <= 0x7FF ) { - buf.addChar(0xC0 | (uc >> 6)); - buf.addChar(0x80 | (uc & 63)); - } else if( uc <= 0xFFFF ) { - buf.addChar(0xE0 | (uc >> 12)); - buf.addChar(0x80 | ((uc >> 6) & 63)); - buf.addChar(0x80 | (uc & 63)); - } else { - buf.addChar(0xF0 | (uc >> 18)); - buf.addChar(0x80 | ((uc >> 12) & 63)); - buf.addChar(0x80 | ((uc >> 6) & 63)); - buf.addChar(0x80 | (uc & 63)); - } - #else - buf.addChar(uc); - #end - default: - throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1); - } - start = pos; - } - #if (neko || php || cpp) - // ensure utf8 chars are not cut - else if( c >= 0x80 ) { - pos++; - if( c >= 0xFC ) pos += 4; - else if( c >= 0xF8 ) pos += 3; - else if( c >= 0xF0 ) pos += 2; - else if( c >= 0xE0 ) pos++; - } - #end - else if( StringTools.isEof(c) ) - throw "Unclosed string"; - } - buf.addSub(str,start, pos - start - 1); - return buf.toString(); - } - - function invalidNumber( start : Int ) { - throw "Invalid number at position "+start+": " + str.substr(start, pos - start); - } - - inline function parseNumber( c : Int ) { - var start = pos - 1; - var minus = c == '-'.code, digit = !minus, zero = c == '0'.code; - var point = false, e = false, pm = false, end = false; - while( true ) { - c = nextChar(); - switch( c ) { - case '0'.code : - if (zero && !point) invalidNumber(start); - if (minus) { - minus = false; zero = true; - } - digit = true; - case '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code : - if (zero && !point) invalidNumber(start); - if (minus) minus = false; - digit = true; zero = false; - case '.'.code : - if (minus || point) invalidNumber(start); - digit = false; point = true; - case 'e'.code, 'E'.code : - if (minus || zero || e) invalidNumber(start); - digit = false; e = true; - case '+'.code, '-'.code : - if (!e || pm) invalidNumber(start); - digit = false; pm = true; - default : - if (!digit) invalidNumber(start); - pos--; - end = true; - } - if (end) break; - } - var f = Std.parseFloat(str.substr(start, pos - start)); - var i = Std.int(f); - return if( i == f ) i else f; - } - -#end - - public static function parse( text : String ) : Dynamic { - #if (php && !haxeJSON) - return phpJsonDecode(text); - #elseif (flash11 && !haxeJSON) - return null; - #else - return new Json().doParse(text); - #end - } - - public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic ) : String { - #if (php && !haxeJSON) - return phpJsonEncode(value); - #elseif (flash11 && !haxeJSON) - return null; - #else - return new Json().toString(value, replacer); - #end - } - - #if !haxeJSON - #if js - static function __init__() untyped { - if( __js__('typeof(JSON)') != 'undefined' ) - Json = __js__('JSON'); - } - #end - #end - - #if php - static function phpJsonDecode(json:String):Dynamic { - var val = untyped __call__("json_decode", json); - return convertAfterDecode(val); - } - - static function convertAfterDecode(val:Dynamic):Dynamic { - var arr:php.NativeArray; - if (untyped __call__("is_object", val)) { - arr = phpMapArray(php.Lib.associativeArrayOfObject(val), convertAfterDecode); - return untyped __call__("_hx_anonymous", arr); - } - else if (untyped __call__("is_array", val)) { - arr = phpMapArray(val, convertAfterDecode); - return php.Lib.toHaxeArray(arr); - } - else - return val; - } - - static function phpJsonEncode(val:Dynamic):String { - var json = untyped __call__("json_encode", convertBeforeEncode(val)); - if (untyped __physeq__(json, false)) - return throw "invalid json"; - else - return json; - } - - static function convertBeforeEncode(val:Dynamic):Dynamic { - var arr:php.NativeArray; - if (untyped __call__("is_object", val)) { - switch (untyped __call__("get_class", val)) { - case "_hx_anonymous", "stdClass" : arr = php.Lib.associativeArrayOfObject(val); - case "_hx_array" : arr = php.Lib.toPhpArray(val); - case "Date" : return Std.string(val); //.split(" ").join("T"); //better with "T"? - case "HList" : arr = php.Lib.toPhpArray(Lambda.array(val)); //convert List to array? - case "_hx_enum" : return Type.enumIndex(val); - case "StringMap", "IntMap" : arr = php.Lib.associativeArrayOfHash(val); - default : arr = php.Lib.associativeArrayOfObject(val); - } - } - else if (untyped __call__("is_array", val)) arr = val; - else { - if (untyped __call__("is_float",val) && !__call__("is_finite",val)) val = null; - return val; - } - return phpMapArray(arr, convertBeforeEncode); - } - - inline static function phpMapArray(arr:php.NativeArray - , func:Dynamic->Dynamic):php.NativeArray { - return untyped __call__("array_map", func, arr); - } - - #end - -} +/* + * Copyright (C)2005-2012 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; + +/** + Crossplatform JSON API : it will automatically use the optimized native API if available. + Use -D haxeJSON to force usage of the Haxe implementation even if a native API is found : this will provide + extra encoding features such as enums (replaced by their index) and StringMaps. +**/ +class Json { + + /** + Parses given JSON-encoded `text` and returns the resulting object. + + JSON objects are parsed into anonymous structures and JSON arrays + are parsed into Array. + + If given `text` is not valid JSON, an exception will be thrown. + **/ + public static inline function parse( text : String ) : Dynamic { + return haxe.format.JsonParser.parse(text); + } + + /** + Encodes given `value` and returns the resulting JSON string. + + If `replacer` is given and is not null, it is used to retrieve + actual object to be encoded. The `replacer` function two parameters, + the key and the value being encoded. Initial key value is an empty string. + + If `space` is given and is not null, the result will be pretty-printed. + Successive levels will be indented by this string. + **/ + public static inline function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space : String ) : String { + return haxe.format.JsonPrinter.print(value, replacer, space); + } + +} diff --git a/std/haxe/Log.hx b/std/haxe/Log.hx index a3bc377c44a8a0a7472749a02b0867fab9b1bd3e..6a7a944eaa19580f550718b4f25dce6bc5fd7b98 100644 --- a/std/haxe/Log.hx +++ b/std/haxe/Log.hx @@ -28,9 +28,9 @@ package haxe; class Log { /** - Outputs [v] in a platform-dependent way. + Outputs `v` in a platform-dependent way. - The second parameter [infos] is injected by the compiler and contains + The second parameter `infos` is injected by the compiler and contains information about the position where the trace() call was made. This method can be rebound to a custom function: @@ -48,7 +48,7 @@ class Log { var pstr = infos == null ? "(null)" : infos.fileName + ":" + infos.lineNumber; var str = flash.Boot.__string_rec(v, ""); if( infos != null && infos.customParams != null ) for( v in infos.customParams ) str += "," + flash.Boot.__string_rec(v, ""); - untyped #if flash9 __global__["trace"] #else __trace__ #end(pstr+": "+str); + untyped __global__["trace"](pstr+": "+str); #else untyped flash.Boot.__trace(v,infos); #end @@ -68,7 +68,7 @@ class Log { untyped __call__('_hx_trace', v + extra, infos); } else - untyped __call__('_hx_trace', v, infos); + untyped __call__('_hx_trace', v, infos); #elseif cpp if (infos!=null && infos.customParams!=null) { var extra:String = ""; @@ -90,10 +90,21 @@ class Log { str = v; } #if cs - untyped __cs__("System.Console.WriteLine(str)"); + cs.system.Console.WriteLine(str); #elseif java untyped __java__("java.lang.System.out.println(str)"); #end + #elseif (python) + var str:String = null; + if (infos != null) { + str = infos.fileName + ":" + Std.string(infos.lineNumber) + ": " + v; + if (infos.customParams != null) { + str += "," + infos.customParams.join(","); + } + } else { + str = v; + } + python.Lib.println(str); #end } @@ -112,7 +123,7 @@ class Log { #if flash /** - Sets the color of the trace output to [rgb]. + Sets the color of the trace output to `rgb`. **/ public static dynamic function setColor( rgb : Int ) { untyped flash.Boot.__set_trace_color(rgb); diff --git a/std/haxe/PosInfos.hx b/std/haxe/PosInfos.hx index 0f2fe578fc7408b57952b531686ec95d37f4aa69..1c9682de7bf09607f9130c5a9fbd80331f6d0a9a 100644 --- a/std/haxe/PosInfos.hx +++ b/std/haxe/PosInfos.hx @@ -24,11 +24,11 @@ package haxe; /** PosInfos is a magic type which can be used to generate position information into the output for debugging use. - + If a function has a final optional argument of this type, i.e. (..., ?pos:haxe.PosInfos), each call to that function which does not assign a value to that argument has its position added as call argument. - + This can be used to track positions of calls in e.g. a unit testing framework. **/ diff --git a/std/haxe/Resource.hx b/std/haxe/Resource.hx index dcf7f3c3bcf41a00705683b2a8f7bcfd8583c45b..228111a31c6b986331efbc74ac715510d615e601 100644 --- a/std/haxe/Resource.hx +++ b/std/haxe/Resource.hx @@ -32,110 +32,52 @@ package haxe; **/ class Resource { - #if (java || cs) - static var content : Array; - #else static var content : Array<{ name : String, data : String, str : String }>; - #end - - #if cs - static var paths : haxe.ds.StringMap; - - #if cs @:keep #end private static function getPaths():haxe.ds.StringMap - { - if (paths != null) - return paths; - var p = new haxe.ds.StringMap(); - var all:cs.NativeArray = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceNames()"); - for (i in 0...all.Length) - { - var path = all[i]; - var name = path.substr(path.indexOf("Resources.") + 10); - p.set(name, path); - } - - return paths = p; - } - #end /** Lists all available resource names. The resource name is the name part of the -resource file@name command line parameter. **/ public static function listNames() : Array { - var names = new Array(); - #if (java || cs) - for ( x in content ) - names.push(x); - #else - for ( x in content ) - names.push(x.name); - #end - return names; + return [for (x in content) x.name]; } /** - Retrieves the resource identified by [name] as a String. + Retrieves the resource identified by `name` as a String. - If [name] does not match any resource name, null is returned. + If `name` does not match any resource name, null is returned. **/ public static function getString( name : String ) : String { - #if java - var stream = cast(Resource, java.lang.Class).getResourceAsStream("/" + name); - if (stream == null) - return null; - var stream = new java.io.NativeInput(stream); - return stream.readAll().toString(); - #elseif cs - var str:cs.system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream((string)getPaths().get(name).@value)"); - if (str != null) - return new cs.io.NativeInput(str).readAll().toString(); - return null; - #else 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.Unserializer.run(x.data); + var b : haxe.io.Bytes = haxe.crypto.Base64.decode(x.data); return b.toString(); #end } return null; - #end } /** - Retrieves the resource identified by [name] as an instance of + Retrieves the resource identified by `name` as an instance of haxe.io.Bytes. - If [name] does not match any resource name, null is returned. + If `name` does not match any resource name, null is returned. **/ public static function getBytes( name : String ) : haxe.io.Bytes { - #if java - var stream = cast(Resource, java.lang.Class).getResourceAsStream("/" + name); - if (stream == null) - return null; - var stream = new java.io.NativeInput(stream); - return stream.readAll(); - #elseif cs - var str:cs.system.io.Stream = untyped __cs__("typeof(haxe.Resource).Assembly.GetManifestResourceStream((string)getPaths().get(name).@value)"); - if (str != null) - return new cs.io.NativeInput(str).readAll(); - return null; - #else 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.Unserializer.run(x.data); + return haxe.crypto.Base64.decode(x.data); #end } return null; - #end } static function __init__() { @@ -146,8 +88,6 @@ class Resource { content = null; #elseif as3 null; - #elseif (java || cs) - //do nothing #else content = untyped __resources__(); #end diff --git a/std/haxe/Serializer.hx b/std/haxe/Serializer.hx index 53b3609345009772d8dea74d142032b34228200e..acc92136473606f05d8639341d84a15d4999e0b4 100644 --- a/std/haxe/Serializer.hx +++ b/std/haxe/Serializer.hx @@ -26,17 +26,18 @@ package haxe; from which the Unserializer class can recreate the original representation. This class can be used in two ways: - - create a new Serializer() instance, call its serialize() method with + + - create a new Serializer() instance, call its serialize() method with any argument and finally retrieve the String representation from toString() - - call Serializer.run() to obtain the serialized representation of a + - call Serializer.run() to obtain the serialized representation of a single argument Serialization is guaranteed to work for all haxe-defined classes, but may or may not work for instances of external/native classes. The specification of the serialization format can be found here: - http://haxe.org/manual/serialization/format + `http://haxe.org/manual/serialization/format` **/ class Serializer { @@ -73,14 +74,14 @@ class Serializer { var scount : Int; /** - The individual cache setting for [this] Serializer instance. + The individual cache setting for `this` Serializer instance. See USE_CACHE for a complete description. **/ public var useCache : Bool; /** - The individual enum index setting for [this] Serializer instance. + The individual enum index setting for `this` Serializer instance. See USE_ENUM_INDEX for a complete description. **/ @@ -89,11 +90,11 @@ class Serializer { /** Creates a new Serializer instance. - Subsequent calls to [this].serialize() will append values to the + Subsequent calls to `this.serialize` will append values to the internal buffer of this String. Once complete, the contents can be - retrieved through a call to [this].toString() . + retrieved through a call to `this.toString`. - Each Serializer instance maintains its own cache if [this].useCache is + Each Serializer instance maintains its own cache if this.useCache` is true. **/ public function new() { @@ -106,7 +107,7 @@ class Serializer { } /** - Return the String representation of [this] Serializer. + Return the String representation of `this` Serializer. The exact format specification can be found here: http://haxe.org/manual/serialization/format @@ -142,6 +143,8 @@ class Serializer { x : exception y : urlencoded string z : zero + A : Class + B : Enum M : haxe.ds.ObjectMap C : custom */ @@ -185,7 +188,7 @@ class Serializer { return false; } - #if flash9 + #if flash // only the instance variables function serializeClassFields(v,c) { @@ -211,13 +214,13 @@ class Serializer { } /** - Serializes [v]. + Serializes `v`. All haxe-defined values and objects with the exception of functions can be serialized. Serialization of external/native objects is not guaranteed to work. - The values of [this].useCache and [this].useEnumIndex may affect + The values of `this.useCache` and `this.useEnumIndex` may affect serialization output. **/ public function serialize( v : Dynamic ) { @@ -225,6 +228,7 @@ class Serializer { case TNull: buf.add("n"); case TInt: + var v : Int = v; if( v == 0 ) { buf.add("z"); return; @@ -232,6 +236,7 @@ class Serializer { buf.add("i"); buf.add(v); case TFloat: + var v : Float = v; if( Math.isNaN(v) ) buf.add("k"); else if( !Math.isFinite(v) ) @@ -249,14 +254,14 @@ class Serializer { } if( useCache && serializeRef(v) ) return; - switch( #if (neko || cs) Type.getClassName(c) #else c #end ) { - case #if (neko || cs) "Array" #else cast Array #end: + switch( #if (neko || cs || python) Type.getClassName(c) #else c #end ) { + case #if (neko || cs || python) "Array" #else cast Array #end: var ucount = 0; buf.add("a"); - #if flash9 + #if (flash || python) var v : Array = v; #end - var l = #if (neko || flash9 || php || cs || java) v.length #elseif cpp v.__length() #else v[untyped "length"] #end; + var l = #if (neko || flash || php || cs || java || python) v.length #elseif cpp v.__length() #else __getField(v, "length") #end; for( i in 0...l ) { if( v[i] == null ) ucount++; @@ -282,17 +287,17 @@ class Serializer { } } buf.add("h"); - case #if (neko || cs) "List" #else cast List #end: + case #if (neko || cs || python) "List" #else cast List #end: buf.add("l"); var v : List = v; for( i in v ) serialize(i); buf.add("h"); - case #if (neko || cs) "Date" #else cast Date #end: + case #if (neko || cs || python) "Date" #else cast Date #end: var d : Date = v; buf.add("v"); - buf.add(d.toString()); - case #if (neko || cs) "haxe.ds.StringMap" #else cast haxe.ds.StringMap #end: + buf.add(d.getTime()); + case #if (neko || cs || python) "haxe.ds.StringMap" #else cast haxe.ds.StringMap #end: buf.add("b"); var v : haxe.ds.StringMap = v; for( k in v.keys() ) { @@ -300,7 +305,7 @@ class Serializer { serialize(v.get(k)); } buf.add("h"); - case #if (neko || cs) "haxe.ds.IntMap" #else cast haxe.ds.IntMap #end: + case #if (neko || cs || python) "haxe.ds.IntMap" #else cast haxe.ds.IntMap #end: buf.add("q"); var v : haxe.ds.IntMap = v; for( k in v.keys() ) { @@ -309,11 +314,11 @@ class Serializer { serialize(v.get(k)); } buf.add("h"); - case #if (neko || cs) "haxe.ds.ObjectMap" #else cast haxe.ds.ObjectMap #end: + case #if (neko || cs || python) "haxe.ds.ObjectMap" #else cast haxe.ds.ObjectMap #end: buf.add("M"); var v : haxe.ds.ObjectMap = v; for ( k in v.keys() ) { - #if (js || flash8 || neko) + #if (js || neko) var id = Reflect.field(k, "__id__"); Reflect.deleteField(k, "__id__"); serialize(k); @@ -324,7 +329,7 @@ class Serializer { serialize(v.get(k)); } buf.add("h"); - case #if (neko || cs) "haxe.io.Bytes" #else cast haxe.io.Bytes #end: + case #if (neko || cs || python) "haxe.io.Bytes" #else cast haxe.io.Bytes #end: var v : haxe.io.Bytes = v; #if neko var chars = new String(base_encode(v.getData(),untyped BASE64.__s)); @@ -361,18 +366,18 @@ class Serializer { buf.add(":"); buf.add(chars); default: - cache.pop(); - if( #if flash9 try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java) Reflect.hasField(v, "hxSerialize") #else v.hxSerialize != null #end ) { + if( useCache ) cache.pop(); + if( #if flash try v.hxSerialize != null catch( e : Dynamic ) false #elseif (cs || java || python) Reflect.hasField(v, "hxSerialize") #else v.hxSerialize != null #end ) { buf.add("C"); serializeString(Type.getClassName(c)); - cache.push(v); + if( useCache ) cache.push(v); v.hxSerialize(this); buf.add("g"); } else { buf.add("c"); serializeString(Type.getClassName(c)); - cache.push(v); - #if flash9 + if( useCache ) cache.push(v); + #if flash serializeClassFields(v,c); #else serializeFields(v); @@ -380,14 +385,30 @@ class Serializer { } } case TObject: - if( useCache && serializeRef(v) ) - return; - buf.add("o"); - serializeFields(v); + if (Std.is(v,Class)) { + var className = Type.getClassName(v); + #if (flash || cpp) + // Currently, Enum and Class are the same for flash and cpp. + // use resolveEnum to test if it is actually an enum + if (Type.resolveEnum(className)!=null) buf.add("B") else + #end + buf.add("A"); + serializeString(className); + } else if (Std.is(v,Enum)) { + buf.add("B"); + serializeString(Type.getEnumName(v)); + } else { + if( useCache && serializeRef(v) ) + return; + buf.add("o"); + serializeFields(v); + } case TEnum(e): - if( useCache && serializeRef(v) ) - return; - cache.pop(); + if( useCache ) { + if( serializeRef(v) ) + return; + cache.pop(); + } buf.add(useEnumIndex?"j":"w"); serializeString(Type.getEnumName(e)); #if neko @@ -405,10 +426,11 @@ class Serializer { for( i in 0...l ) serialize(v.args[i]); } - #elseif flash9 + #elseif flash if( useEnumIndex ) { buf.add(":"); - buf.add(v.index); + var i : Int = v.index; + buf.add(i); } else serializeString(v.tag); buf.add(":"); @@ -450,7 +472,7 @@ class Serializer { for( i in 0...l ) serialize(untyped __field__(v, __php__("params"), i)); } - #elseif (java || cs) + #elseif (java || cs || python) if( useEnumIndex ) { buf.add(":"); buf.add(Type.enumIndex(v)); @@ -474,12 +496,12 @@ class Serializer { } else serializeString(v[0]); buf.add(":"); - var l = v[untyped "length"]; + var l = __getField(v, "length"); buf.add(l - 2); for( i in 2...l ) serialize(v[i]); #end - cache.push(v); + if( useCache ) cache.push(v); case TFunction: throw "Cannot serialize function"; default: @@ -494,9 +516,11 @@ class Serializer { } } + @:extern inline function __getField(o:Dynamic, f:String):Dynamic return untyped o[f]; + public function serializeException( e : Dynamic ) { buf.add("x"); - #if flash9 + #if flash if( untyped __is__(e,__global__["Error"]) ) { var e : flash.errors.Error = e; var s = e.getStackTrace(); @@ -511,10 +535,10 @@ class Serializer { } /** - Serializes [v] and returns the String representation. + Serializes `v` and returns the String representation. This is a convenience function for creating a new instance of - Serializer, serialize [v] into it and obtain the result through a call + Serializer, serialize `v` into it and obtain the result through a call to toString(). **/ public static function run( v : Dynamic ) { diff --git a/std/haxe/Template.hx b/std/haxe/Template.hx index 890d4c6d8e02c948bbfab062a221279d9c30fa89..1855f7fd6b782ba921d5212d8d5efc718c15485d 100644 --- a/std/haxe/Template.hx +++ b/std/haxe/Template.hx @@ -45,9 +45,9 @@ private typedef ExprToken = { /** Template provides a basic templating mechanism to replace values in a source String, and to have some basic logic. - + A complete documentation of the supported syntax is available at: - http://haxe.org/doc/cross/template + http://haxe.org/manual/std-template.html **/ class Template { @@ -70,14 +70,14 @@ class Template { var buf : StringBuf; /** - Creates a new Template instance from [str]. - - [str] is parsed into tokens, which are stored for internal use. This + Creates a new Template instance from `str`. + + `str` is parsed into tokens, which are stored for internal use. This means that multiple execute() operations on a single Template instance are more efficient than one execute() operations on multiple Template instances. - - If [str] is null, the result is unspecified. + + If `str` is null, the result is unspecified. **/ public function new( str : String ) { var tokens = parseTokens(str); @@ -87,19 +87,19 @@ class Template { } /** - Executes [this] Template, taking into account [context] for - replacements and [macros] for callback functions. - - If [context] has a field 'name', its value replaces all occurrences of + Executes `this` Template, taking into account `context` for + replacements and `macros` for callback functions. + + If `context` has a field 'name', its value replaces all occurrences of ::name:: in the Template. Otherwise Template.globals is checked instead, If 'name' is not a field of that either, ::name:: is replaced with null. - - If [macros] has a field 'name', all occurrences of $$name(args) are + + If `macros` has a field 'name', all occurrences of $$name(args) are replaced with the result of calling that field. The first argument is - always the the resolve() method, followed by the given arguments. - If [macros] has no such field, the result is unspecified. - - If [context] is null, the result is unspecified. If [macros] is null, + always the resolve() method, followed by the given arguments. + If `macros` has no such field, the result is unspecified. + + If `context` is null, the result is unspecified. If `macros` is null, no macros are used. **/ public function execute( context : Dynamic, ?macros : Dynamic ):String { @@ -139,17 +139,27 @@ class Template { // macro parse var parp = p.pos + p.len; var npar = 1; - while( npar > 0 ) { + var params = []; + var part = ""; + while( true ) { var c = data.charCodeAt(parp); - if( c == 40 ) + parp++; + if( c == 40 ) { npar++; - else if( c == 41 ) + } else if( c == 41 ) { npar--; - else if( c == null ) + if (npar <= 0) break; + } else if( c == null ){ throw "Unclosed macro parenthesis"; - parp++; + } + if ( c == 44 && npar == 1) { + params.push(part); + part = ""; + } else { + part += String.fromCharCode(c); + } } - var params = data.substr(p.pos+p.len,parp - (p.pos+p.len) - 1).split(","); + params.push(part); tokens.add({ p : splitter.matched(2), s : false, l : params }); data = data.substr(parp,data.length - parp); } @@ -237,7 +247,7 @@ class Template { } if( data.length != 0 ) l.add({ p : data, s : true }); - var e; + var e:Void->Dynamic; try { e = makeExpr(l); if( !l.isEmpty() ) @@ -325,7 +335,7 @@ class Template { default: throw "Unknown operation "+p.p; } case "!": - var e = makeExpr(l); + var e : Void->Dynamic = makeExpr(l); return function() { var v : Dynamic = e(); return (v == null || v == false); diff --git a/std/haxe/Timer.hx b/std/haxe/Timer.hx index dbfeb6b955a66cb10cb7b64d8c35bd7cc395a7d2..ea1924918d494c0f199a62ffea1cf800c6b0a1f7 100644 --- a/std/haxe/Timer.hx +++ b/std/haxe/Timer.hx @@ -24,88 +24,99 @@ package haxe; /** The Timer class allows you to create asynchronous timers on platforms that support events. - + The intended usage is to create an instance of the Timer class with a given interval, set its run() method to a custom function to be invoked and eventually call stop() to stop the Timer. - + + Note that a running Timer may or may not prevent the program to exit + automatically when main() returns. + It is also possible to extend this class and override its run() method in the child class. **/ class Timer { - #if (neko || php || cpp) - #else + #if (flash || js || java || python) - private var id : Null; + #if (flash || js) + private var id : Null; + #elseif java + private var timer : java.util.Timer; + private var task : java.util.TimerTask; + #end /** - Creates a new timer that will run every [time_ms] milliseconds. - - After creating the Timer instance, it calls [this].run() repeatedly, - with delays of [time_ms] milliseconds, until [this].stop() is called. - - The first invocation occurs after [time_ms] milliseconds, not + Creates a new timer that will run every `time_ms` milliseconds. + + After creating the Timer instance, it calls `this].run` repeatedly, + with delays of `time_ms` milliseconds, until `this.stop` is called. + + The first invocation occurs after `time_ms` milliseconds, not immediately. - + The accuracy of this may be platform-dependent. **/ public function new( time_ms : Int ){ - #if flash9 + #if flash var me = this; id = untyped __global__["flash.utils.setInterval"](function() { me.run(); },time_ms); - #elseif flash - var me = this; - id = untyped _global["setInterval"](function() { me.run(); },time_ms); #elseif js var me = this; id = untyped setInterval(function() me.run(),time_ms); + #elseif java + timer = new java.util.Timer(); + timer.scheduleAtFixedRate(task = new TimerTask(this), haxe.Int64.ofInt(time_ms), haxe.Int64.ofInt(time_ms)); #end } /** - Stops [this] Timer. - - After calling this method, no additional invocations of [this].run() + Stops `this` Timer. + + After calling this method, no additional invocations of `this.run` will occur. - - It is not possible to restart [this] Timer once stopped. + + It is not possible to restart `this` Timer once stopped. **/ public function stop() { - if( id == null ) - return; - #if flash9 - untyped __global__["flash.utils.clearInterval"](id); - #elseif flash - untyped _global["clearInterval"](id); - #elseif js - untyped clearInterval(id); + #if (flash || js) + if( id == null ) + return; + #if flash + untyped __global__["flash.utils.clearInterval"](id); + #elseif js + untyped clearInterval(id); + #end + id = null; + #elseif java + timer.cancel(); + timer = null; + task = null; #end - id = null; } /** - This method is invoked repeatedly on [this] Timer. - + This method is invoked repeatedly on `this` Timer. + It can be overridden in a subclass, or rebound directly to a custom function: 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(). + + Once bound, it can still be rebound to different functions until `this` + Timer is stopped through a call to `this.stop`. **/ public dynamic function run() { - trace("run"); + } /** - Invokes [f] after [time_ms] milliseconds. - + Invokes `f` after `time_ms` milliseconds. + This is a convenience function for creating a new Timer instance with - [time_ms] as argument, binding its run() method to [f] and then stopping - [this] Timer upon the first invocation. - - If [f] is null, the result is unspecified. + `time_ms` as argument, binding its run() method to `f` and then stopping + `this` Timer upon the first invocation. + + If `f` is null, the result is unspecified. **/ public static function delay( f : Void -> Void, time_ms : Int ) { var t = new haxe.Timer(time_ms); @@ -119,15 +130,15 @@ class Timer { #end /** - Measures the time it takes to execute [f], in seconds with fractions. - + Measures the time it takes to execute `f`, in seconds with fractions. + This is a convenience function for calculating the difference between - Timer.stamp() before and after the invocation of [f]. - + Timer.stamp() before and after the invocation of `f`. + The difference is passed as argument to Log.trace(), with "s" appended - to denote the unit. The optional [pos] argument is passed through. - - If [f] is null, the result is unspecified. + to denote the unit. The optional `pos` argument is passed through. + + If `f` is null, the result is unspecified. **/ public static function measure( f : Void -> T, ?pos : PosInfos ) : T { var t0 = stamp(); @@ -138,7 +149,7 @@ class Timer { /** Returns a timestamp, in seconds with fractions. - + The value itself might differ depending on platforms, only differences between two values make sense. **/ @@ -159,3 +170,18 @@ class Timer { } } + +#if java +@:nativeGen +private class TimerTask extends java.util.TimerTask { + var timer:Timer; + public function new(timer:Timer):Void { + super(); + this.timer = timer; + } + + @:overload override public function run():Void { + timer.run(); + } +} +#end diff --git a/std/haxe/Ucs2.hx b/std/haxe/Ucs2.hx new file mode 100644 index 0000000000000000000000000000000000000000..f974710404c6dd442e1d7750fd7e873dacafd038 --- /dev/null +++ b/std/haxe/Ucs2.hx @@ -0,0 +1,192 @@ +/* + * Copyright (C)2005-2012 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; + +/** + Cross platform UCS2 string API. +**/ +abstract Ucs2(String) { + + @:extern public var length(get,never) : Int; + + @:extern inline function new(str:String) : Void { + // this implementation only allows platforms which have native UCS2 String. + // other platforms should create a shadow class in their _std directory + #if !(flash || js) + throw "Ucs2 String not supported on this platform"; + #end + this = str; + } + + @:extern inline function get_length() { + return this.length; + } + + /** + Returns a Ucs2 where all characters of `this` Ucs2 are upper case. + + Affects the characters `a-z`. Other characters remain unchanged. + **/ + @:extern public inline function toUpperCase() : Ucs2 { + return new Ucs2(this.toUpperCase()); + } + + /** + Returns a Ucs2 where all characters of `this` Ucs2 are lower case. + + Affects the characters `A-Z`. Other characters remain unchanged. + **/ + @:extern public inline function toLowerCase() : Ucs2 { + return new Ucs2(this.toLowerCase()); + } + + /** + Returns the character at position `index` of `this` Ucs2. + + If `index` is negative or exceeds `this.length`, the empty Ucs2 "" + is returned. + **/ + @:extern public inline function charAt(index : Int) : Ucs2 { + return new Ucs2(this.charAt(index)); + } + + /** + Returns the character code at position `index` of `this` Ucs2. + + If `index` is negative or exceeds `this.length`, null is returned. + + To obtain the character code of a single character, "x".code can be used + instead to @:extern public inline the character code at compile time. Note that this + only works on Ucs2 literals of length 1. + **/ + @:extern public inline function charCodeAt( index : Int) : Null { + return this.charCodeAt(index); + } + + /** + Returns the position of the leftmost occurence of `str` within `this` + Ucs2. + + If `startIndex` is given, the search is performed within the substring + of `this` Ucs2 starting from `startIndex`. Otherwise the search is + performed within `this` Ucs2. In either case, the returned position + is relative to the beginning of `this` Ucs2. + + If `str` cannot be found, -1 is returned. + **/ + @:extern public inline function indexOf( str : Ucs2, ?startIndex : Int ) : Int { + return this.indexOf(str.toNativeString(),startIndex); + } + + /** + Returns the position of the rightmost occurence of `str` within `this` + Ucs2. + + If `startIndex` is given, the search is performed within the substring + of `this` Ucs2 from 0 to `startIndex`. Otherwise the search is + performed within `this` Ucs2. In either case, the returned position + is relative to the beginning of `this` Ucs2. + + If `str` cannot be found, -1 is returned. + **/ + @:extern public inline function lastIndexOf( str : Ucs2, ?startIndex : Int ) : Int { + return this.lastIndexOf(str.toNativeString(),startIndex); + } + + /** + Splits `this` Ucs2 at each occurence of `delimiter`. + + If `this` Ucs2 is the empty Ucs2 "", the result is not consistent + across targets and may either be `[]` (on Js, Cpp) or `[""]`. + + If `delimiter` is the empty Ucs2 "", `this` Ucs2 is split into an + Array of `this.length` elements, where the elements correspond to the + characters of `this` Ucs2. + + If `delimiter` is not found within `this` Ucs2, the result is an Array + with one element, which equals `this` Ucs2. + + If `delimiter` is null, the result is unspecified. + + Otherwise, `this` Ucs2 is split into parts at each occurence of + `delimiter`. If `this` Ucs2 starts (or ends) with [delimiter}, the + result Array contains a leading (or trailing) empty Ucs2 "" element. + Two subsequent delimiters also result in an empty Ucs2 "" element. + **/ + @:extern public inline function split( delimiter : Ucs2 ) : Array { + return cast this.split(delimiter.toNativeString()); + } + + /** + Returns `len` characters of `this` Ucs2, starting at position `pos`. + + If `len` is omitted, all characters from position `pos` to the end of + `this` Ucs2 are included. + + If `pos` is negative, its value is calculated from the end of `this` + Ucs2 by `this.length + pos`. If this yields a negative value, 0 is + used instead. + + If the calculated position + `len` exceeds `this.length`, the characters + from that position to the end of `this` Ucs2 are returned. + + If `len` is negative, the result is unspecified. + **/ + @:extern public inline function substr( pos : Int, ?len : Int ) : Ucs2 { + return new Ucs2(this.substr(pos,len)); + } + + /** + Returns the part of `this` Ucs2 from `startIndex` to `endIndex`. + + If `startIndex` or `endIndex` are negative, 0 is used instead. + + If `startIndex` exceeds `endIndex`, they are swapped. + + If the (possibly swapped) `endIndex` is omitted or exceeds + `this.length`, `this.length` is used instead. + + If the (possibly swapped) `startIndex` exceeds `this.length`, the empty + Ucs2 "" is returned. + **/ + @:extern public inline function substring( startIndex : Int, ?endIndex : Int ) : Ucs2 { + return new Ucs2(this.substring(startIndex,endIndex)); + } + + /** + Returns the native underlying String. + **/ + @:extern public inline function toNativeString() : String { + return this; + } + + /** + Returns the Ucs2 corresponding to the character code `code`. + + If `code` is negative or has another invalid value, the result is + unspecified. + **/ + @:extern public static inline function fromCharCode( code : Int ) : Ucs2 { + return new Ucs2(String.fromCharCode(code)); + } + +} \ No newline at end of file diff --git a/std/haxe/Unserializer.hx b/std/haxe/Unserializer.hx index df4791b60ab7ef88b474bca7ab258cf293b3b210..9e189fe5e02f222ceb226861aa7723edb39fd51c 100644 --- a/std/haxe/Unserializer.hx +++ b/std/haxe/Unserializer.hx @@ -21,6 +21,7 @@ */ package haxe; +@:noDoc typedef TypeResolver = { function resolveClass( name : String ) : Class; function resolveEnum( name : String ) : Enum; @@ -31,10 +32,11 @@ typedef TypeResolver = { a serialization String and creates objects from the contained data. This class can be used in two ways: - - create a new Unserializer() instance with a given serialization + + - create a new Unserializer() instance with a given serialization String, then call its unserialize() method until all values are extracted - - call Unserializer.run() to unserialize a single value from a given + - call Unserializer.run() to unserialize a single value from a given String **/ class Unserializer { @@ -46,9 +48,10 @@ class Unserializer { default, the haxe Type Api is used. A type resolver must provide two methods: - resolveClass(name:String):Class is called to determine a + + 1. resolveClass(name:String):Class is called to determine a Class from a class name - resolveEnum(name:String):Enum is called to determine an + 2. resolveEnum(name:String):Enum is called to determine an Enum from an enum name This value is applied when a new Unserializer instance is created. @@ -63,7 +66,7 @@ class Unserializer { static function initCodes() { var codes = - #if flash9 + #if flash new flash.utils.ByteArray(); #else new Array(); @@ -86,10 +89,10 @@ class Unserializer { /** Creates a new Unserializer instance, with its internal buffer - initialized to [buf]. + initialized to `buf`. - This does not parse [buf] immediately. It is parsed only when calls to - [this].unserialize are made. + This does not parse `buf` immediately. It is parsed only when calls to + `this.unserialize` are made. Each Unserializer instance maintains its own cache. **/ @@ -111,9 +114,9 @@ class Unserializer { } /** - Sets the type resolver of [this] Unserializer instance to [r]. + Sets the type resolver of `this` Unserializer instance to `r`. - If [r] is null, a special resolver is used which returns null for all + If `r` is null, a special resolver is used which returns null for all input values. See DEFAULT_RESOLVER for more information on type resolvers. @@ -129,7 +132,7 @@ class Unserializer { } /** - Gets the type resolver of [this] Unserializer instance. + Gets the type resolver of `this` Unserializer instance. See DEFAULT_RESOLVER for more information on type resolvers. **/ @@ -166,6 +169,19 @@ class Unserializer { return k; } + function readFloat() { + var p1 = pos; + while( true ) { + var c = get(pos); + // + - . , 0-9 + if( (c >= 43 && c < 58) || c == "e".code || c == "E".code ) + pos++; + else + break; + } + return Std.parseFloat(buf.substr(p1,pos-p1)); + } + function unserializeObject(o) { while( true ) { if( pos >= length ) @@ -194,14 +210,14 @@ class Unserializer { } /** - Unserializes the next part of [this] Unserializer instance and returns + Unserializes the next part of `this` Unserializer instance and returns the according value. - This function may call [this].resolver.resolveClass to determine a - Class from a String, and [this].resolver.resolveEnum to determine an + This function may call `this.resolver.resolveClass` to determine a + Class from a String, and `this.resolver.resolveEnum` to determine an Enum from a String. - If [this] Unserializer instance contains no more or invalid data, an + If `this` Unserializer instance contains no more or invalid data, an exception is thrown. This operation may fail on structurally valid data if a type cannot be @@ -226,16 +242,7 @@ class Unserializer { case "i".code: return readDigits(); case "d".code: - var p1 = pos; - while( true ) { - var c = get(pos); - // + - . , 0-9 - if( (c >= 43 && c < 58) || c == "e".code || c == "E".code ) - pos++; - else - break; - } - return Std.parseFloat(buf.substr(p1,pos-p1)); + return readFloat(); case "y".code: var len = readDigits(); if( get(pos++) != ":".code || length - pos < len ) @@ -358,9 +365,19 @@ class Unserializer { pos++; return h; case "v".code: - var d = Date.fromString(buf.substr(pos,19)); + var d; + if( get(pos) >= '0'.code && get(pos) <= '9'.code && + get(pos + 1) >= '0'.code && get(pos + 1) <= '9'.code && + get(pos + 2) >= '0'.code && get(pos + 2) <= '9'.code && + get(pos + 3) >= '0'.code && get(pos + 3) <= '9'.code && + get(pos + 4) == '-'.code + ) { + // Included for backwards compatibility + d = Date.fromString(buf.substr(pos,19)); + pos += 19; + } else + d = Date.fromTime(readFloat()); cache.push(d); - pos += 19; return d; case "s".code: var len = readDigits(); @@ -414,6 +431,18 @@ class Unserializer { if( get(pos++) != "g".code ) throw "Invalid custom data"; return o; + case "A".code: + var name = unserialize(); + var cl = resolver.resolveClass(name); + if( cl == null ) + throw "Class not found " + name; + return cl; + case "B".code: + var name = unserialize(); + var e = resolver.resolveEnum(name); + if( e == null ) + throw "Enum not found " + name; + return e; default: } pos--; @@ -421,10 +450,10 @@ class Unserializer { } /** - Unserializes [v] and returns the according value. + Unserializes `v` and returns the according value. This is a convenience function for creating a new instance of - Unserializer with [v] as buffer and calling its unserialize() method + Unserializer with `v` as buffer and calling its unserialize() method once. **/ public static function run( v : String ) : Dynamic { diff --git a/std/haxe/Utf8.hx b/std/haxe/Utf8.hx index 91b5187f3d8f6a9eda4820aec448dfc695aa63f7..222c024641ea64713b4a364708fa1cf3eea9daf6 100644 --- a/std/haxe/Utf8.hx +++ b/std/haxe/Utf8.hx @@ -51,7 +51,7 @@ class Utf8 { } /** - Call the [chars] function for each UTF8 char of the string. + Call the `chars` function for each UTF8 char of the string. **/ public static function iter( s : String, chars : Int -> Void ) { for( i in 0...s.length ) @@ -63,7 +63,6 @@ class Utf8 { **/ public static function encode( s : String ) : String { throw "Not implemented"; - return s; } /** @@ -72,11 +71,10 @@ class Utf8 { **/ public static function decode( s : String ) : String { throw "Not implemented"; - return s; } /** - Similar to [String.charCodeAt] but uses the UTF8 character position. + Similar to `String.charCodeAt` but uses the UTF8 character position. **/ public static inline function charCodeAt( s : String, index : Int ) : Int { return s.charCodeAt(index); @@ -105,7 +103,7 @@ class Utf8 { } /** - This is similar to [String.substr] but the [pos] and [len] parts are considering UTF8 characters. + This is similar to `String.substr` but the `pos` and `len` parts are considering UTF8 characters. **/ public static inline function sub( s : String, pos : Int, len : Int ) : String { return s.substr(pos,len); diff --git a/std/haxe/crypto/Adler32.hx b/std/haxe/crypto/Adler32.hx index cf5247342f1dab5c085394643d1f42f6038ce4f0..4ce234ab633eea8a05435c55be608f9d049d88fe 100644 --- a/std/haxe/crypto/Adler32.hx +++ b/std/haxe/crypto/Adler32.hx @@ -1,70 +1,78 @@ -/* - * Copyright (C)2005-2012 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 Adler32 { - - var a1 : Int; - var a2 : Int; - - public function new() { - a1 = 1; - a2 = 0; - } - - public function get() { - return (a2 << 16) | a1; - } - - public function update( b : haxe.io.Bytes, pos, len ) { - var a1 = a1, a2 = a2; - for( p in pos...pos + len ) { - var c = b.get(p); - a1 = (a1 + c) % 65521; - a2 = (a2 + a1) % 65521; - } - this.a1 = a1; - this.a2 = a2; - } - - public function equals( a : Adler32 ) { - return a.a1 == a1 && a.a2 == a2; - } - - public static function read( i : haxe.io.Input ) { - var a = new Adler32(); - var a2a = i.readByte(); - var a2b = i.readByte(); - var a1a = i.readByte(); - var a1b = i.readByte(); - a.a1 = (a1a << 8) | a1b; - a.a2 = (a2a << 8) | a2b; - return a; - } - - public static function make( b : haxe.io.Bytes ) { - var a = new Adler32(); - a.update(b,0,b.length); - return a.get(); - } - -} +/* + * Copyright (C)2005-2012 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; + +/** + Calculates the Adler32 of the given Bytes. +*/ +class Adler32 { + + var a1 : Int; + var a2 : Int; + + public function new() { + a1 = 1; + a2 = 0; + } + + public function get() { + return (a2 << 16) | a1; + } + + public function update( b : haxe.io.Bytes, pos, len ) { + var a1 = a1, a2 = a2; + for( p in pos...pos + len ) { + var c = b.get(p); + a1 = (a1 + c) % 65521; + a2 = (a2 + a1) % 65521; + } + this.a1 = a1; + this.a2 = a2; + } + + public function equals( a : Adler32 ) { + return a.a1 == a1 && a.a2 == a2; + } + + public function toString() { + return StringTools.hex(a2,8) + StringTools.hex(a1,8); + } + + public static function read( i : haxe.io.Input ) { + var a = new Adler32(); + var a2a = i.readByte(); + var a2b = i.readByte(); + var a1a = i.readByte(); + var a1b = i.readByte(); + a.a1 = (a1a << 8) | a1b; + a.a2 = (a2a << 8) | a2b; + return a; + } + + public static function make( b : haxe.io.Bytes ) { + var a = new Adler32(); + a.update(b,0,b.length); + return a.get(); + } + + +} diff --git a/std/js/html/CSSFilterValue.hx b/std/haxe/crypto/Base64.hx similarity index 57% rename from std/js/html/CSSFilterValue.hx rename to std/haxe/crypto/Base64.hx index 4ba074981af3e256c2a43cc91c02a1e12c3a9ea3..765be3d21e29692d5f26c7f607b2eeed9eda2343 100644 --- a/std/js/html/CSSFilterValue.hx +++ b/std/haxe/crypto/Base64.hx @@ -19,37 +19,34 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - -// This file is generated, do not edit! -package js.html; - -@:native("CSSFilterValue") -extern class CSSFilterValue extends CSSValueList -{ - static inline var CSS_FILTER_BLUR : Int = 10; - - static inline var CSS_FILTER_BRIGHTNESS : Int = 8; - - static inline var CSS_FILTER_CONTRAST : Int = 9; - - static inline var CSS_FILTER_CUSTOM : Int = 12; - - static inline var CSS_FILTER_DROP_SHADOW : Int = 11; - - static inline var CSS_FILTER_GRAYSCALE : Int = 2; - - static inline var CSS_FILTER_HUE_ROTATE : Int = 5; - - static inline var CSS_FILTER_INVERT : Int = 6; - - static inline var CSS_FILTER_OPACITY : Int = 7; - - static inline var CSS_FILTER_REFERENCE : Int = 1; - - static inline var CSS_FILTER_SATURATE : Int = 4; - - static inline var CSS_FILTER_SEPIA : Int = 3; - - var operationType(default,null) : Int; +package haxe.crypto; + +/** + Allows to encode/decode String and bytes using Base64 encoding. +**/ +class Base64 { + + public static var CHARS(default,null) = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + public static var BYTES(default,null) = haxe.io.Bytes.ofString(CHARS); + + public static function encode( bytes : haxe.io.Bytes, complement = true ) : String { + var str = new BaseCode(BYTES).encodeBytes(bytes).toString(); + if( complement ) + switch (bytes.length % 3) { + case 1: + str += "=="; + case 2: + str += "="; + default: + } + return str; + } + + public static function decode( str : String, complement = true ) : haxe.io.Bytes { + if( complement ) + while( str.charCodeAt(str.length-1) == "=".code ) + str = str.substr(0,-1); + return new BaseCode(BYTES).decodeBytes(haxe.io.Bytes.ofString(str)); + } } diff --git a/std/haxe/crypto/BaseCode.hx b/std/haxe/crypto/BaseCode.hx index 11b2e935f90b166e5c9ec4c6e1b1ab2c7bf49d26..ebb8952da61c58d3e4df63354c2740547729db02 100644 --- a/std/haxe/crypto/BaseCode.hx +++ b/std/haxe/crypto/BaseCode.hx @@ -42,7 +42,7 @@ class BaseCode { } public function encodeBytes( b : haxe.io.Bytes ) : haxe.io.Bytes { - #if neko + #if (neko && !interp) return haxe.io.Bytes.ofData( base_encode(b.getData(),base.getData()) ); #else var nbits = this.nbits; @@ -79,7 +79,7 @@ class BaseCode { } public function decodeBytes( b : haxe.io.Bytes ) : haxe.io.Bytes { - #if neko + #if (neko && !interp) return haxe.io.Bytes.ofData( base_decode(b.getData(),base.getData()) ); #else var nbits = this.nbits; @@ -109,7 +109,7 @@ class BaseCode { } public function encodeString( s : String ) { - #if neko + #if (neko && !interp) return neko.NativeString.toString( base_encode(neko.NativeString.ofString(s),base.getData()) ); #else return encodeBytes(haxe.io.Bytes.ofString(s)).toString(); @@ -117,7 +117,7 @@ class BaseCode { } public function decodeString( s : String ) { - #if neko + #if (neko && !interp) return neko.NativeString.toString( base_decode(neko.NativeString.ofString(s),base.getData()) ); #else return decodeBytes(haxe.io.Bytes.ofString(s)).toString(); diff --git a/std/haxe/crypto/Crc32.hx b/std/haxe/crypto/Crc32.hx index 9018925153d6690d3af54cce2bce1585bb6810f0..bb4f11763780bed17ba7f890b023a1ebe0d4e93f 100644 --- a/std/haxe/crypto/Crc32.hx +++ b/std/haxe/crypto/Crc32.hx @@ -1,81 +1,84 @@ -/* - * Copyright (C)2005-2012 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 Crc32 { - - var crc : Int; - - public function new() { - crc = 0xFFFFFFFF; - } - - public function byte( b : Int ) { - var tmp = (crc ^ b) & 0xFF; - for( j in 0...8 ) { - if( tmp & 1 == 1 ) - tmp = (tmp >>> 1) ^ 0xEDB88320; - else - tmp >>>= 1; - } - crc = (crc >>> 8) ^ tmp; - } - - public function update( b : haxe.io.Bytes, pos, len ) { - var b = b.getData(); - for( i in pos...pos+len ) { - var tmp = (crc ^ haxe.io.Bytes.fastGet(b,i)) & 0xFF; - for( j in 0...8 ) { - if( tmp & 1 == 1 ) - tmp = (tmp >>> 1) ^ 0xEDB88320; - else - tmp >>>= 1; - } - crc = (crc >>> 8) ^ tmp; - } - } - - public function get() { - return crc ^ 0xFFFFFFFF; - } - - /** - Calculates the CRC32 of the given data bytes - **/ - public static function make( data : haxe.io.Bytes ) : Int { - var init = 0xFFFFFFFF; - var crc = init; - var b = data.getData(); - for( i in 0...data.length ) { - var tmp = (crc ^ haxe.io.Bytes.fastGet(b,i)) & 0xFF; - for( j in 0...8 ) { - if( tmp & 1 == 1 ) - tmp = (tmp >>> 1) ^ 0xEDB88320; - else - tmp >>>= 1; - } - crc = (crc >>> 8) ^ tmp; - } - return crc ^ init; - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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; + +/** + Calculates the Crc32 of the given Bytes. +*/ +class Crc32 { + + var crc : Int; + + public function new() { + crc = 0xFFFFFFFF; + } + + public function byte( b : Int ) { + var tmp = (crc ^ b) & 0xFF; + for( j in 0...8 ) { + if( tmp & 1 == 1 ) + tmp = (tmp >>> 1) ^ 0xEDB88320; + else + tmp >>>= 1; + } + crc = (crc >>> 8) ^ tmp; + } + + public function update( b : haxe.io.Bytes, pos, len ) { + var b = b.getData(); + for( i in pos...pos+len ) { + var tmp = (crc ^ haxe.io.Bytes.fastGet(b,i)) & 0xFF; + for( j in 0...8 ) { + if( tmp & 1 == 1 ) + tmp = (tmp >>> 1) ^ 0xEDB88320; + else + tmp >>>= 1; + } + crc = (crc >>> 8) ^ tmp; + } + } + + public function get() { + return crc ^ 0xFFFFFFFF; + } + + /** + Calculates the CRC32 of the given data bytes + **/ + public static function make( data : haxe.io.Bytes ) : Int { + var init = 0xFFFFFFFF; + var crc = init; + var b = data.getData(); + for( i in 0...data.length ) { + var tmp = (crc ^ haxe.io.Bytes.fastGet(b,i)) & 0xFF; + for( j in 0...8 ) { + if( tmp & 1 == 1 ) + tmp = (tmp >>> 1) ^ 0xEDB88320; + else + tmp >>>= 1; + } + crc = (crc >>> 8) ^ tmp; + } + return crc ^ init; + } + +} diff --git a/std/haxe/crypto/Hmac.hx b/std/haxe/crypto/Hmac.hx new file mode 100644 index 0000000000000000000000000000000000000000..da60d1917d3f357515b2630e216157a30509a2c7 --- /dev/null +++ b/std/haxe/crypto/Hmac.hx @@ -0,0 +1,91 @@ +/* + * Copyright (C)2005-2012 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; + +/** + Hash methods for Hmac calculation. +*/ +enum HashMethod { + MD5; + SHA1; + SHA256; +} + +/** + Calculates a Hmac of the given Bytes using a HashMethod. +*/ +class Hmac { + + var method : HashMethod; + var blockSize : Int; + var length : Int; + + public function new( hashMethod : HashMethod ) { + method = hashMethod; + blockSize = switch ( hashMethod ) { + case MD5, SHA1, SHA256: 64; + } + length = switch ( hashMethod ) { + case MD5: 16; + case SHA1: 20; + case SHA256: 32; + } + } + + inline function doHash( b : haxe.io.Bytes ) : haxe.io.Bytes { + return switch ( method ) { + case MD5: Md5.make(b); + case SHA1: Sha1.make(b); + case SHA256: Sha256.make(b); + } + } + + function nullPad( s : haxe.io.Bytes, chunkLen : Int ) : haxe.io.Bytes { + var r = chunkLen - (s.length % chunkLen); + if(r == chunkLen && s.length != 0) + return s; + var sb = new haxe.io.BytesBuffer(); + sb.add(s); + for(x in 0...r) + sb.addByte(0); + return sb.getBytes(); + } + + public function make( key : haxe.io.Bytes, msg : haxe.io.Bytes ) : haxe.io.Bytes { + if(key.length > blockSize) { + key = doHash(key); + } + key = nullPad(key, blockSize); + + var Ki = new haxe.io.BytesBuffer(); + var Ko = new haxe.io.BytesBuffer(); + for (i in 0...key.length) { + Ko.addByte(key.get(i) ^ 0x5c); + Ki.addByte(key.get(i) ^ 0x36); + } + // hash(Ko + hash(Ki + message)) + Ki.add(msg); + Ko.add(doHash(Ki.getBytes())); + return doHash(Ko.getBytes()); + } + +} diff --git a/std/haxe/crypto/Sha1.hx b/std/haxe/crypto/Sha1.hx index 5c6373ec05ed92c710a9a6ced1d8fea3191aa15b..9eb038ee2f94e46e333242353910843570b769a8 100644 --- a/std/haxe/crypto/Sha1.hx +++ b/std/haxe/crypto/Sha1.hx @@ -21,6 +21,9 @@ */ package haxe.crypto; +/** + Creates a Sha1 of a String. +*/ class Sha1 { public static function encode( s:String ) : String { @@ -167,15 +170,10 @@ class Sha1 { function hex( a : Array ){ var str = ""; - var hex_chr = "0123456789abcdef"; for( num in a ) { - var j = 7; - while( j >= 0 ) { - str += hex_chr.charAt( (num >>> (j<<2)) & 0xF ); - j--; - } + str += StringTools.hex(num, 8); } - return str; + return str.toLowerCase(); } #end diff --git a/std/haxe/crypto/Sha224.hx b/std/haxe/crypto/Sha224.hx new file mode 100644 index 0000000000000000000000000000000000000000..a3cd5aadfaba6d90551bca5baa5c3c56cdb5a890 --- /dev/null +++ b/std/haxe/crypto/Sha224.hx @@ -0,0 +1,201 @@ +/* + * Copyright (C)2005-2012 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; + +/** + Creates a Sha224 of a String. +*/ +class Sha224 { + + public static function encode( s:String ) : String { + #if php + return untyped __call__("hash", "sha224", s); + #else + var sh = new Sha224(); + var h = sh.doEncode(s, s.length*8); + return sh.hex(h); + #end + } + + public static function make( b : haxe.io.Bytes ) : haxe.io.Bytes { + #if php + return haxe.io.Bytes.ofData(untyped __call__("hash", "sha224", b.getData(), true)); + #else + var h = new Sha224().doEncode(b.toString(), b.length*8); + var out = haxe.io.Bytes.alloc(28); + var p = 0; + for( i in 0...8 ) { + out.set(p++,h[i]>>>24); + out.set(p++,(h[i]>>16)&0xFF); + out.set(p++,(h[i]>>8)&0xFF); + out.set(p++,h[i]&0xFF); + } + return out; + #end + } + + public function new() { + } + + function doEncode( str : String, strlen : Int ) : Array { + var K : Array = [ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0xFC19DC6 , 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x6CA6351 , 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 + ]; + var HASH : Array = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]; + var W = new Array(); + W[64] = 0; + + var a:Int,b:Int,c:Int,d:Int,e:Int,f:Int,g:Int,h:Int,i:Int,j:Int; + var T1, T2; + var i : Int = 0; + var blocks : Array = str2blks(str); + blocks[strlen >> 5] |= 0x80 << (24 - strlen % 32); + blocks[((strlen + 64 >> 9) << 4) + 15] = strlen; + + while ( i < blocks.length ) { + a = HASH[0]; + b = HASH[1]; + c = HASH[2]; + d = HASH[3]; + e = HASH[4]; + f = HASH[5]; + g = HASH[6]; + h = HASH[7]; + + for ( j in 0...64 ) { + if (j < 16) { + W[j] = blocks[j + i]; + } else { + W[j] = safeAdd(safeAdd(safeAdd(Gamma1(W[j - 2]), W[j - 7]), Gamma0(W[j - 15])), W[j - 16]); + } + + T1 = safeAdd(safeAdd(safeAdd(safeAdd(h, Sigma1(e)), Ch(e, f, g)), K[j]), W[j]); + T2 = safeAdd(Sigma0(a), Maj(a, b, c)); + + h = g; + g = f; + f = e; + e = safeAdd(d, T1); + d = c; + c = b; + b = a; + a = safeAdd(T1, T2); + } + + HASH[0] = safeAdd(a, HASH[0]); + HASH[1] = safeAdd(b, HASH[1]); + HASH[2] = safeAdd(c, HASH[2]); + HASH[3] = safeAdd(d, HASH[3]); + HASH[4] = safeAdd(e, HASH[4]); + HASH[5] = safeAdd(f, HASH[5]); + HASH[6] = safeAdd(g, HASH[6]); + HASH[7] = safeAdd(h, HASH[7]); + i += 16; + } + return HASH; + } + + static function str2blks( s :String ) : Array { + var nblk = ((s.length + 8) >> 6) + 1; + var blks = new Array(); + for (i in 0...nblk*16) + blks[i] = 0; + for (i in 0...s.length){ + var p = i >> 2; + blks[p] |= s.charCodeAt(i) << (24 - ((i & 3) << 3)); + } + var i = s.length; + var p = i >> 2; + blks[p] |= 0x80 << (24 - ((i & 3) << 3)); + blks[nblk * 16 - 1] = s.length * 8; + return blks; + } + + static function safeAdd(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16); + return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF); + } + + // ++ + function ROTR(X, n) { + return ( X >>> n ) | (X << (32 - n)); + } + + // ++ + function SHR(X, n) { + return ( X >>> n ); + } + + // ++ + function Ch(x, y, z) { + return ((x & y) ^ ((~x) & z)); + } + + // ++ + function Maj(x, y, z) { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + function Sigma0(x) { + return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22); + } + + function Sigma1(x) { + return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25); + } + + function Gamma0(x) { + return ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3); + } + + function Gamma1(x) { + return ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10); + } + + function hex( a : Array ){ + var str = ""; + for( num in a ) { + str += StringTools.hex(num, 8); + } + return str.substring(0, 56).toLowerCase(); + } + +} diff --git a/std/haxe/crypto/Sha256.hx b/std/haxe/crypto/Sha256.hx new file mode 100644 index 0000000000000000000000000000000000000000..2a08b38646a1e5a548c0cf73f13d2a440f96da93 --- /dev/null +++ b/std/haxe/crypto/Sha256.hx @@ -0,0 +1,195 @@ +/* + * Copyright (C)2005-2012 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; + +/** + Creates a Sha256 of a String. +*/ +class Sha256 { + + public static function encode( s:String ) : String { + #if php + return untyped __call__("hash", "sha256", s); + #else + var sh = new Sha256(); + var h = sh.doEncode(str2blks(s), s.length*8); + return sh.hex(h); + #end + } + + public static function make( b : haxe.io.Bytes ) : haxe.io.Bytes { + #if php + return haxe.io.Bytes.ofData(untyped __call__("hash", "sha256", b.getData(), true)); + #else + var h = new Sha256().doEncode(bytes2blks(b), b.length*8); + var out = haxe.io.Bytes.alloc(32); + var p = 0; + for( i in 0...8 ) { + out.set(p++,h[i]>>>24); + out.set(p++,(h[i]>>16)&0xFF); + out.set(p++,(h[i]>>8)&0xFF); + out.set(p++,h[i]&0xFF); + } + return out; + #end + } + + public function new() { + } + + function doEncode( m : Array, l : Int ) : Array { + var K : Array = [ + 0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B, + 0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01, + 0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7, + 0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC, + 0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152, + 0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147, + 0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC, + 0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85, + 0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819, + 0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08, + 0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F, + 0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208, + 0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2 + ]; + var HASH : Array = [ + 0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A, + 0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19 + ]; + + var W = new Array(); + W[64] = 0; + var a:Int,b:Int,c:Int,d:Int,e:Int,f:Int,g:Int,h:Int; + var T1, T2; + m[l >> 5] |= 0x80 << (24 - l % 32); + m[((l + 64 >> 9) << 4) + 15] = l; + var i : Int = 0; + while ( i < m.length ) { + a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7]; + for ( j in 0...64 ) { + if (j < 16) + W[j] = m[j + i]; + else + W[j] = safeAdd(safeAdd(safeAdd(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]); + T1 = safeAdd(safeAdd(safeAdd(safeAdd(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]); + T2 = safeAdd(Sigma0256(a), Maj(a, b, c)); + h = g; g = f; f = e; e = safeAdd(d, T1); d = c; c = b; b = a; a = safeAdd(T1, T2); + } + HASH[0] = safeAdd(a, HASH[0]); + HASH[1] = safeAdd(b, HASH[1]); + HASH[2] = safeAdd(c, HASH[2]); + HASH[3] = safeAdd(d, HASH[3]); + HASH[4] = safeAdd(e, HASH[4]); + HASH[5] = safeAdd(f, HASH[5]); + HASH[6] = safeAdd(g, HASH[6]); + HASH[7] = safeAdd(h, HASH[7]); + i += 16; + } + return HASH; + } + + /* + Convert a string to a sequence of 16-word blocks, stored as an array. + Append padding bits and the length, as described in the SHA1 standard. + */ + static function str2blks( s :String ) : Array { + var nblk = ((s.length + 8) >> 6) + 1; + var blks = new Array(); + + for (i in 0...nblk*16) + blks[i] = 0; + for (i in 0...s.length){ + var p = i >> 2; + blks[p] |= s.charCodeAt(i) << (24 - ((i & 3) << 3)); + } + var i = s.length; + var p = i >> 2; + blks[p] |= 0x80 << (24 - ((i & 3) << 3)); + blks[nblk * 16 - 1] = s.length * 8; + return blks; + } + + static function bytes2blks( b : haxe.io.Bytes ) : Array { + var nblk = ((b.length + 8) >> 6) + 1; + var blks = new Array(); + + for (i in 0...nblk*16) + blks[i] = 0; + for (i in 0...b.length){ + var p = i >> 2; + blks[p] |= b.get(i) << (24 - ((i & 3) << 3)); + } + var i = b.length; + var p = i >> 2; + blks[p] |= 0x80 << (24 - ((i & 3) << 3)); + blks[nblk * 16 - 1] = b.length * 8; + return blks; + } + + function S(X, n) { + return ( X >>> n ) | (X << (32 - n)); + } + + function R(X, n) { + return ( X >>> n ); + } + + function Ch(x, y, z) { + return ((x & y) ^ ((~x) & z)); + } + + function Maj(x, y, z) { + return ((x & y) ^ (x & z) ^ (y & z)); + } + + function Sigma0256(x) { + return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); + } + + function Sigma1256(x) { + return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); + } + + function Gamma0256(x) { + return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); + } + + function Gamma1256(x) { + return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); + } + + function safeAdd(x, y) { + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); + } + + function hex( a : Array ){ + var str = ""; + for( num in a ) { + str += StringTools.hex(num, 8); + } + return str.toLowerCase(); + } + +} diff --git a/std/haxe/ds/ArraySort.hx b/std/haxe/ds/ArraySort.hx index bb41015e80896165d48a7d0e8215825d56938d7e..4f826e5af892a15bdbf007e86c3780f093cb716a 100644 --- a/std/haxe/ds/ArraySort.hx +++ b/std/haxe/ds/ArraySort.hx @@ -1,158 +1,159 @@ -/* - * Copyright (C)2005-2012 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; - -/** - ArraySort provides a stable implementation of merge sort through its sort() - method. It should be used instead of Array.sort() in cases where the order - of equal elements has to be retained on all targets. -**/ -class ArraySort { - /** - Sorts Array [a] according to the comparison function [cmp], where - [cmp(x,y)] returns 0 if x == y, a positive Int if x > y and a - negative Int if x < y. - - This operation modifies Array [a] in place. - - This operation is stable: The order of equal elements is preserved. - - If [a] or [cmp] are null, the result is unspecified. - **/ - static public function sort(a:Array, cmp:T -> T -> Int) { - rec(a, cmp, 0, a.length); - } - - static function rec(a:Array, cmp, from, to) { - var middle = (from + to) >> 1; - if (to - from < 12) { - if (to <= from) return; - for (i in (from + 1)...to) { - var j = i; - while (j > from) { - if (compare(a, cmp, j, j - 1) < 0) - swap(a, j - 1, j); - else - break; - j--; - } - } - return; - } - rec(a, cmp, from, middle); - rec(a, cmp, middle, to); - doMerge(a, cmp, from, middle, to, middle - from, to - middle); - } - - static function doMerge(a:Array, cmp, from, pivot, to, len1, len2) { - var first_cut, second_cut, len11, len22, new_mid; - if (len1 == 0 || len2 == 0) - return; - if (len1 + len2 == 2) { - if (compare(a, cmp, pivot, from) < 0) - swap(a, pivot, from); - return; - } - if (len1 > len2) { - len11 = len1 >> 1; - first_cut = from + len11; - second_cut = lower(a, cmp, pivot, to, first_cut); - len22 = second_cut - pivot; - } else { - len22 = len2 >> 1; - second_cut = pivot + len22; - first_cut = upper(a, cmp, from, pivot, second_cut); - len11 = first_cut - from; - } - rotate(a, cmp, first_cut, pivot, second_cut); - new_mid = first_cut + len22; - doMerge(a, cmp, from, first_cut, new_mid, len11, len22); - doMerge(a, cmp, new_mid, second_cut, to, len1 - len11, len2 - len22); - } - - static function rotate(a:Array, cmp, from, mid, to) { - var n; - if (from == mid || mid == to) return; - n = gcd(to - from, mid - from); - while (n-- != 0) { - var val = a[from + n]; - var shift = mid - from; - var p1 = from + n, p2 = from + n + shift; - while (p2 != from + n) { - a[p1] = a[p2]; - p1 = p2; - if (to - p2 > shift) p2 += shift; - else p2 = from + (shift - (to - p2)); - } - a[p1] = val; - } - } - - static function gcd(m, n) { - while (n != 0) { - var t = m % n; - m = n; - n = t; - } - return m; - } - - static function upper(a:Array, cmp, from, to, val) { - var len = to - from, half, mid; - while (len > 0) { - half = len >> 1; - mid = from + half; - if (compare(a, cmp, val, mid) < 0) - len = half; - else { - from = mid + 1; - len = len - half - 1; - } - } - return from; - } - - static function lower(a:Array, cmp, from, to, val) { - var len = to - from, half, mid; - while (len > 0) { - half = len >> 1; - mid = from + half; - if (compare(a, cmp, mid, val) < 0) { - from = mid + 1; - len = len - half - 1; - } else - len = half; - } - return from; - } - - static function swap(a:Array, i, j) { - var tmp = a[i]; - a[i] = a[j]; - a[j] = tmp; - } - - static inline function compare(a:Array, cmp, i, j) { - return cmp(a[i], a[j]); - } +/* + * Copyright (C)2005-2012 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; + +/** + ArraySort provides a stable implementation of merge sort through its `sort` + method. It should be used instead of `Array.sort` in cases where the order + of equal elements has to be retained on all targets. +**/ +class ArraySort { + + /** + Sorts Array `a` according to the comparison function `cmp`, where + `cmp(x,y)` returns 0 if `x == y`, a positive Int if `x > y` and a + negative Int if `x < y`. + + This operation modifies Array `a` in place. + + This operation is stable: The order of equal elements is preserved. + + If `a` or `cmp` are null, the result is unspecified. + **/ + static public function sort(a:Array, cmp:T -> T -> Int) { + rec(a, cmp, 0, a.length); + } + + static function rec(a:Array, cmp, from, to) { + var middle = (from + to) >> 1; + if (to - from < 12) { + if (to <= from) return; + for (i in (from + 1)...to) { + var j = i; + while (j > from) { + if (compare(a, cmp, j, j - 1) < 0) + swap(a, j - 1, j); + else + break; + j--; + } + } + return; + } + rec(a, cmp, from, middle); + rec(a, cmp, middle, to); + doMerge(a, cmp, from, middle, to, middle - from, to - middle); + } + + static function doMerge(a:Array, cmp, from, pivot, to, len1, len2) { + var first_cut, second_cut, len11, len22, new_mid; + if (len1 == 0 || len2 == 0) + return; + if (len1 + len2 == 2) { + if (compare(a, cmp, pivot, from) < 0) + swap(a, pivot, from); + return; + } + if (len1 > len2) { + len11 = len1 >> 1; + first_cut = from + len11; + second_cut = lower(a, cmp, pivot, to, first_cut); + len22 = second_cut - pivot; + } else { + len22 = len2 >> 1; + second_cut = pivot + len22; + first_cut = upper(a, cmp, from, pivot, second_cut); + len11 = first_cut - from; + } + rotate(a, cmp, first_cut, pivot, second_cut); + new_mid = first_cut + len22; + doMerge(a, cmp, from, first_cut, new_mid, len11, len22); + doMerge(a, cmp, new_mid, second_cut, to, len1 - len11, len2 - len22); + } + + static function rotate(a:Array, cmp, from, mid, to) { + var n; + if (from == mid || mid == to) return; + n = gcd(to - from, mid - from); + while (n-- != 0) { + var val = a[from + n]; + var shift = mid - from; + var p1 = from + n, p2 = from + n + shift; + while (p2 != from + n) { + a[p1] = a[p2]; + p1 = p2; + if (to - p2 > shift) p2 += shift; + else p2 = from + (shift - (to - p2)); + } + a[p1] = val; + } + } + + static function gcd(m, n) { + while (n != 0) { + var t = m % n; + m = n; + n = t; + } + return m; + } + + static function upper(a:Array, cmp, from, to, val) { + var len = to - from, half, mid; + while (len > 0) { + half = len >> 1; + mid = from + half; + if (compare(a, cmp, val, mid) < 0) + len = half; + else { + from = mid + 1; + len = len - half - 1; + } + } + return from; + } + + static function lower(a:Array, cmp, from, to, val) { + var len = to - from, half, mid; + while (len > 0) { + half = len >> 1; + mid = from + half; + if (compare(a, cmp, mid, val) < 0) { + from = mid + 1; + len = len - half - 1; + } else + len = half; + } + return from; + } + + static function swap(a:Array, i, j) { + var tmp = a[i]; + a[i] = a[j]; + a[j] = tmp; + } + + static inline function compare(a:Array, cmp, i, j) { + return cmp(a[i], a[j]); + } } \ No newline at end of file diff --git a/std/haxe/ds/BalancedTree.hx b/std/haxe/ds/BalancedTree.hx index 4ff5aaf030e630450df0c65fd31ee08e860c16af..199ec3641e4f8296c8e510689b82279b61716da8 100644 --- a/std/haxe/ds/BalancedTree.hx +++ b/std/haxe/ds/BalancedTree.hx @@ -1,182 +1,236 @@ -/* - * Copyright (C)2005-2013 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; - -class BalancedTree { - var root:TreeNode; - - public function new() { } - - public function set(k:K, v:V) { - root = setLoop(k, v, root); - } - - public function get(k:K):Null { - var node = root; - while (node != null) { - var c = compare(k, node.key); - if (c == 0) return node.value; - if (c < 0) node = node.left; - else node = node.right; - } - return null; - } - - public function remove(k:K) { - try { - root = removeLoop(k, root); - return true; - } - catch (e:String) { - return false; - } - } - - public function exists(k:K) { - var node = root; - while (node != null) { - var c = compare(k, node.key); - if (c == 0) return true; - else if (c < 0) node = node.left; - else node = node.right; - } - return false; - } - - public function iterator():Iterator { - var ret = []; - iteratorLoop(root, ret); - return ret.iterator(); - } - - public function keys():Iterator { - var ret = []; - keysLoop(root, ret); - return ret.iterator(); - } - - function setLoop(k:K, v:V, node:TreeNode) { - if (node == null) return new TreeNode(null, k, v, null); - var c = compare(k, node.key); - return if (c == 0) new TreeNode(node.left, k, v, node.right, node.get_height()); - else if (c < 0) { - var nl = setLoop(k, v, node.left); - balance(nl, node.key, node.value, node.right); - } else { - var nr = setLoop(k, v, node.right); - balance(node.left, node.key, node.value, nr); - } - } - - function removeLoop(k:K, node:TreeNode) { - if (node == null) throw "Not_found"; - var c = compare(k, node.key); - return if (c == 0) merge(node.left, node.right); - else if (c < 0) balance(removeLoop(k, node.left), node.key, node.value, node.right); - else balance(node.left, node.key, node.value, removeLoop(k, node.right)); - } - - function iteratorLoop(node:TreeNode, acc:Array) { - if (node != null) { - acc.push(node.value); - iteratorLoop(node.left, acc); - iteratorLoop(node.right, acc); - } - } - - function keysLoop(node:TreeNode, acc:Array) { - if (node != null) { - acc.push(node.key); - keysLoop(node.left, acc); - keysLoop(node.right, acc); - } - } - - function merge(t1, t2) { - if (t1 == null) return t2; - if (t2 == null) return t1; - var t = minBinding(t2); - return balance(t1, t.key, t.value, removeMinBinding(t2)); - } - - function minBinding(t:TreeNode) { - return if (t == null) throw "Not_found"; - else if (t.left == null) t; - else minBinding(t.left); - } - - function removeMinBinding(t:TreeNode) { - return if (t.left == null) t.right; - else balance(removeMinBinding(t.left), t.key, t.value, t.right); - } - - function balance(l:TreeNode, k:K, v:V, r:TreeNode):TreeNode { - var hl = l.get_height(); - var hr = r.get_height(); - return if (hl > hr + 2) { - if (l.left.get_height() >= l.right.get_height()) new TreeNode(l.left, l.key, l.value, new TreeNode(l.right, k, v, r)); - else new TreeNode(new TreeNode(l.left,l.key, l.value, l.right.left), l.right.key, l.right.value, new TreeNode(l.right.right, k, v, r)); - } else if (hr > hl + 2) { - if (r.right.get_height() > r.left.get_height()) new TreeNode(new TreeNode(l, k, v, r.left), r.key, r.value, r.right); - else new TreeNode(new TreeNode(l, k, v, r.left.left), r.left.key, r.left.value, new TreeNode(r.left.right, r.key, r.value, r.right)); - } else { - new TreeNode(l, k, v, r, (hl > hr ? hl : hr) + 1); - } - } - - function compare(k1:K, k2:K) { - return Reflect.compare(k1, k2); - } - - public function toString() { - return '{${root.toString()}}'; - } -} - -class TreeNode { - public var left : TreeNode; - public var right : 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) { - left = l; - key = k; - value = v; - right = r; - if (h == -1) - _height = (left.get_height() > right.get_height() ? left.get_height() : right.get_height()) + 1; - else - _height = h; - } - - @:extern public inline function get_height() return this == null ? 0 : _height; - - public function toString() { - return (left == null ? "" : left.toString() + ", ") + '$key=$value' + (right == null ? "" : ", " +right.toString()); - } +/* + * Copyright (C)2005-2013 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; + +/** + BalancedTree allows key-value mapping with arbitrary keys, as long as they + can be ordered. By default, `Reflect.compare` is used in the `compare` + method, which can be overridden in subclasses. + + Operations have a logarithmic average and worst-case cost. + + Iteration over keys and values, using `keys` and `iterator` respectively, + are in-order. +**/ +class BalancedTree { + var root:TreeNode; + + /** + Creates a new BalancedTree, which is initially empty. + **/ + public function new() { } + + /** + Binds `key` to `value`. + + If `key` is already bound to a value, that binding disappears. + + If `key` is null, the result is unspecified. + **/ + public function set(key:K, value:V) { + root = setLoop(key, value, root); + } + + /** + Returns the value `key` is bound to. + + If `key` is not bound to any value, `null` is returned. + + If `key` is null, the result is unspecified. + **/ + public function get(key:K):Null { + var node = root; + while (node != null) { + var c = compare(key, node.key); + if (c == 0) return node.value; + if (c < 0) node = node.left; + else node = node.right; + } + return null; + } + + /** + Removes the current binding of `key`. + + If `key` has no binding, `this` BalancedTree is unchanged and false is + returned. + + Otherwise the binding of `key` is removed and true is returned. + + If `key` is null, the result is unspecified. + **/ + public function remove(key:K) { + try { + root = removeLoop(key, root); + return true; + } + catch (e:String) { + return false; + } + } + + /** + Tells if `key` is bound to a value. + + This method returns true even if `key` is bound to null. + + If `key` is null, the result is unspecified. + **/ + public function exists(key:K) { + var node = root; + while (node != null) { + var c = compare(key, node.key); + if (c == 0) return true; + else if (c < 0) node = node.left; + else node = node.right; + } + return false; + } + + /** + Iterates over the bound values of `this` BalancedTree. + + This operation is performed in-order. + **/ + public function iterator():Iterator { + var ret = []; + iteratorLoop(root, ret); + return ret.iterator(); + } + + /** + Iterates over the keys of `this` BalancedTree. + + This operation is performed in-order. + **/ + public function keys():Iterator { + var ret = []; + keysLoop(root, ret); + return ret.iterator(); + } + + function setLoop(k:K, v:V, node:TreeNode) { + if (node == null) return new TreeNode(null, k, v, null); + var c = compare(k, node.key); + return if (c == 0) new TreeNode(node.left, k, v, node.right, node.get_height()); + else if (c < 0) { + var nl = setLoop(k, v, node.left); + balance(nl, node.key, node.value, node.right); + } else { + var nr = setLoop(k, v, node.right); + balance(node.left, node.key, node.value, nr); + } + } + + function removeLoop(k:K, node:TreeNode) { + if (node == null) throw "Not_found"; + var c = compare(k, node.key); + return if (c == 0) merge(node.left, node.right); + else if (c < 0) balance(removeLoop(k, node.left), node.key, node.value, node.right); + else balance(node.left, node.key, node.value, removeLoop(k, node.right)); + } + + function iteratorLoop(node:TreeNode, acc:Array) { + if (node != null) { + iteratorLoop(node.left, acc); + acc.push(node.value); + iteratorLoop(node.right, acc); + } + } + + function keysLoop(node:TreeNode, acc:Array) { + if (node != null) { + keysLoop(node.left, acc); + acc.push(node.key); + keysLoop(node.right, acc); + } + } + + function merge(t1, t2) { + if (t1 == null) return t2; + if (t2 == null) return t1; + var t = minBinding(t2); + return balance(t1, t.key, t.value, removeMinBinding(t2)); + } + + function minBinding(t:TreeNode) { + return if (t == null) throw "Not_found"; + else if (t.left == null) t; + else minBinding(t.left); + } + + function removeMinBinding(t:TreeNode) { + return if (t.left == null) t.right; + else balance(removeMinBinding(t.left), t.key, t.value, t.right); + } + + function balance(l:TreeNode, k:K, v:V, r:TreeNode):TreeNode { + var hl = l.get_height(); + var hr = r.get_height(); + return if (hl > hr + 2) { + if (l.left.get_height() >= l.right.get_height()) new TreeNode(l.left, l.key, l.value, new TreeNode(l.right, k, v, r)); + else new TreeNode(new TreeNode(l.left,l.key, l.value, l.right.left), l.right.key, l.right.value, new TreeNode(l.right.right, k, v, r)); + } else if (hr > hl + 2) { + if (r.right.get_height() > r.left.get_height()) new TreeNode(new TreeNode(l, k, v, r.left), r.key, r.value, r.right); + else new TreeNode(new TreeNode(l, k, v, r.left.left), r.left.key, r.left.value, new TreeNode(r.left.right, r.key, r.value, r.right)); + } else { + new TreeNode(l, k, v, r, (hl > hr ? hl : hr) + 1); + } + } + + function compare(k1:K, k2:K) { + return Reflect.compare(k1, k2); + } + + public function toString() { + return root == null ? '{}' : '{${root.toString()}}'; + } +} + +class TreeNode { + public var left : TreeNode; + public var right : 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) { + left = l; + key = k; + value = v; + right = r; + if (h == -1) + _height = (left.get_height() > right.get_height() ? left.get_height() : right.get_height()) + 1; + else + _height = h; + } + + @:extern public inline function get_height() return this == null ? 0 : _height; + + public function toString() { + return (left == null ? "" : left.toString() + ", ") + '$key=$value' + (right == null ? "" : ", " +right.toString()); + } } \ No newline at end of file diff --git a/std/haxe/ds/Either.hx b/std/haxe/ds/Either.hx new file mode 100644 index 0000000000000000000000000000000000000000..ca18894aad0617cb15d621c1ac659779bbe12256 --- /dev/null +++ b/std/haxe/ds/Either.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2014 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; + +/** + Either represents values which are either of type `L` (Left) or type `R` + (Right). +**/ +enum Either { + Left(v:L); + Right(v:R); +} \ No newline at end of file diff --git a/std/haxe/ds/EnumValueMap.hx b/std/haxe/ds/EnumValueMap.hx index 30b59b8358886f193f399a4d74069facc5fe9bdf..53d4416e4602df9b5281917b6ff2b2c8c9d2ceb4 100644 --- a/std/haxe/ds/EnumValueMap.hx +++ b/std/haxe/ds/EnumValueMap.hx @@ -1,47 +1,61 @@ -/* - * Copyright (C)2005-2013 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; - -class EnumValueMap extends haxe.ds.BalancedTree implements Map.IMap { - - override function compare(k1:EnumValue, k2:EnumValue) { - var d = k1.getIndex() - k2.getIndex(); - if (d != 0) return d; - var p1 = k1.getParameters(); - var p2 = k2.getParameters(); - if (p1.length == 0 && p2.length == 0) return 0; - return compareArgs(p1, p2); - } - - function compareArgs(a1:Array, a2:Array) { - var ld = a1.length - a2.length; - if (ld != 0) return ld; - for (i in 0...a1.length) { - var v1:Dynamic = a1[i], v2:Dynamic = a2[i]; - var d = if (Reflect.isEnumValue(v1) && Reflect.isEnumValue(v2)) compare(v1, v2); - else Reflect.compare(v1, v2); - if (d != 0) return d; - } - return 0; - } +/* + * Copyright (C)2005-2013 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; + +/** + EnumValueMap allows mapping of enum value keys to arbitrary values. + + Keys are compared by value and recursively over their parameters. If any + parameter is not an enum value, `Reflect.compare` is used to compare them. +**/ +class EnumValueMap extends haxe.ds.BalancedTree implements haxe.Constraints.IMap { + + override function compare(k1:EnumValue, k2:EnumValue):Int { + var d = k1.getIndex() - k2.getIndex(); + if (d != 0) return d; + var p1 = k1.getParameters(); + var p2 = k2.getParameters(); + if (p1.length == 0 && p2.length == 0) return 0; + return compareArgs(p1, p2); + } + + function compareArgs(a1:Array, a2:Array):Int { + var ld = a1.length - a2.length; + if (ld != 0) return ld; + for (i in 0...a1.length) { + var d = compareArg(a1[i], a2[i]); + if (d != 0) return d; + } + return 0; + } + + 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)) { + compareArgs(v1, v2); + } else { + Reflect.compare(v1, v2); + } + } } \ No newline at end of file diff --git a/std/haxe/ds/GenericStack.hx b/std/haxe/ds/GenericStack.hx index bb94ef5b1acdfcf7f883f260cad00991fc8d6a1e..a165a98855318ba756c0a8fef1c3928b9b417aaf 100644 --- a/std/haxe/ds/GenericStack.hx +++ b/std/haxe/ds/GenericStack.hx @@ -21,7 +21,7 @@ */ package haxe.ds; -#if (flash9 || cpp) +#if (flash || cpp) @:generic #end class GenericCell { @@ -43,9 +43,18 @@ private class GenericStackIterator extends cpp.FastIterator { #end /** - A linked-list of elements. A different class is created for each container used in platforms where it matters + A stack of elements. + + This class is generic, which means one type is generated for each type + parameter T on static targets. For example: + + - `new GenericStack()` generates `GenericStack_Int` + - `new GenericStack()` generates `GenericStack_String` + + The generated name is an implementation detail and should not be relied + upon. **/ -#if (flash9 || cpp) +#if (flash || cpp) @:generic #end class GenericStack { @@ -53,30 +62,31 @@ class GenericStack { public var head : GenericCell; /** - Creates a new empty list. + Creates a new empty GenericStack. **/ public function new() { } /** - Add an element at the head of the list. + Pushes element `item` onto the stack. **/ public inline function add( item : T ) { head = new GenericCell(item,head); } /** - Returns the first element of the list, or null - if the list is empty. + Returns the topmost stack element without removing it. + + If the stack is empty, null is returned. **/ public inline function first() : Null { return if( head == null ) null else head.elt; } /** - Removes the first element of the list and - returns it or simply returns null if the - list is empty. + Returns the topmost stack element and removes it. + + If the stack is empty, null is returned. **/ public inline function pop() : Null { var k = head; @@ -89,18 +99,23 @@ class GenericStack { } /** - Tells if a list is empty. + Tells if the stack is empty. **/ public inline function isEmpty() : Bool { return (head == null); } /** - Remove the first element that is [== v] from the list. - Returns [true] if an element was removed, [false] otherwise. + Removes the first element which is equal to `v` according to the `==` + operator. + + This method traverses the stack until it finds a matching element and + unlinks it, returning true. + + If no matching element is found, false is returned. **/ public function remove( v : T ) : Bool { - var prev = null; + var prev:GenericCell = null; var l = head; while( l != null ) { if( l.elt == v ) { @@ -119,7 +134,7 @@ class GenericStack { #if cpp /** - Returns an iterator on the elements of the list. + Returns an iterator over the elements of `this` GenericStack. **/ public function iterator() : Iterator { return new GenericStackIterator(head); @@ -128,7 +143,7 @@ class GenericStack { #else /** - Returns an iterator on the elements of the list. + Returns an iterator over the elements of `this` GenericStack. **/ public function iterator() : Iterator { var l = head; @@ -146,7 +161,7 @@ class GenericStack { #end /** - Returns a displayable representation of the String. + Returns a String representation of `this` GenericStack. **/ public function toString() { var a = new Array(); diff --git a/std/haxe/ds/HashMap.hx b/std/haxe/ds/HashMap.hx index cdc88805f612239180fe59938fe74028365136fb..616e7a8f4e45aeef98807cf0036b2aa3c6e2c576 100644 --- a/std/haxe/ds/HashMap.hx +++ b/std/haxe/ds/HashMap.hx @@ -1,48 +1,57 @@ -/* - * Copyright (C)2005-2013 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; - -abstract HashMap({keys:IntMap, values:IntMap}) { - public function new() { - this = { keys:new IntMap(), values: new IntMap() }; - } - public inline function set(k:K, v:V) { - this.keys.set(k.hashCode(), k); - this.values.set(k.hashCode(), v); - } - public inline function get(k:K) { - return this.values.get(k.hashCode()); - } - public inline function exists(k:K) { - return this.values.exists(k.hashCode()); - } - public inline function remove(k:K) { - this.values.remove(k.hashCode()); - return this.keys.remove(k.hashCode()); - } - public inline function keys() { - return this.keys.iterator(); - } - public inline function iterator() { - return this.values.iterator(); - } +/* + * Copyright (C)2005-2013 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; + +abstract HashMap(HashMapData) { + public inline function new() { + this = new HashMapData(); + } + public inline function set(k:K, v:V) { + this.keys.set(k.hashCode(), k); + this.values.set(k.hashCode(), v); + } + public inline function get(k:K) { + return this.values.get(k.hashCode()); + } + public inline function exists(k:K) { + return this.values.exists(k.hashCode()); + } + public inline function remove(k:K) { + this.values.remove(k.hashCode()); + return this.keys.remove(k.hashCode()); + } + public inline function keys() { + return this.keys.iterator(); + } + public inline function iterator() { + return this.values.iterator(); + } +} + +private class HashMapData { + public var keys:IntMap; + public var values:IntMap; + public inline function new() { + keys = new IntMap(); + values = new IntMap(); + } } \ No newline at end of file diff --git a/std/haxe/ds/IntMap.hx b/std/haxe/ds/IntMap.hx index 21dfac2fcaf7d0190b0be69c7cfa9fce3189db7b..3f9e8bc72e7419087d8e35a0ff63908e9e45f523 100644 --- a/std/haxe/ds/IntMap.hx +++ b/std/haxe/ds/IntMap.hx @@ -22,50 +22,49 @@ package haxe.ds; /** - Hashtable over a set of elements, using [Int] as keys. - On Flash and Javascript, the underlying structure is an Object. + IntMap allows mapping of Int keys to arbitrary values. + + See `Map` for documentation details. **/ -extern class IntMap implements Map.IMap { +extern class IntMap implements haxe.Constraints.IMap { /** - Creates a new empty hashtable. + Creates a new IntMap. **/ public function new() : Void; /** - Set a value for the given key. + See `Map.set` **/ public function set( key : Int, value : T ) : Void; + /** - Get a value for the given key. + See `Map.get` **/ public function get( key : Int ) : Null; /** - Tells if a value exists for the given key. - In particular, it's useful to tells if a key has - a [null] value versus no value. + See `Map.exists` **/ public function exists( key : Int ) : Bool; /** - Removes a hashtable entry. Returns [true] if - there was such entry. + See `Map.remove` **/ public function remove( key : Int ) : Bool; /** - Returns an iterator of all keys in the hashtable. + See `Map.keys` **/ public function keys() : Iterator; /** - Returns an iterator of all values in the hashtable. + See `Map.iterator` **/ public function iterator() : Iterator; /** - Returns an displayable representation of the hashtable content. + See `Map.toString` **/ public function toString() : String; diff --git a/std/haxe/ds/ListSort.hx b/std/haxe/ds/ListSort.hx new file mode 100644 index 0000000000000000000000000000000000000000..63feb9c380725471ac147282ab2e41c71b2e64ff --- /dev/null +++ b/std/haxe/ds/ListSort.hx @@ -0,0 +1,150 @@ +/* + * Copyright (C)2005-2013 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; + +/** + ListSort provides a stable implementation of merge sort through its `sort` + method. It has a O(N.log(N)) complexity and does not require additional memory allocation +**/ +class ListSort { + + // Note : we prefer [inline] over [@:generic] here since we want to inline the comparison function as well + + /** + Sorts List `lst` according to the comparison function `cmp`, where + `cmp(x,y)` returns 0 if `x == y`, a positive Int if `x > y` and a + negative Int if `x < y`. + + This operation modifies List `a` in place and returns its head once modified. + The `prev` of the head is set to the tail of the sorted list. + + If `list` or `cmp` are null, the result is unspecified. + **/ + public static inline function sort(list:T, cmp : T -> T -> Int) : T { + // ported from http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + if( list == null ) + return null; + var insize = 1, nmerges, psize = 0, qsize = 0; + var p, q, e, tail : T = null; + while( true ) { + p = list; + list = null; + tail = null; + nmerges = 0; + while( p != null ) { + nmerges++; + q = p; + psize = 0; + for( i in 0...insize ) { + psize++; + q = q.next; + if( q == null ) break; + } + qsize = insize; + while( psize > 0 || (qsize > 0 && q != null) ) { + if( psize == 0 ) { + e = q; + q = q.next; + qsize--; + } else if( qsize == 0 || q == null || cmp(p,q) <= 0 ) { + e = p; + p = p.next; + psize--; + } else { + e = q; + q = q.next; + qsize--; + } + if( tail != null ) + tail.next = e; + else + list = e; + e.prev = tail; + tail = e; + } + p = q; + } + tail.next = null; + if( nmerges <= 1 ) + break; + insize *= 2; + } + list.prev = tail; + return list; + } + + + /** + Same as [sort] but on single linked list. + **/ + public static inline function sortSingleLinked(list:T, cmp : T -> T -> Int) : T { + if( list == null ) + return null; + var insize = 1, nmerges, psize = 0, qsize = 0; + var p, q, e, tail : T; + while( true ) { + p = list; + list = null; + tail = null; + nmerges = 0; + while( p != null ) { + nmerges++; + q = p; + psize = 0; + for( i in 0...insize ) { + psize++; + q = q.next; + if( q == null ) break; + } + qsize = insize; + while( psize > 0 || (qsize > 0 && q != null) ) { + if( psize == 0 ) { + e = q; + q = q.next; + qsize--; + } else if( qsize == 0 || q == null || cmp(p,q) <= 0 ) { + e = p; + p = p.next; + psize--; + } else { + e = q; + q = q.next; + qsize--; + } + if( tail != null ) + tail.next = e; + else + list = e; + tail = e; + } + p = q; + } + tail.next = null; + if( nmerges <= 1 ) + break; + insize *= 2; + } + return list; + } + +} \ No newline at end of file diff --git a/std/haxe/ds/ObjectMap.hx b/std/haxe/ds/ObjectMap.hx index c70d84c40c73e7ed1e4a48d553622b1b53faa20e..c464838966dbab0cbda73780dc5e17478c2947a9 100644 --- a/std/haxe/ds/ObjectMap.hx +++ b/std/haxe/ds/ObjectMap.hx @@ -22,13 +22,53 @@ package haxe.ds; -extern class ObjectMap < K: { }, V > implements Map.IMap { +/** + ObjectMap allows mapping of object keys to arbitrary values. + + On static targets, the keys are considered to be strong references. Refer + to `haxe.ds.WeakMap` for a weak reference version. + + See `Map` for documentation details. +**/ +extern class ObjectMap < K: { }, V > implements haxe.Constraints.IMap { + + /** + Creates a new ObjectMap. + **/ public function new():Void; + + /** + See `Map.set` + **/ public function set(key:K, value:V):Void; + + /** + See `Map.get` + **/ public function get(key:K):Null; + + /** + See `Map.exists` + **/ public function exists(key:K):Bool; + + /** + See `Map.remove` + **/ public function remove(key:K):Bool; + + /** + See `Map.keys` + **/ public function keys():Iterator; + + /** + See `Map.iterator` + **/ public function iterator():Iterator; + + /** + See `Map.toString` + **/ public function toString():String; } \ No newline at end of file diff --git a/std/haxe/ds/Option.hx b/std/haxe/ds/Option.hx index df98bea0c1df171f5db5dafbf612bd4a8f3c532f..7a873c6b62a56f8fefc49558fd56e2c02a2eec6a 100644 --- a/std/haxe/ds/Option.hx +++ b/std/haxe/ds/Option.hx @@ -1,32 +1,32 @@ -/* - * Copyright (C)2005-2012 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; - -/** - An Option is a wrapper type which can either have a value (Some) or not a - value (None). -**/ -enum Option { - Some(v:T); - None; +/* + * Copyright (C)2005-2012 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; + +/** + An Option is a wrapper type which can either have a value (Some) or not a + value (None). +**/ +enum Option { + Some(v:T); + None; } \ No newline at end of file diff --git a/std/haxe/ds/StringMap.hx b/std/haxe/ds/StringMap.hx index 1e44251e928e18214f1972959c70a5076f9be758..c6a86b8999acbef2e345f52243ae58f6f248d20c 100644 --- a/std/haxe/ds/StringMap.hx +++ b/std/haxe/ds/StringMap.hx @@ -23,52 +23,49 @@ package haxe.ds; /** - Hashtable over a set of elements, using [String] as keys. - Other kind of keys are not possible on all platforms since they - can't always be implemented efficiently. + StringMap allows mapping of String keys to arbitrary values. + + See `Map` for documentation details. **/ -extern class StringMap implements Map.IMap { +extern class StringMap implements haxe.Constraints.IMap { /** - Creates a new empty hashtable. + Creates a new StringMap. **/ public function new() : Void; /** - Set a value for the given key. + See `Map.set` **/ public function set( key : String, value : T ) : Void; /** - Get a value for the given key. + See `Map.get` **/ public function get( key : String ) : Null; /** - Tells if a value exists for the given key. - In particular, it's useful to tells if a key has - a [null] value versus no value. + See `Map.exists` **/ public function exists( key : String ) : Bool; /** - Removes a hashtable entry. Returns [true] if - there was such entry. + See `Map.remove` **/ public function remove( key : String ) : Bool; /** - Returns an iterator of all keys in the hashtable. + See `Map.keys` **/ public function keys() : Iterator; /** - Returns an iterator of all values in the hashtable. + See `Map.iterator` **/ public function iterator() : Iterator; /** - Returns an displayable representation of the hashtable content. + See `Map.toString` **/ public function toString() : String; diff --git a/std/haxe/ds/Vector.hx b/std/haxe/ds/Vector.hx index f569734c2ce3b786b4a3fc61c903efccf372c80a..175d686da59627cacd907bf604389f7bc5be0078 100644 --- a/std/haxe/ds/Vector.hx +++ b/std/haxe/ds/Vector.hx @@ -1,166 +1,222 @@ -/* - * Copyright (C)2005-2013 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; - -private typedef VectorData = #if flash10 - flash.Vector -#elseif neko - neko.NativeArray -#elseif cs - cs.NativeArray -#elseif java - java.NativeArray -#else - Array -#end - -/** - A Vector is a storage of fixed size. It can be faster than Array on some - targets, and is never slower. -**/ -@:arrayAccess -abstract Vector(VectorData) { - /** - Creates a new Vector of length [length]. - - Initially [this] Vector contains [length] neutral elements: - - always null on dynamic targets - - 0, 0.0 or false for Int, Float and Bool respectively on static - targets - - null for other types on static targets - - If [length] is less than or equal to 0, the result is unspecified. - **/ - public inline function new(length:Int) { - #if flash9 - this = new flash.Vector(length, true); - #elseif neko - this = untyped __dollar__amake(length); - #elseif js - this = untyped __new__(Array, length); - #elseif cs - this = new cs.NativeArray(length); - #elseif java - this = new java.NativeArray(length); - #elseif cpp - this = untyped (new Array()).__SetSizeExact(length); - #else - this = []; - untyped this.length = length; - #end - } - - /** - Returns the value at index [index]. - - If [index] is negative or exceeds [this].length, the result is - unspecified. - **/ - public inline function get(index:Int):Null { - return this[index]; - } - - /** - Sets the value at index [index] to [val]. - - If [index] is negative or exceeds [this].length, the result is - unspecified. - **/ - public inline function set(index:Int, val:T):T { - return this[index] = val; - } - - /** - Returns the length of [this] Vector. - **/ - public var length(get, never):Int; - - inline function get_length():Int { - #if neko - return untyped __dollar__asize(this); - #elseif cs - return this.Length; - #elseif java - return this.length; - #else - return untyped this.length; - #end - } - - /** - Copies [length] of elements from [src] Vector, beginning at [srcPos] to [dest] Vector, beginning at [destPos] - - The results are unspecified if [length] results in out-of-bounds access, or if [src] or [dest] are null - **/ - public static #if (cs || java || neko) inline #end function blit(src:Vector, srcPos:Int, dest:Vector, destPos:Int, len:Int):Void - { - #if neko - untyped __dollar__ablit(dest,destPos,src,srcPos,len); - #elseif java - java.lang.System.arraycopy(src, srcPos, dest, destPos, len); - #elseif cs - cs.system.Array.Copy(cast src, srcPos,cast dest, destPos, len); - #else - for (i in 0...len) - { - dest[destPos + i] = src[srcPos + i]; - } - #end - } - - /** - Extracts the data of [this] Vector. - - This returns the internal representation type. - **/ - public inline function toData():VectorData - return cast this; - - /** - Initializes a new Vector from [data]. - - Since [data] is the internal representation of Vector, this is a no-op. - - If [data] is null, the corresponding Vector is also [null]. - **/ - static public inline function fromData(data:VectorData):Vector - return cast data; - - /** - Creates a new Vector by copying the elements of [array]. - - This always creates a copy, even on platforms where the internal - representation is Array. - - The elements are not copied and retain their identity, so - a[i] == Vector.fromArrayCopy(a).get(i) is true for any valid i. - - If [array] is null, the result is unspecified. - **/ - static public inline function fromArrayCopy(array:Array):Vector { - // TODO: Optimize this for flash (and others?) - var vec = new Vector(array.length); - for (i in 0...array.length) - vec.set(i, array[i]); - return vec; - } -} +/* + * Copyright (C)2005-2013 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; + +#if cpp +using cpp.NativeArray; +#end + +private typedef VectorData = #if flash10 + flash.Vector +#elseif neko + neko.NativeArray +#elseif cs + cs.NativeArray +#elseif java + java.NativeArray +#else + Array +#end + +/** + A Vector is a storage of fixed size. It can be faster than Array on some + targets, and is never slower. +**/ +abstract Vector(VectorData) { + /** + Creates a new Vector of length `length`. + + Initially `this` Vector contains `length` neutral elements: + + - always null on dynamic targets + - 0, 0.0 or false for Int, Float and Bool respectively on static targets + - null for other types on static targets + + If `length` is less than or equal to 0, the result is unspecified. + **/ + public inline function new(length:Int) { + #if flash10 + this = new flash.Vector(length, true); + #elseif neko + this = untyped __dollar__amake(length); + #elseif js + this = untyped __new__(Array, length); + #elseif cs + this = new cs.NativeArray(length); + #elseif java + this = new java.NativeArray(length); + #elseif cpp + this = new Array(); + untyped this.__SetSizeExact(length); + #elseif python + this = python.Syntax.pythonCode("[{0}]*{1}", null, length); + #else + this = []; + untyped this.length = length; + #end + } + + /** + Returns the value at index `index`. + + If `index` is negative or exceeds `this.length`, the result is + unspecified. + **/ + @:arrayAccess public inline function get(index:Int):T { + #if cpp + return this.unsafeGet(index); + #elseif python + return python.internal.ArrayImpl.unsafeGet(this, index); + #else + return this[index]; + #end + } + + /** + Sets the value at index `index` to `val`. + + If `index` is negative or exceeds `this.length`, the result is + unspecified. + **/ + @:arrayAccess public inline function set(index:Int, val:T):T { + #if cpp + return this.unsafeSet(index,val); + #elseif python + return python.internal.ArrayImpl.unsafeSet(this, index, val); + #else + return this[index] = val; + #end + } + + /** + Returns the length of `this` Vector. + **/ + public var length(get, never):Int; + + inline function get_length():Int { + #if neko + return untyped __dollar__asize(this); + #elseif cs + return this.Length; + #elseif java + return this.length; + #elseif python + return this.length; + #else + return untyped this.length; + #end + } + + /** + Copies `length` of elements from `src` Vector, beginning at `srcPos` to + `dest` Vector, beginning at `destPos` + + The results are unspecified if `length` results in out-of-bounds access, + or if `src` or `dest` are null + **/ + public static #if (cs || java || neko || cpp) inline #end function blit(src:Vector, srcPos:Int, dest:Vector, destPos:Int, len:Int):Void + { + #if neko + untyped __dollar__ablit(dest,destPos,src,srcPos,len); + #elseif java + java.lang.System.arraycopy(src, srcPos, dest, destPos, len); + #elseif cs + cs.system.Array.Copy(cast src, srcPos,cast dest, destPos, len); + #elseif cpp + dest.toData().blit(destPos,src.toData(), srcPos,len); + #else + for (i in 0...len) + { + dest[destPos + i] = src[srcPos + i]; + } + #end + } + + /** + Creates a new Array, copy the content from the Vector to it, and returns it. + **/ + public #if (flash || cpp) inline #end function toArray():Array { + #if cpp + return this.copy(); + #elseif python + return this.copy(); + #else + var a = new Array(); + var len = length; + #if (neko) + // prealloc good size + if( len > 0 ) a[len - 1] = get(0); + #end + for( i in 0...len ) + a[i] = get(i); + return a; + #end + } + + /** + Extracts the data of `this` Vector. + + This returns the internal representation type. + **/ + public inline function toData():VectorData + return cast this; + + /** + Initializes a new Vector from `data`. + + Since `data` is the internal representation of Vector, this is a no-op. + + If `data` is null, the corresponding Vector is also `null`. + **/ + static public inline function fromData(data:VectorData):Vector + return cast data; + + /** + Creates a new Vector by copying the elements of `array`. + + This always creates a copy, even on platforms where the internal + representation is Array. + + The elements are not copied and retain their identity, so + `a[i] == Vector.fromArrayCopy(a).get(i)` is true for any valid i. + + 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(); + #elseif flash10 + return fromData(flash.Vector.ofArray(array)); + #elseif java + return fromData(java.Lib.nativeArray(array,false)); + #elseif cs + return fromData(cs.Lib.nativeArray(array,false)); + #else + // TODO: Optimize this for flash (and others?) + var vec = new Vector(array.length); + for (i in 0...array.length) + vec.set(i, array[i]); + return vec; + #end + } +} diff --git a/std/haxe/ds/WeakMap.hx b/std/haxe/ds/WeakMap.hx index f9ec9fec552024420a983d7470bd29ffdabcf6f3..c3730913073ea350fd2f14e5ba70927b855edccf 100644 --- a/std/haxe/ds/WeakMap.hx +++ b/std/haxe/ds/WeakMap.hx @@ -22,27 +22,66 @@ package haxe.ds; -class WeakMap implements Map.IMap { +/** + WeakMap allows mapping of object keys to arbitrary values. + + The keys are considered to be weak references on static targets. + + See `Map` for documentation details. +**/ +class WeakMap implements haxe.Constraints.IMap { + + /** + Creates a new WeakMap. + **/ public function new():Void { throw "Not implemented for this platform"; } + + /** + See `Map.set` + **/ public function set(key:K, value:V):Void { } + + /** + See `Map.get` + **/ public function get(key:K):Null { return null; } + + /** + See `Map.exists` + **/ public function exists(key:K):Bool { return false; } + + /** + See `Map.remove` + **/ public function remove(key:K):Bool { return false; } + + /** + See `Map.keys` + **/ public function keys():Iterator { return null; } + + /** + See `Map.iterator` + **/ public function iterator():Iterator { return null; } + + /** + See `Map.toString` + **/ public function toString():String { return null; } diff --git a/std/haxe/extern/EitherType.hx b/std/haxe/extern/EitherType.hx new file mode 100644 index 0000000000000000000000000000000000000000..ad027297015440e58904afb5cdf2b4a25e9e66f8 --- /dev/null +++ b/std/haxe/extern/EitherType.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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.extern; + +/** + An abstract type allowing values to be either of `T1` or `T2` type. + Supports implicit casts from/to either types. + + It is useful for interfacing with external code on dynamic platforms + such as JavaScript or Python. + + Otherwise, use of this type is discouraged. +**/ +abstract EitherType(Dynamic) from T1 to T1 from T2 to T2 {} diff --git a/std/haxe/extern/Rest.hx b/std/haxe/extern/Rest.hx new file mode 100644 index 0000000000000000000000000000000000000000..494ca7c7c2b39b5db18642fedabf5e7c1728d7a9 --- /dev/null +++ b/std/haxe/extern/Rest.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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.extern; + +/** + A special abstract type that represents "rest" function argument. + + Should be used as a type for the last argument of an extern method, + representing that arbitrary number of arguments of given type can be + passed to that method. +**/ +abstract Rest(Array) {} diff --git a/std/haxe/format/JsonParser.hx b/std/haxe/format/JsonParser.hx new file mode 100644 index 0000000000000000000000000000000000000000..f7bd0fcf09924a46ca7cf4c3793dce919269568c --- /dev/null +++ b/std/haxe/format/JsonParser.hx @@ -0,0 +1,255 @@ +/* + * Copyright (C)2005-2014 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.format; + +/** + An implementation of JSON parser in Haxe. + + This class is used by `haxe.Json` when native JSON implementation + is not available. +**/ +class JsonParser { + + /** + Parses given JSON-encoded `str` and returns the resulting object. + + JSON objects are parsed into anonymous structures and JSON arrays + are parsed into Array. + + If given `str` is not valid JSON, an exception will be thrown. + + If `str` is null, the result is unspecified. + **/ + static public inline function parse(str : String) : Dynamic { + return new JsonParser(str).parseRec(); + } + + var str : String; + var pos : Int; + + function new( str : String ) { + this.str = str; + this.pos = 0; + } + + function parseRec() : Dynamic { + while( true ) { + var c = nextChar(); + switch( c ) { + case ' '.code, '\r'.code, '\n'.code, '\t'.code: + // loop + case '{'.code: + var obj = {}, field = null, comma : Null = null; + while( true ) { + var c = nextChar(); + switch( c ) { + case ' '.code, '\r'.code, '\n'.code, '\t'.code: + // loop + case '}'.code: + if( field != null || comma == false ) + invalidChar(); + return obj; + case ':'.code: + if( field == null ) + invalidChar(); + Reflect.setField(obj,field,parseRec()); + field = null; + comma = true; + case ','.code: + if( comma ) comma = false else invalidChar(); + case '"'.code: + if( comma ) invalidChar(); + field = parseString(); + default: + invalidChar(); + } + } + case '['.code: + var arr = [], comma : Null = null; + while( true ) { + var c = nextChar(); + switch( c ) { + case ' '.code, '\r'.code, '\n'.code, '\t'.code: + // loop + case ']'.code: + if( comma == false ) invalidChar(); + return arr; + case ','.code: + if( comma ) comma = false else invalidChar(); + default: + if( comma ) invalidChar(); + pos--; + arr.push(parseRec()); + comma = true; + } + } + case 't'.code: + var save = pos; + if( nextChar() != 'r'.code || nextChar() != 'u'.code || nextChar() != 'e'.code ) { + pos = save; + invalidChar(); + } + return true; + case 'f'.code: + var save = pos; + if( nextChar() != 'a'.code || nextChar() != 'l'.code || nextChar() != 's'.code || nextChar() != 'e'.code ) { + pos = save; + invalidChar(); + } + return false; + case 'n'.code: + var save = pos; + if( nextChar() != 'u'.code || nextChar() != 'l'.code || nextChar() != 'l'.code ) { + pos = save; + invalidChar(); + } + return null; + case '"'.code: + return parseString(); + case '0'.code, '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code,'-'.code: + return parseNumber(c); + default: + invalidChar(); + } + } + } + + function parseString() { + var start = pos; + var buf = null; + while( true ) { + var c = nextChar(); + if( c == '"'.code ) + break; + if( c == '\\'.code ) { + if (buf == null) { + buf = new StringBuf(); + } + buf.addSub(str,start, pos - start - 1); + c = nextChar(); + switch( c ) { + case "r".code: buf.addChar("\r".code); + case "n".code: buf.addChar("\n".code); + case "t".code: buf.addChar("\t".code); + case "b".code: buf.addChar(8); + case "f".code: buf.addChar(12); + case "/".code, '\\'.code, '"'.code: buf.addChar(c); + case 'u'.code: + var uc = Std.parseInt("0x" + str.substr(pos, 4)); + pos += 4; + #if (neko || php || cpp) + if( uc <= 0x7F ) + buf.addChar(uc); + else if( uc <= 0x7FF ) { + buf.addChar(0xC0 | (uc >> 6)); + buf.addChar(0x80 | (uc & 63)); + } else if( uc <= 0xFFFF ) { + buf.addChar(0xE0 | (uc >> 12)); + buf.addChar(0x80 | ((uc >> 6) & 63)); + buf.addChar(0x80 | (uc & 63)); + } else { + buf.addChar(0xF0 | (uc >> 18)); + buf.addChar(0x80 | ((uc >> 12) & 63)); + buf.addChar(0x80 | ((uc >> 6) & 63)); + buf.addChar(0x80 | (uc & 63)); + } + #else + buf.addChar(uc); + #end + default: + throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1); + } + start = pos; + } + #if (neko || php || cpp) + // ensure utf8 chars are not cut + else if( c >= 0x80 ) { + pos++; + if( c >= 0xFC ) pos += 4; + else if( c >= 0xF8 ) pos += 3; + else if( c >= 0xF0 ) pos += 2; + else if( c >= 0xE0 ) pos++; + } + #end + else if( StringTools.isEof(c) ) + throw "Unclosed string"; + } + if (buf == null) { + return str.substr(start, pos - start - 1); + } + else { + buf.addSub(str,start, pos - start - 1); + return buf.toString(); + } + } + + inline function parseNumber( c : Int ) : Dynamic { + var start = pos - 1; + var minus = c == '-'.code, digit = !minus, zero = c == '0'.code; + var point = false, e = false, pm = false, end = false; + while( true ) { + c = nextChar(); + switch( c ) { + case '0'.code : + if (zero && !point) invalidNumber(start); + if (minus) { + minus = false; zero = true; + } + digit = true; + case '1'.code,'2'.code,'3'.code,'4'.code,'5'.code,'6'.code,'7'.code,'8'.code,'9'.code : + if (zero && !point) invalidNumber(start); + if (minus) minus = false; + digit = true; zero = false; + case '.'.code : + if (minus || point) invalidNumber(start); + digit = false; point = true; + case 'e'.code, 'E'.code : + if (minus || zero || e) invalidNumber(start); + digit = false; e = true; + case '+'.code, '-'.code : + if (!e || pm) invalidNumber(start); + digit = false; pm = true; + default : + if (!digit) invalidNumber(start); + pos--; + end = true; + } + if (end) break; + } + var f = Std.parseFloat(str.substr(start, pos - start)); + var i = Std.int(f); + return if( i == f ) i else f; + } + + inline function nextChar() { + return StringTools.fastCodeAt(str,pos++); + } + + function invalidChar() { + pos--; // rewind + throw "Invalid char "+StringTools.fastCodeAt(str,pos)+" at position "+pos; + } + + function invalidNumber( start : Int ) { + throw "Invalid number at position "+start+": " + str.substr(start, pos - start); + } +} diff --git a/std/haxe/format/JsonPrinter.hx b/std/haxe/format/JsonPrinter.hx new file mode 100644 index 0000000000000000000000000000000000000000..2ae53c445e8c8fa00d9cec559073cafc7865c8b4 --- /dev/null +++ b/std/haxe/format/JsonPrinter.hx @@ -0,0 +1,241 @@ +/* + * Copyright (C)2005-2014 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.format; + +/** + An implementation of JSON printer in Haxe. + + This class is used by `haxe.Json` when native JSON implementation + is not available. +**/ +class JsonPrinter { + + /** + Encodes `o` value and returns the resulting JSON string. + + If `replacer` is given and is not null, it is used to retrieve + actual object to be encoded. The `replacer` function two parameters, + the key and the value being encoded. Initial key value is an empty string. + + If `space` is given and is not null, the result will be pretty-printed. + Successive levels will be indented by this string. + **/ + static public function print(o:Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String) : String { + var printer = new JsonPrinter(replacer, space); + printer.write("", o); + return printer.buf.toString(); + } + + var buf : #if flash flash.utils.ByteArray #else StringBuf #end; + var replacer : Dynamic -> Dynamic -> Dynamic; + var indent:String; + var pretty:Bool; + var nind:Int; + + function new(replacer:Dynamic -> Dynamic -> Dynamic, space:String) { + this.replacer = replacer; + this.indent = space; + this.pretty = space != null; + this.nind = 0; + + #if flash + buf = new flash.utils.ByteArray(); + buf.endian = flash.utils.Endian.BIG_ENDIAN; + buf.position = 0; + #else + buf = new StringBuf(); + #end + } + + inline function ipad ():Void { + if (pretty) add(StringTools.lpad('', indent, nind * indent.length)); + } + + inline function newl ():Void { + if (pretty) addChar('\n'.code); + } + + function write(k:Dynamic, v:Dynamic) { + if (replacer != null) v = replacer(k, v); + switch( Type.typeof(v) ) { + case TUnknown: + add('"???"'); + case TObject: + objString(v); + case TInt: + add(v); + case TFloat: + add(Math.isFinite(v) ? v : 'null'); + case TFunction: + add('""'); + case TClass(c): + if( c == String ) + quote(v); + else if( c == Array ) { + var v : Array = v; + addChar('['.code); + + var len = v.length; + var last = len - 1; + for (i in 0...len) + { + if (i > 0) addChar(','.code) else nind++; + newl(); + ipad(); + write(i, v[i]); + if (i == last) + { + nind--; + newl(); + ipad(); + } + } + addChar(']'.code); + } else if( c == haxe.ds.StringMap ) { + var v : haxe.ds.StringMap = v; + var o = {}; + for( k in v.keys() ) + Reflect.setField(o,k,v.get(k)); + objString(o); + } else if( c == Date ) { + var v : Date = v; + quote(v.toString()); + } else + #if flash + classString(v); + #else + objString(v); + #end + case TEnum(_): + var i : Dynamic = Type.enumIndex(v); + add(i); + case TBool: + add(#if php (v ? 'true' : 'false') #else v #end); + case TNull: + add('null'); + } + } + + @:extern inline function addChar(c:Int) { + #if flash + buf.writeByte(c); + #else + buf.addChar(c); + #end + } + + @:extern inline function add(v:String) { + #if flash + // argument is not always a string but will be automatically casted + buf.writeUTFBytes(v); + #else + buf.add(v); + #end + } + + #if flash + function classString ( v : Dynamic ) { + fieldsString(v,Type.getInstanceFields(Type.getClass(v))); + } + #end + + inline function objString( v : Dynamic ) { + fieldsString(v,Reflect.fields(v)); + } + + function fieldsString( v : Dynamic, fields : Array ) { + addChar('{'.code); + var len = fields.length; + var last = len - 1; + var first = true; + for( i in 0...len ) { + var f = fields[i]; + var value = Reflect.field(v,f); + if( Reflect.isFunction(value) ) continue; + if( first ) { nind++; first = false; } else addChar(','.code); + newl(); + ipad(); + quote(f); + addChar(':'.code); + if (pretty) addChar(' '.code); + write(f, value); + if (i == last) + { + nind--; + newl(); + ipad(); + } + } + addChar('}'.code); + } + + function quote( s : String ) { + #if (neko || php || cpp) + if( s.length != haxe.Utf8.length(s) ) { + quoteUtf8(s); + return; + } + #end + addChar('"'.code); + var i = 0; + while( true ) { + var c = StringTools.fastCodeAt(s, i++); + if( StringTools.isEof(c) ) break; + switch( c ) { + case '"'.code: add('\\"'); + case '\\'.code: add('\\\\'); + case '\n'.code: add('\\n'); + case '\r'.code: add('\\r'); + case '\t'.code: add('\\t'); + case 8: add('\\b'); + case 12: add('\\f'); + default: + #if flash + if( c >= 128 ) add(String.fromCharCode(c)) else addChar(c); + #else + addChar(c); + #end + } + } + addChar('"'.code); + } + + #if (neko || php || cpp) + function quoteUtf8( s : String ) { + var u = new haxe.Utf8(); + haxe.Utf8.iter(s,function(c) { + switch( c ) { + case '\\'.code, '"'.code: u.addChar('\\'.code); u.addChar(c); + case '\n'.code: u.addChar('\\'.code); u.addChar('n'.code); + case '\r'.code: u.addChar('\\'.code); u.addChar('r'.code); + case '\t'.code: u.addChar('\\'.code); u.addChar('t'.code); + case 8: u.addChar('\\'.code); u.addChar('b'.code); + case 12: u.addChar('\\'.code); u.addChar('f'.code); + default: u.addChar(c); + } + }); + buf.add('"'); + buf.add(u.toString()); + buf.add('"'); + } + #end +} diff --git a/std/haxe/io/ArrayBufferView.hx b/std/haxe/io/ArrayBufferView.hx new file mode 100644 index 0000000000000000000000000000000000000000..1f1739800ad433e02fc90922b787716546566727 --- /dev/null +++ b/std/haxe/io/ArrayBufferView.hx @@ -0,0 +1,73 @@ +package haxe.io; + +typedef ArrayBufferViewData = ArrayBufferViewImpl; + +class ArrayBufferViewImpl { + public var bytes : haxe.io.Bytes; + public var byteOffset : Int; + public var byteLength : Int; + public function new(bytes, pos, length) { + this.bytes = bytes; + this.byteOffset = pos; + this.byteLength = length; + } + public function sub( begin : Int, ?length : Int ) { + if( length == null ) length = byteLength - begin; + if( begin < 0 || length < 0 || begin + length > byteLength ) throw Error.OutsideBounds; + return new ArrayBufferViewImpl(bytes, byteOffset + begin, length); + } + public function subarray( ?begin : Int, ?end : Int ) { + if( begin == null ) begin = 0; + if( end == null ) end = byteLength - begin; + return sub(begin, end - begin); + } +} + +abstract ArrayBufferView(ArrayBufferViewData) { + + /** + On some platforms configurations (for instance JS with no TypedArray support as in IE8-), Haxe will + try to emulate the array buffers API. However in that case memory sharing will not be supported : + each typed array or will copy its own data set. This flag allows users to detect if we are doing such emulation. + At the moment only JavaScript is concerned. + **/ + public static var EMULATED(get,never) : Bool; + static inline function get_EMULATED() : Bool { + return false; + } + + public var buffer(get,never) : haxe.io.Bytes; + public var byteOffset(get, never) : Int; + public var byteLength(get, never) : Int; + + public inline function new( size : Int ) { + this = new ArrayBufferViewData(haxe.io.Bytes.alloc(size), 0, size); + } + + inline function get_byteOffset() : Int return this.byteOffset; + inline function get_byteLength() : Int return this.byteLength; + inline function get_buffer() : haxe.io.Bytes return this.bytes; + + public inline function sub( begin : Int, ?length : Int ) : ArrayBufferView { + return fromData(this.sub(begin,length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : ArrayBufferView { + return fromData(this.subarray(begin,end)); + } + + public inline function getData() : ArrayBufferViewData { + return this; + } + + public static inline function fromData( a : ArrayBufferViewData ) : ArrayBufferView { + return cast a; + } + + public static function fromBytes( bytes : haxe.io.Bytes, pos = 0, ?length : Int ) : ArrayBufferView { + if( length == null ) length = bytes.length - pos; + if( pos < 0 || length < 0 || pos + length > bytes.length ) throw Error.OutsideBounds; + return fromData(new ArrayBufferViewData(bytes, pos, length)); + } + +} \ No newline at end of file diff --git a/std/haxe/io/BufferInput.hx b/std/haxe/io/BufferInput.hx index d125ba18524323ec26cdd04d32745e0777047040..cfbdbddf0b238f2d4d83165ac6aa501cede33433 100644 --- a/std/haxe/io/BufferInput.hx +++ b/std/haxe/io/BufferInput.hx @@ -1,63 +1,63 @@ -/* - * Copyright (C)2005-2012 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 BufferInput extends haxe.io.Input { - - public var i : haxe.io.Input; - public var buf : haxe.io.Bytes; - public var available : Int; - public var pos : Int; - - public function new(i, buf, ?pos = 0, ?available = 0) { - this.i = i; - this.buf = buf; - this.pos = pos; - this.available = available; - } - - public function refill() { - if( pos > 0 ) { - buf.blit(0, buf, pos, available); - pos = 0; - } - available += i.readBytes(buf, available, buf.length - available); - } - - override function readByte() { - if( available == 0 ) refill(); - var c = buf.get(pos); - pos++; - available--; - return c; - } - - override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) { - if( available == 0 ) refill(); - var size = if( len > available ) available else len; - buf.blit(pos, this.buf, this.pos, size); - this.pos += size; - this.available -= size; - return size; - } - +/* + * Copyright (C)2005-2012 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 BufferInput extends haxe.io.Input { + + public var i : haxe.io.Input; + public var buf : haxe.io.Bytes; + public var available : Int; + public var pos : Int; + + public function new(i, buf, ?pos = 0, ?available = 0) { + this.i = i; + this.buf = buf; + this.pos = pos; + this.available = available; + } + + public function refill() { + if( pos > 0 ) { + buf.blit(0, buf, pos, available); + pos = 0; + } + available += i.readBytes(buf, available, buf.length - available); + } + + override function readByte() { + if( available == 0 ) refill(); + var c = buf.get(pos); + pos++; + available--; + return c; + } + + override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) { + if( available == 0 ) refill(); + var size = if( len > available ) available else len; + buf.blit(pos, this.buf, this.pos, size); + this.pos += size; + this.available -= size; + return size; + } + } \ No newline at end of file diff --git a/std/haxe/io/Bytes.hx b/std/haxe/io/Bytes.hx index bcf5913dd4b1c502545cc218978a42409a358ad8..3be2b22ad061f7f500002f42daf1c8fd3e478aff 100644 --- a/std/haxe/io/Bytes.hx +++ b/std/haxe/io/Bytes.hx @@ -21,6 +21,10 @@ */ package haxe.io; +#if cpp +using cpp.NativeArray; +#end + class Bytes { public var length(default,null) : Int; @@ -29,12 +33,15 @@ class Bytes { function new(length,b) { this.length = length; this.b = b; + #if flash + b.endian = flash.utils.Endian.LITTLE_ENDIAN; + #end } public inline function get( pos : Int ) : Int { #if neko - return untyped __dollar__sget(b,pos); - #elseif flash9 + return untyped $sget(b,pos); + #elseif flash return b[pos]; #elseif php return untyped __call__("ord", b[pos]); @@ -42,6 +49,8 @@ class Bytes { return untyped b[pos]; #elseif java return untyped b[pos] & 0xFF; + #elseif python + return python.Syntax.arrayAccess(b, pos); #else return b[pos]; #end @@ -49,8 +58,8 @@ class Bytes { public inline function set( pos : Int, v : Int ) : Void { #if neko - untyped __dollar__sset(b,pos,v); - #elseif flash9 + untyped $sset(b,pos,v); + #elseif flash b[pos] = v; #elseif php b[pos] = untyped __call__("chr", v); @@ -60,6 +69,8 @@ class Bytes { b[pos] = cast v; #elseif cs b[pos] = cast v; + #elseif python + python.Syntax.arraySet(b, pos, v & 0xFF); #else b[pos] = v & 0xFF; #end @@ -70,16 +81,20 @@ class Bytes { if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds; #end #if neko - try untyped __dollar__sblit(b,pos,src.b,srcpos,len) catch( e : Dynamic ) throw Error.OutsideBounds; + try untyped $sblit(b,pos,src.b,srcpos,len) catch( e : Dynamic ) throw Error.OutsideBounds; #elseif php b = untyped __php__("substr($this->b, 0, $pos) . substr($src->b, $srcpos, $len) . substr($this->b, $pos+$len)"); //__call__("substr", b, 0, pos)+__call__("substr", src.b, srcpos, len)+__call__("substr", b, pos+len); - #elseif flash9 + #elseif flash b.position = pos; if( len > 0 ) b.writeBytes(src.b,srcpos,len); #elseif java java.lang.System.arraycopy(src.b, srcpos, b, pos, len); #elseif cs cs.system.Array.Copy(src.b, srcpos, b, pos, len); + #elseif python + python.Syntax.pythonCode("self.b[{0}:{0}+{1}] = src.b[srcpos:srcpos+{1}]", pos, len); + #elseif cpp + b.blit(pos, src.b, srcpos, len); #else var b1 = b; var b2 = src.b; @@ -96,13 +111,32 @@ class Bytes { #end } + public function fill( pos : Int, len : Int, value : Int ) { + #if flash + var v4 = value&0xFF; + v4 |= v4<<8; + v4 |= v4<<16; + b.position = pos; + for( i in 0...len>>2 ) + b.writeUnsignedInt(v4); + pos += len&~3; + for( i in 0...len&3 ) + set(pos++,value); + #elseif cpp + untyped __global__.__hxcpp_memory_memset(b,pos,len,value); + #else + for( i in 0...len ) + set(pos++, value); + #end + } + public function sub( pos : Int, len : Int ) : Bytes { #if !neko if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds; #end #if neko return try new Bytes(len,untyped __dollar__ssub(b,pos,len)) catch( e : Dynamic ) throw Error.OutsideBounds; - #elseif flash9 + #elseif flash b.position = pos; var b2 = new flash.utils.ByteArray(); b.readBytes(b2,0,len); @@ -117,6 +151,8 @@ class Bytes { var newarr = new cs.NativeArray(len); cs.system.Array.Copy(b, pos, newarr, 0, len); return new Bytes(len, newarr); + #elseif python + return new Bytes(len, python.Syntax.arrayAccess(b, pos, pos+len) ); #else return new Bytes(len,b.slice(pos,pos+len)); #end @@ -125,48 +161,206 @@ class Bytes { public function compare( other : Bytes ) : Int { #if neko return untyped __dollar__compare(b,other.b); - #elseif flash9 + #elseif flash var len = (length < other.length) ? length : other.length; var b1 = b; var b2 = other.b; b1.position = 0; b2.position = 0; + b1.endian = flash.utils.Endian.BIG_ENDIAN; + b2.endian = flash.utils.Endian.BIG_ENDIAN; for( i in 0...len>>2 ) if( b1.readUnsignedInt() != b2.readUnsignedInt() ) { b1.position -= 4; b2.position -= 4; - return b1.readUnsignedInt() - b2.readUnsignedInt(); + var d = b1.readUnsignedInt() - b2.readUnsignedInt(); + b1.endian = flash.utils.Endian.LITTLE_ENDIAN; + b2.endian = flash.utils.Endian.LITTLE_ENDIAN; + return d; } for( i in 0...len & 3 ) - if( b1.readUnsignedByte() != b2.readUnsignedByte() ) + if( b1.readUnsignedByte() != b2.readUnsignedByte() ) { + b1.endian = flash.utils.Endian.LITTLE_ENDIAN; + b2.endian = flash.utils.Endian.LITTLE_ENDIAN; return b1[b1.position-1] - b2[b2.position-1]; + } + b1.endian = flash.utils.Endian.LITTLE_ENDIAN; + b2.endian = flash.utils.Endian.LITTLE_ENDIAN; return length - other.length; #elseif php return untyped __php__("$this->b < $other->b ? -1 : ($this->b == $other->b ? 0 : 1)"); //#elseif cs //TODO: memcmp if unsafe flag is on + #elseif cpp + return b.memcmp(other.b); #else var b1 = b; var b2 = other.b; var len = (length < other.length) ? length : other.length; for( i in 0...len ) if( b1[i] != b2[i] ) - #if cpp return untyped b1[i] - untyped b2[i]; - #else - return untyped b1[i] - untyped b2[i]; - #end return length - other.length; #end } - public function readString( pos : Int, len : Int ) : String { + + /** + Returns the IEEE double precision value at given position (in low endian encoding). + Result is unspecified if reading outside of the bounds + **/ + #if (neko_v21 || (cpp && !cppia)) inline #end + public function getDouble( pos : Int ) : Float { + #if neko_v21 + return untyped $sgetd(b, pos, false); + #elseif flash + b.position = pos; + return b.readDouble(); + #elseif cpp + if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds; + return untyped __global__.__hxcpp_memory_get_double(b,pos); + #else + return FPHelper.i64ToDouble(getInt32(pos),getInt32(pos+4)); + #end + } + + /** + Returns the IEEE single precision value at given position (in low endian encoding). + Result is unspecified if reading outside of the bounds + **/ + #if (neko_v21 || (cpp && !cppia)) inline #end + public function getFloat( pos : Int ) : Float { + #if neko_v21 + return untyped $sgetf(b, pos, false); + #elseif flash + b.position = pos; + return b.readFloat(); + #elseif cpp + if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds; + return untyped __global__.__hxcpp_memory_get_float(b,pos); + #else + var b = new haxe.io.BytesInput(this,pos,4); + return b.readFloat(); + #end + } + + /** + Store the IEEE double precision value at given position in low endian encoding. + Result is unspecified if writing outside of the bounds. + **/ + #if neko_v21 inline #end + public function setDouble( pos : Int, v : Float ) : Void { + #if neko_v21 + untyped $ssetd(b, pos, v, false); + #elseif neko + untyped $sblit(b, pos, FPHelper._double_bytes(v,false), 0, 8); + #elseif flash + b.position = pos; + b.writeDouble(v); + #elseif cpp + if( pos < 0 || pos + 8 > length ) throw Error.OutsideBounds; + untyped __global__.__hxcpp_memory_set_double(b,pos,v); + #else + var i = FPHelper.doubleToI64(v); + setInt32(pos, i.low); + setInt32(pos + 4, i.high); + #end + } + + /** + Store the IEEE single precision value at given position in low endian encoding. + Result is unspecified if writing outside of the bounds. + **/ + #if neko_v21 inline #end + public function setFloat( pos : Int, v : Float ) : Void { + #if neko_v21 + untyped $ssetf(b, pos, v, false); + #elseif neko + untyped $sblit(b, pos, FPHelper._float_bytes(v,false), 0, 4); + #elseif flash + b.position = pos; + b.writeFloat(v); + #elseif cpp + if( pos < 0 || pos + 4 > length ) throw Error.OutsideBounds; + untyped __global__.__hxcpp_memory_set_float(b,pos,v); + #else + setInt32(pos, FPHelper.floatToI32(v)); + #end + } + + /** + Returns the 16 bit unsignged integer at given position (in low endian encoding). + **/ + public inline function getUInt16( pos : Int ) : Int { + #if neko_v21 + return untyped $sget16(b, pos, false); + #else + return get(pos) | (get(pos + 1) << 8); + #end + } + + /** + Returns the 16 bit unsignged integer at given position (in low endian encoding). + **/ + public inline function setUInt16( pos : Int, v : Int ) : Void { + #if neko_v21 + untyped $sset16(b, pos, v, false); + #else + set(pos, v); + set(pos + 1, v >> 8); + #end + } + + /** + Returns the 32 bit integer at given position (in low endian encoding). + **/ + public inline function getInt32( pos : Int ) : Int { + #if neko_v21 + return untyped $sget32(b, pos, false); + #elseif (php || python) + var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24); + return if( v & 0x80000000 != 0 ) v | 0x80000000 else v; + #else + return get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos+3) << 24); + #end + } + + /** + Returns the 64 bit integer at given position (in low endian encoding). + **/ + public inline function getInt64( pos : Int ) : haxe.Int64 { + return haxe.Int64.make(getInt32(pos+4),getInt32(pos)); + } + + /** + Store the 32 bit integer at given position (in low endian encoding). + **/ + public inline function setInt32( pos : Int, v : Int ) : Void { + #if neko_v21 + untyped $sset32(b, pos, v, false); + #else + set(pos, v); + set(pos + 1, v >> 8); + set(pos + 2, v >> 16); + set(pos + 3, v >>> 24); + #end + } + + /** + Store the 64 bit integer at given position (in low endian encoding). + **/ + public inline function setInt64( pos : Int, v : haxe.Int64 ) : Void { + setInt32(pos, v.low); + setInt32(pos + 4, v.high); + } + + public function getString( pos : Int, len : Int ) : String { #if !neko if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds; #end #if neko return try new String(untyped __dollar__ssub(b,pos,len)) catch( e : Dynamic ) throw Error.OutsideBounds; - #elseif flash9 + #elseif flash b.position = pos; return b.readUTFBytes(len); #elseif php @@ -181,13 +375,15 @@ class Bytes { try return new String(b, pos, len, "UTF-8") catch (e:Dynamic) throw e; + #elseif python + return python.Syntax.pythonCode("self.b[{0}:{0}+{1}].decode('UTF-8','replace')", pos, len); #else var s = ""; var b = b; var fcc = String.fromCharCode; var i = pos; var max = pos+len; - // utf8-encode + // utf8-decode and utf16-encode while( i < max ) { var c = b[i++]; if( c < 0x80 ) { @@ -201,17 +397,26 @@ class Bytes { } else { var c2 = b[i++]; var c3 = b[i++]; - s += fcc( ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 << 6) & 0x7F) | (b[i++] & 0x7F) ); + var u = ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | (b[i++] & 0x7F); + // surrogate pair + s += fcc( (u >> 10) + 0xD7C0 ); + s += fcc( (u & 0x3FF) | 0xDC00 ); } } return s; #end } + @:deprecated("readString is deprecated, use getString instead") + @:noCompletion + public inline function readString(pos:Int, len:Int):String { + return getString(pos, len); + } + public function toString() : String { #if neko return new String(untyped __dollar__ssub(b,0,length)); - #elseif flash9 + #elseif flash b.position = 0; return b.readUTFBytes(length); #elseif php @@ -225,7 +430,7 @@ class Bytes { } catch (e:Dynamic) throw e; #else - return readString(0,length); + return getString(0,length); #end } @@ -250,7 +455,7 @@ class Bytes { public static function alloc( length : Int ) : Bytes { #if neko return new Bytes(length,untyped __dollar__smake(length)); - #elseif flash9 + #elseif flash var b = new flash.utils.ByteArray(); b.length = length; return new Bytes(length,b); @@ -264,6 +469,8 @@ class Bytes { return new Bytes(length, new cs.NativeArray(length)); #elseif java return new Bytes(length, new java.NativeArray(length)); + #elseif python + return new Bytes(length, new python.Bytearray(length)); #else var a = new Array(); for( i in 0...length ) @@ -275,7 +482,7 @@ class Bytes { public static function ofString( s : String ) : Bytes { #if neko return new Bytes(s.length,untyped __dollar__ssub(s.__s,0,s.length)); - #elseif flash9 + #elseif flash var b = new flash.utils.ByteArray(); b.writeUTFBytes(s); return new Bytes(b.length,b); @@ -296,11 +503,20 @@ class Bytes { return new Bytes(b.length, b); } catch (e:Dynamic) throw e; + + #elseif python + var b:BytesData = new python.Bytearray(s, "UTF-8"); + return new Bytes(b.length, b); + #else var a = new Array(); - // utf8-decode - for( i in 0...s.length ) { - var c : Int = StringTools.fastCodeAt(s,i); + // utf16-decode and utf8-encode + var i = 0; + while( i < s.length ) { + var c : Int = StringTools.fastCodeAt(s,i++); + // surrogate pair + if( 0xD800 <= c && c <= 0xDBFF ) + c = (c - 0xD7C0 << 10) | (StringTools.fastCodeAt(s,i++) & 0x3FF); if( c <= 0x7F ) a.push(c); else if( c <= 0x7FF ) { @@ -322,7 +538,7 @@ class Bytes { } public static function ofData( b : BytesData ) { - #if flash9 + #if flash return new Bytes(b.length,b); #elseif neko return new Bytes(untyped __dollar__ssize(b),b); @@ -342,12 +558,12 @@ class Bytes { public inline static function fastGet( b : BytesData, pos : Int ) : Int { #if neko return untyped __dollar__sget(b,pos); - #elseif flash9 + #elseif flash return b[pos]; #elseif php return untyped __call__("ord", b[pos]); #elseif cpp - return untyped b[pos]; + return untyped b.unsafeGet(pos); #elseif java return untyped b[pos] & 0xFF; #else diff --git a/std/haxe/io/BytesBuffer.hx b/std/haxe/io/BytesBuffer.hx index 4f4bea51618844d68d18c6bff58dc88ba0597c3c..1619b335c9c2f7276553c1e6bce266301a762efd 100644 --- a/std/haxe/io/BytesBuffer.hx +++ b/std/haxe/io/BytesBuffer.hx @@ -25,7 +25,7 @@ class BytesBuffer { #if neko var b : Dynamic; // neko string buffer - #elseif flash9 + #elseif flash var b : flash.utils.ByteArray; #elseif php var b : String; @@ -39,11 +39,15 @@ class BytesBuffer { var b : Array; #end + /** The length of the buffer in bytes. **/ + public var length(get,never) : Int; + public function new() { #if neko b = untyped StringBuf.__make(); - #elseif flash9 + #elseif flash b = new flash.utils.ByteArray(); + b.endian = flash.utils.Endian.LITTLE_ENDIAN; #elseif php b = ""; #elseif cpp @@ -57,17 +61,29 @@ class BytesBuffer { #end } + inline function get_length() : Int { + #if neko + return untyped __dollar__ssize( StringBuf.__to_string(b) ); + #elseif cs + return haxe.Int64.toInt( b.Length ); + #elseif java + return b.size(); + #else + return b.length; + #end + } + public inline function addByte( byte : Int ) { #if neko untyped StringBuf.__add_char(b,byte); - #elseif flash9 + #elseif flash b.writeByte(byte); #elseif php b += untyped __call__("chr", byte); #elseif cpp b.push(untyped byte); #elseif cs - b.WriteByte(byte); + b.WriteByte(cast byte); #elseif java b.write(byte); #else @@ -78,7 +94,7 @@ class BytesBuffer { public inline function add( src : Bytes ) { #if neko untyped StringBuf.__add(b,src.getData()); - #elseif flash9 + #elseif flash b.writeBytes(src.getData()); #elseif php b += cast src.getData(); @@ -86,6 +102,11 @@ class BytesBuffer { b.Write(src.getData(), 0, src.length); #elseif java b.write(src.getData(), 0, src.length); + #elseif js + var b1 = b; + var b2 = @:privateAccess src.b; + for( i in 0...src.length ) + b.push(b2[i]); #else var b1 = b; var b2 = src.getData(); @@ -94,20 +115,67 @@ class BytesBuffer { #end } + public inline function addString( v : String ) { + #if neko + untyped StringBuf.__add(b, v.__s); + #elseif flash + b.writeUTFBytes(v); + #else + add(Bytes.ofString(v)); + #end + } + + public #if flash inline #end function addInt32( v : Int ) { + #if flash + b.writeUnsignedInt(v); + #else + addByte(v&0xFF); + addByte((v>>8)&0xFF); + addByte((v>>16)&0xFF); + addByte(v>>>24); + #end + } + + public #if flash inline #end function addInt64( v : haxe.Int64 ) { + addInt32(v.low); + addInt32(v.high); + } + + public inline function addFloat( v : Float ) { + #if flash + b.writeFloat(v); + #else + addInt32(FPHelper.floatToI32(v)); + #end + } + + public inline function addDouble( v : Float ) { + #if flash + b.writeDouble(v); + #else + addInt64(FPHelper.doubleToI64(v)); + #end + } + public inline function addBytes( src : Bytes, pos : Int, len : Int ) { #if !neko if( pos < 0 || len < 0 || pos + len > src.length ) throw Error.OutsideBounds; #end #if neko try untyped StringBuf.__add_sub(b,src.getData(),pos,len) catch( e : Dynamic ) throw Error.OutsideBounds; - #elseif flash9 - b.writeBytes(src.getData(),pos,len); + #elseif flash + if( len > 0 ) b.writeBytes(src.getData(),pos,len); #elseif php b += untyped __call__("substr", src.b, pos, len); #elseif cs b.Write(src.getData(), pos, len); #elseif java b.write(src.getData(), pos, len); + #elseif js + var b1 = b; + var b2 = @:privateAccess src.b; + for( i in pos...pos+len ) + b.push(b2[i]); #else var b1 = b; var b2 = src.getData(); @@ -124,7 +192,7 @@ class BytesBuffer { #if neko var str = StringBuf.__to_string(b); var bytes = new Bytes(__dollar__ssize(str),str); - #elseif flash9 + #elseif flash var bytes = new Bytes(b.length,b); b.position = 0; #elseif php @@ -135,6 +203,11 @@ class BytesBuffer { #elseif java var buf = b.toByteArray(); var bytes = new Bytes(buf.length, buf); + #elseif python + var buf = new python.Bytearray(b); + var bytes = new Bytes(buf.length, buf); + #elseif js + var bytes = new Bytes(new js.html.Uint8Array(b).buffer); #else var bytes = new Bytes(b.length,b); #end diff --git a/std/haxe/io/BytesData.hx b/std/haxe/io/BytesData.hx index 0b8feb2ebbf5594f759625d8277674629f049208..e099af1af78523def65c368a298f5906b7fc8d09 100644 --- a/std/haxe/io/BytesData.hx +++ b/std/haxe/io/BytesData.hx @@ -23,7 +23,7 @@ package haxe.io; #if neko typedef BytesData = neko.NativeString; -#elseif flash9 +#elseif flash typedef BytesData = flash.utils.ByteArray; #elseif php typedef BytesData = php.NativeString; @@ -34,6 +34,10 @@ package haxe.io; typedef BytesData = java.NativeArray; #elseif cs typedef BytesData = cs.NativeArray; +#elseif python + typedef BytesData = python.Bytearray; +#elseif js + typedef BytesData = js.html.ArrayBuffer; #else typedef BytesData = Array; #end diff --git a/std/haxe/io/BytesInput.hx b/std/haxe/io/BytesInput.hx index 7f92317eadcff90d7d9ef5e535f926c56a25486c..2cc65f59eb947c64c6a9aff9cc371cadd2470cf9 100644 --- a/std/haxe/io/BytesInput.hx +++ b/std/haxe/io/BytesInput.hx @@ -22,19 +22,24 @@ package haxe.io; class BytesInput extends Input { - var b : BytesData; - #if !flash9 + var b : #if js js.html.Uint8Array #else BytesData #end; + #if !flash var pos : Int; var len : Int; + var totlen : Int; #end - + + /** The current position in the stream in bytes. */ public var position(get,set) : Int; + /** The length of the stream in bytes. */ + public var length(get,never) : Int; + public function new( b : Bytes, ?pos : Int, ?len : Int ) { if( pos == null ) pos = 0; if( len == null ) len = b.length - pos; if( pos < 0 || len < 0 || pos + len > b.length ) throw Error.OutsideBounds; - #if flash9 + #if flash var ba = b.getData(); ba.position = pos; if( len != ba.bytesAvailable ) { @@ -45,30 +50,45 @@ class BytesInput extends Input { this.b = ba; this.b.endian = flash.utils.Endian.LITTLE_ENDIAN; #else - this.b = b.getData(); + this.b = #if js @:privateAccess b.b #else b.getData() #end; this.pos = pos; this.len = len; + this.totlen = len; + #end + #if python + bigEndian = false; #end } - - function get_position() : Int { - #if flash9 + + inline function get_position() : Int { + #if flash return b.position; #else return pos; #end } + inline function get_length() : Int { + #if flash + return b.length; + #else + return totlen; + #end + } + function set_position( p : Int ) : Int { - #if flash9 + if( p < 0 ) p = 0; + else if( p > length ) p = length; + #if flash return b.position = p; #else + len = totlen - p; return pos = p; #end } - + public override function readByte() : Int { - #if flash9 + #if flash return try b.readUnsignedByte() catch( e : Dynamic ) throw new Eof(); #else if( this.len == 0 ) @@ -93,7 +113,7 @@ class BytesInput extends Input { if( pos < 0 || len < 0 || pos + len > buf.length ) throw Error.OutsideBounds; #end - #if flash9 + #if flash var avail : Int = b.bytesAvailable; if( len > avail && avail > 0 ) len = avail; try b.readBytes(buf.getData(),pos,len) catch( e : Dynamic ) throw new Eof(); @@ -124,7 +144,7 @@ class BytesInput extends Input { untyped __php__("$buf->b = substr($buf->b, 0, $pos) . substr($this->b, $this->pos, $len) . substr($buf->b, $pos+$len)"); #else var b1 = b; - var b2 = buf.getData(); + var b2 = #if js @:privateAccess buf.b #else buf.getData() #end; for( i in 0...len ) b2[pos+i] = b1[this.pos+i]; #end @@ -134,37 +154,45 @@ class BytesInput extends Input { return len; } - #if flash9 + #if flash + @:dox(hide) override function set_bigEndian(e) { bigEndian = e; b.endian = e ? flash.utils.Endian.BIG_ENDIAN : flash.utils.Endian.LITTLE_ENDIAN; return e; } + @:dox(hide) override function readFloat() { return try b.readFloat() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readDouble() { return try b.readDouble() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readInt8() { return try b.readByte() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readInt16() { return try b.readShort() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readUInt16() : Int { return try b.readUnsignedShort() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readInt32() : Int { return try b.readInt() catch( e : Dynamic ) throw new Eof(); } + @:dox(hide) override function readString( len : Int ) { return try b.readUTFBytes(len) catch( e : Dynamic ) throw new Eof(); } diff --git a/std/haxe/io/BytesOutput.hx b/std/haxe/io/BytesOutput.hx index 668b09ce301050bd7a1f68acaea675d099fe442f..e8f8c0084bd9546372cfe9015ef70e68ec735a69 100644 --- a/std/haxe/io/BytesOutput.hx +++ b/std/haxe/io/BytesOutput.hx @@ -23,23 +23,33 @@ package haxe.io; class BytesOutput extends Output { - #if flash9 + #if flash var b : flash.utils.ByteArray; #else var b : BytesBuffer; #end + /** The length of the stream in bytes. **/ + public var length(get,never) : Int; + public function new() { - #if flash9 + #if flash b = new flash.utils.ByteArray(); b.endian = flash.utils.Endian.LITTLE_ENDIAN; #else b = new BytesBuffer(); #end + #if python + bigEndian = false; + #end + } + + inline function get_length() : Int { + return b.length; } override function writeByte(c) { - #if flash9 + #if flash b.writeByte(c); #else b.addByte(c); @@ -47,7 +57,7 @@ class BytesOutput extends Output { } override function writeBytes( buf : Bytes, pos, len ) : Int { - #if flash9 + #if flash if( pos < 0 || len < 0 || pos + len > buf.length ) throw Error.OutsideBounds; b.writeBytes(buf.getData(),pos,len); #else @@ -56,52 +66,56 @@ class BytesOutput extends Output { return len; } - #if flash9 + #if flash // optimized operations + @:dox(hide) override function set_bigEndian(e) { bigEndian = e; b.endian = e ? flash.utils.Endian.BIG_ENDIAN : flash.utils.Endian.LITTLE_ENDIAN; return e; } + @:dox(hide) override function writeFloat( f : Float ) { b.writeFloat(f); } + @:dox(hide) override function writeDouble( f : Float ) { b.writeDouble(f); } + @:dox(hide) override function writeInt8( x : Int ) { if( x < -0x80 || x >= 0x80 ) throw Error.Overflow; b.writeByte(x); } + @:dox(hide) override function writeInt16( x : Int ) { if( x < -0x8000 || x >= 0x8000 ) throw Error.Overflow; b.writeShort(x); } + @:dox(hide) override function writeUInt16( x : Int ) { if( x < 0 || x >= 0x10000 ) throw Error.Overflow; b.writeShort(x); } + @:dox(hide) override function writeInt32( x : Int ) { b.writeInt(x); } + @:dox(hide) override function prepare( size : Int ) { - if( size > 0 ) - #if cpp - untyped b.__Resize(size); - #else - b[size-1] = b[size-1]; - #end + if( size > 0 ) b[size-1] = b[size-1]; } + @:dox(hide) override function writeString( s : String ) { b.writeUTFBytes(s); } @@ -109,7 +123,7 @@ class BytesOutput extends Output { #end public function getBytes() : Bytes { - #if flash9 + #if flash var bytes = b; b = null; return untyped new Bytes(bytes.length,bytes); diff --git a/std/haxe/io/FPHelper.hx b/std/haxe/io/FPHelper.hx new file mode 100644 index 0000000000000000000000000000000000000000..117c318cf80e64d2fee04a5e3be66ccff887488f --- /dev/null +++ b/std/haxe/io/FPHelper.hx @@ -0,0 +1,327 @@ +/* + * Copyright (C)2005-2015 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; + +/** + Helper that converts between floating point and binary representation. + Always works in low-endian encoding. +**/ +class FPHelper { + + #if neko_v21 + // stored in helper + #elseif neko + static var i64tmp = new neko.vm.Tls(); + #elseif !(java || cs) + static var i64tmp = Int64.ofInt(0); + #end + + #if neko + #if neko_v21 + static var helpers = new neko.vm.Tls>(); + #else + static var helperf = new neko.vm.Tls(); + static var helperd = new neko.vm.Tls(); + static var _float_of_bytes = neko.Lib.load("std","float_of_bytes",2); + static var _double_of_bytes = neko.Lib.load("std","double_of_bytes",2); + static var _float_bytes = neko.Lib.load("std","float_bytes",2); + static var _double_bytes = neko.Lib.load("std","double_bytes",2); + #end + #elseif flash + static var helper = { + var b = new flash.utils.ByteArray(); + b.endian = flash.utils.Endian.LITTLE_ENDIAN; + b; + } + #elseif php + static var isLittleEndian : Bool = untyped __call__('unpack','S','\x01\x00')[1] == 1; + #else + static inline var LN2 = 0.6931471805599453; // Math.log(2) + #end + + #if neko_v21 inline #end + public static function i32ToFloat( i : Int ) : Float { + #if neko + #if neko_v21 + return untyped $itof(i,false); + #else + var helper = helperf.value; + if( helper == null ) + helperf.value = helper = neko.NativeString.alloc(4); + untyped $sset(helper,0,i&0xFF); + untyped $sset(helper,1,(i>>8)&0xFF); + untyped $sset(helper,2,(i>>16)&0xFF); + untyped $sset(helper,3,i>>>24); + return _float_of_bytes(helper,false); + #end + #elseif cpp + return untyped __global__.__hxcpp_reinterpret_le_int32_as_float32(i); + #elseif cs + var helper = new SingleHelper(0); + if( cs.system.BitConverter.IsLittleEndian ) + { + helper.i = i; + } else { + helper.i = ((i >>> 24) & 0xFF) | (((i >> 16) & 0xFF) << 8) | (((i >> 8) & 0xFF) << 16) | ((i & 0xFF) << 24); + } + + return helper.f; + #elseif java + return java.lang.Float.FloatClass.intBitsToFloat(i); + #elseif php + return untyped __call__('unpack', 'f', __call__('pack', 'l', i))[1]; + #elseif flash + var helper = helper; + helper.position = 0; + helper.writeUnsignedInt(i); + helper.position = 0; + return helper.readFloat(); + #else + var sign = 1 - ((i >>> 31) << 1); + var exp = (i >>> 23) & 0xFF; + var sig = i & 0x7FFFFF; + if( sig == 0 && exp == 0 ) + return 0.0; + return sign*(1 + Math.pow(2, -23)*sig) * Math.pow(2, exp-127); + #end + } + + #if neko_v21 inline #end + public static function floatToI32( f : Float ) : Int { + #if neko + #if neko_v21 + return untyped $ftoi(f,false); + #else + var r = _float_bytes(f,false); + return untyped $sget(r,0) | ($sget(r,1)<<8) | ($sget(r,2)<<16) | ($sget(r,3)<<24); + #end + #elseif cpp + return untyped __global__.__hxcpp_reinterpret_float32_as_le_int32(f); + #elseif cs + var helper = new SingleHelper(f); + if( cs.system.BitConverter.IsLittleEndian ) + { + return helper.i; + } else { + var i = helper.i; + return ((i >>> 24) & 0xFF) | (((i >> 16) & 0xFF) << 8) | (((i >> 8) & 0xFF) << 16) | ((i & 0xFF) << 24); + } + #elseif java + return java.lang.Float.FloatClass.floatToRawIntBits(f); + #elseif flash + var helper = helper; + helper.position = 0; + helper.writeFloat(f); + helper.position = 0; + return helper.readUnsignedInt(); + #elseif php + return untyped __call__('unpack','l',__call__('pack', 'f', f))[1]; + #else + if( f == 0 ) return 0; + var af = f < 0 ? -f : f; + var exp = Math.floor(Math.log(af) / LN2); + if( exp < -127 ) exp = -127 else if( exp > 128 ) exp = 128; + var sig = Math.round((af / Math.pow(2, exp) - 1) * 0x800000) & 0x7FFFFF; + return (f < 0 ? 0x80000000 : 0) | ((exp + 127) << 23) | sig; + #end + } + + #if neko_v21 inline #end + public static function i64ToDouble( low : Int, high : Int ) : Float { + #if neko + #if neko_v21 + return untyped $itod(low,high,false); + #else + var helper = helperd.value; + if( helper == null ) + helperd.value = helper = neko.NativeString.alloc(8); + untyped $sset(helper,0,low&0xFF); + untyped $sset(helper,1,(low>>8)&0xFF); + untyped $sset(helper,2,(low>>16)&0xFF); + untyped $sset(helper,3,low>>>24); + untyped $sset(helper,4,high&0xFF); + untyped $sset(helper,5,(high>>8)&0xFF); + untyped $sset(helper,6,(high>>16)&0xFF); + untyped $sset(helper,7,high>>>24); + return _double_of_bytes(helper,false); + #end + #elseif cpp + return untyped __global__.__hxcpp_reinterpret_le_int32s_as_float64(low,high); + #elseif cs + var helper = new FloatHelper(0); + if( cs.system.BitConverter.IsLittleEndian ) + { + helper.i = haxe.Int64.make(high,low); + } else { + var i1 = high, + i2 = low; + var j2 = ((i1 >>> 24) & 0xFF) | (((i1 >> 16) & 0xFF) << 8) | (((i1 >> 8) & 0xFF) << 16) | ((i1 & 0xFF) << 24); + var j1 = ((i2 >>> 24) & 0xFF) | (((i2 >> 16) & 0xFF) << 8) | (((i2 >> 8) & 0xFF) << 16) | ((i2 & 0xFF) << 24); + helper.i = haxe.Int64.make(j1,j2); + } + return helper.f; + #elseif java + return java.lang.Double.DoubleClass.longBitsToDouble( Int64.make(high,low) ); + #elseif flash + var helper = helper; + helper.position = 0; + helper.writeUnsignedInt(low); + helper.writeUnsignedInt(high); + helper.position = 0; + return helper.readDouble(); + #elseif php + return untyped __call__('unpack', 'd', __call__('pack', 'ii', isLittleEndian ? low : high, isLittleEndian ? high : low))[1]; + #else + var sign = 1 - ((high >>> 31) << 1); + var exp = ((high >> 20) & 0x7FF) - 1023; + var sig = (high&0xFFFFF) * 4294967296. + (low>>>31) * 2147483648. + (low&0x7FFFFFFF); + if( sig == 0 && exp == -1023 ) + return 0.0; + return sign*(1.0 + Math.pow(2, -52)*sig) * Math.pow(2, exp); + #end + } + + /** + Returns an Int64 representing the bytes representation of the double precision IEEE float value. + WARNING : for performance reason, the same Int64 value might be reused every time. Copy its low/high values before calling again. + We still ensure that this is safe to use in a multithread environment + **/ + public static function doubleToI64( v : Float ) : Int64 { + #if neko + #if neko_v21 + var helper = helpers.value; + if( helper == null ) { + helpers.value = helper = neko.NativeArray.alloc(2); + helper[0] = neko.NativeArray.alloc(2); + helper[1] = haxe.Int64.ofInt(0); + } + var i64 : haxe.Int64 = helper[1], int2 = helper[0]; + untyped $dtoi(v,int2,false); + @:privateAccess { + i64.set_low(int2[0]); + i64.set_high(int2[1]); + } + return i64; + #else + var r = _double_bytes(v,false), i64 = i64tmp.value; + if( i64 == null ) + i64 = i64tmp.value = haxe.Int64.ofInt(0); + @:privateAccess { + i64.set_low(untyped $sget(r,0) | ($sget(r,1)<<8) | ($sget(r,2)<<16) | ($sget(r,3)<<24)); + i64.set_high(untyped $sget(r,4) | ($sget(r,5)<<8) | ($sget(r,6)<<16) | ($sget(r,7)<<24)); + } + return i64; + #end + #elseif cpp + return Int64.make(untyped __global__.__hxcpp_reinterpret_float64_as_le_int32_high(v), + untyped __global__.__hxcpp_reinterpret_float64_as_le_int32_low(v) ); + #elseif java + return java.lang.Double.DoubleClass.doubleToRawLongBits(v); + #elseif cs + var helper = new FloatHelper(v); + if( cs.system.BitConverter.IsLittleEndian ) + { + return helper.i; + } else { + var i = helper.i; + var i1 = haxe.Int64.getHigh(i), + i2 = haxe.Int64.getLow(i); + var j2 = ((i1 >>> 24) & 0xFF) | (((i1 >> 16) & 0xFF) << 8) | (((i1 >> 8) & 0xFF) << 16) | ((i1 & 0xFF) << 24); + var j1 = ((i2 >>> 24) & 0xFF) | (((i2 >> 16) & 0xFF) << 8) | (((i2 >> 8) & 0xFF) << 16) | ((i2 & 0xFF) << 24); + + return haxe.Int64.make(j1,j2); + } + #elseif flash + var helper = helper; + helper.position = 0; + helper.writeDouble(v); + helper.position = 0; + var i64 = i64tmp; + @:privateAccess { + i64.set_low(cast helper.readUnsignedInt()); + i64.set_high(cast helper.readUnsignedInt()); + } + return i64; + #elseif php + var a = untyped __call__('unpack',isLittleEndian ? 'V2' : 'N2',__call__('pack', 'd', v)); + var i64 = i64tmp; + @:privateAccess { + i64.set_low(a[isLittleEndian ? 1 : 2]); + i64.set_high(a[isLittleEndian ? 2 : 1]); + } + return i64; + #else + var i64 = i64tmp; + if( v == 0 ) { + @:privateAccess { + i64.set_low(0); + i64.set_high(0); + } + } else { + var av = v < 0 ? -v : v; + var exp = Math.floor(Math.log(av) / LN2); + var sig = Math.fround(((av / Math.pow(2, exp)) - 1) * 4503599627370496.); // 2^52 + var sig_l = Std.int(sig); + var sig_h = Std.int(sig / 4294967296.0); + @:privateAccess { + i64.set_low(sig_l); + i64.set_high((v < 0 ? 0x80000000 : 0) | ((exp + 1023) << 20) | sig_h); + } + } + return i64; + #end + } + +} + +#if cs +@:meta(System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)) +@:nativeGen @:struct private class SingleHelper +{ + @:meta(System.Runtime.InteropServices.FieldOffset(0)) + public var i:Int; + @:meta(System.Runtime.InteropServices.FieldOffset(0)) + public var f:Single; + + public function new(f:Single) + { + this.i = 0; + this.f = f; + } +} + +@:meta(System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)) +@:nativeGen @:struct private class FloatHelper +{ + @:meta(System.Runtime.InteropServices.FieldOffset(0)) + public var i:haxe.Int64; + @:meta(System.Runtime.InteropServices.FieldOffset(0)) + public var f:Float; + + public function new(f:Float) + { + this.i = haxe.Int64.ofInt(0); + this.f = f; + } +} + +#end diff --git a/std/haxe/io/Float32Array.hx b/std/haxe/io/Float32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..a45d84ce857c8fda6450168ecb5dca0b4bdb7e7b --- /dev/null +++ b/std/haxe/io/Float32Array.hx @@ -0,0 +1,85 @@ +/* + * Copyright (C)2005-2015 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; + +typedef Float32ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract Float32Array(Float32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength >> 2; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Float { + return this.bytes.getFloat((index<<2) + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : Float ) : Float { + if( index >= 0 && index < length ) { + this.bytes.setFloat((index<<2) + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : Float32Array { + return fromData(this.sub(begin<<2,length == null ? null : length<<2)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Float32Array { + return fromData(this.subarray(begin==null?null:begin<<2,end==null?null:end<<2)); + } + + public inline function getData() : Float32ArrayData { + return this; + } + + public static function fromData( d : Float32ArrayData ) : Float32Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : Float32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new Float32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos = 0, ?length : Int ) : Float32Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,(length == null ? (bytes.length - bytePos)>>2 : length)<<2).getData()); + } +} + diff --git a/std/haxe/io/Float64Array.hx b/std/haxe/io/Float64Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..6747ee1d520e06a4332a4c7e7b0d4c0d386fb2fd --- /dev/null +++ b/std/haxe/io/Float64Array.hx @@ -0,0 +1,85 @@ +/* + * Copyright (C)2005-2015 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; + +typedef Float64ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract Float64Array(Float64ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 8; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength >> 3; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Float { + return this.bytes.getFloat((index<<3) + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : Float ) : Float { + if( index >= 0 && index < length ) { + this.bytes.setFloat((index<<3) + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : Float64Array { + return fromData(this.sub(begin<<3,length == null ? null : length<<3)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Float64Array { + return fromData(this.subarray(begin==null?null:begin<<3,end==null?null:end<<3)); + } + + public inline function getData() : Float64ArrayData { + return this; + } + + public static function fromData( d : Float64ArrayData ) : Float64Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : Float64Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new Float64Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos = 0, ?length : Int ) : Float64Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,(length == null ? (bytes.length - bytePos)>>3 : length)<<3).getData()); + } +} + diff --git a/std/haxe/io/Input.hx b/std/haxe/io/Input.hx index 8e747f7dc86276634ad43b7ee38d279621dceda1..b1f9ff5b1a05d17b999a7e322b999909b657b5a6 100644 --- a/std/haxe/io/Input.hx +++ b/std/haxe/io/Input.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2012 Haxe Foundation + * Copyright (C)2005-2014 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,30 +22,45 @@ package haxe.io; /** - An Input is an abstract reader. See other classes in the [haxe.io] package + An Input is an abstract reader. See other classes in the `haxe.io` package for several possible implementations. **/ class Input { + /** + Endianness (word byte order) used when reading numbers. + + If `true`, big-endian is used, otherwise `little-endian` is used. + **/ public var bigEndian(default,set) : Bool; + #if cs private var helper:BytesData; #elseif java private var helper:java.nio.ByteBuffer; #end + /** + Read and return one byte. + **/ public function readByte() : Int { #if cpp throw "Not implemented"; - return 0; #else return throw "Not implemented"; #end } + /** + Read `len` bytes and write them into `s` to the position specified by `pos`. + + Returns the actual length of read data that can be smaller than `len`. + + See `readFullBytes` that tries to read the exact amount of specified bytes. + **/ public function readBytes( s : Bytes, pos : Int, len : Int ) : Int { var k = len; - var b = s.getData(); + var b = #if js @:privateAccess s.b #else s.getData() #end; if( pos < 0 || len < 0 || pos + len > s.length ) throw Error.OutsideBounds; while( k > 0 ) { @@ -64,16 +79,27 @@ class Input { return len; } - public function close() { + /** + Close the input source. + + Behaviour while reading after calling this method is unspecified. + **/ + public function close() : Void { } - function set_bigEndian(b) { + function set_bigEndian( b : Bool ) : Bool { bigEndian = b; return b; } /* ------------------ API ------------------ */ + /** + Read and return all available data. + + The `bufsize` optional argument specifies the size of chunks by + which data is read. Its default value is target-specific. + **/ public function readAll( ?bufsize : Int ) : Bytes { if( bufsize == null ) #if php @@ -96,7 +122,12 @@ class Input { return total.getBytes(); } - public function readFullBytes( s : Bytes, pos : Int, len : Int ) { + /** + Read `len` bytes and write them into `s` to the position specified by `pos`. + + Unlike `readBytes`, this method tries to read the exact `len` amount of bytes. + **/ + public function readFullBytes( s : Bytes, pos : Int, len : Int ) : Void { while( len > 0 ) { var k = readBytes(s,pos,len); pos += k; @@ -104,6 +135,9 @@ class Input { } } + /** + Read and return `nbytes` bytes. + **/ public function read( nbytes : Int ) : Bytes { var s = Bytes.alloc(nbytes); var p = 0; @@ -116,6 +150,11 @@ class Input { return s; } + /** + Read a string until a character code specified by `end` is occurred. + + The final character is not included in the resulting string. + **/ public function readUntil( end : Int ) : String { var buf = new StringBuf(); var last : Int; @@ -124,6 +163,11 @@ class Input { return buf.toString(); } + /** + Read a line of text separated by CR and/or LF bytes. + + The CR/LF characters are not included in the resulting string. + **/ public function readLine() : String { var buf = new StringBuf(); var last : Int; @@ -141,141 +185,42 @@ class Input { return s; } - public function readFloat() : Float { - #if neko - return _float_of_bytes(untyped read(4).b,bigEndian); - #elseif cpp - return _float_of_bytes(read(4).getData(),bigEndian); - #elseif php - var a = untyped __call__('unpack', 'f', readString(4)); - return a[1]; - #elseif cs - if (helper == null) helper = new cs.NativeArray(8); - - var helper = helper; - if (bigEndian == !cs.system.BitConverter.IsLittleEndian) - { - helper[0] = readByte(); - helper[1] = readByte(); - helper[2] = readByte(); - helper[3] = readByte(); - } else { - helper[3] = readByte(); - helper[2] = readByte(); - helper[1] = readByte(); - helper[0] = readByte(); - } + /** + Read a 32-bit floating point number. - return cs.system.BitConverter.ToSingle(helper, 0); - #elseif java - if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8); - var helper = helper; - helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN); - - helper.put(0, cast readByte()); - helper.put(1, cast readByte()); - helper.put(2, cast readByte()); - helper.put(3, cast readByte()); - - return helper.getFloat(0); - #else - var bytes = []; - bytes.push(cast readByte()); - bytes.push(cast readByte()); - bytes.push(cast readByte()); - bytes.push(cast readByte()); - if (bigEndian) - bytes.reverse(); - var sign = 1 - ((bytes[0] >> 7) << 1); - var exp = (((bytes[0] << 1) & 0xFF) | (bytes[1] >> 7)) - 127; - var sig = ((bytes[1] & 0x7F) << 16) | (bytes[2] << 8) | bytes[3]; - if (sig == 0 && exp == -127) - return 0.0; - return sign*(1 + Math.pow(2, -23)*sig) * Math.pow(2, exp); - #end + Endianness is specified by the `bigEndian` property. + **/ + public #if !(flash || python) inline #end function readFloat() : Float { + return FPHelper.i32ToFloat(readInt32()); } - public function readDouble() : Float { - #if neko - return _double_of_bytes(untyped read(8).b,bigEndian); - #elseif cpp - return _double_of_bytes(read(8).getData(),bigEndian); - #elseif php - var a = untyped __call__('unpack', 'd', readString(8)); - return a[1]; - #elseif (flash || js) - var bytes = []; - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - bytes.push(readByte()); - if (bigEndian) - bytes.reverse(); - - var sign = 1 - ((bytes[0] >> 7) << 1); // sign = bit 0 - var exp = (((bytes[0] << 4) & 0x7FF) | (bytes[1] >> 4)) - 1023; // exponent = bits 1..11 - var sig = getDoubleSig(bytes); - if (sig == 0 && exp == -1023) - return 0.0; - return sign * (1.0 + Math.pow(2, -52) * sig) * Math.pow(2, exp); - #elseif cs - if (helper == null) helper = new cs.NativeArray(8); - - var helper = helper; - if (bigEndian == !cs.system.BitConverter.IsLittleEndian) - { - helper[0] = readByte(); - helper[1] = readByte(); - helper[2] = readByte(); - helper[3] = readByte(); - helper[4] = readByte(); - helper[5] = readByte(); - helper[6] = readByte(); - helper[7] = readByte(); - } else { - helper[7] = readByte(); - helper[6] = readByte(); - helper[5] = readByte(); - helper[4] = readByte(); - helper[3] = readByte(); - helper[2] = readByte(); - helper[1] = readByte(); - helper[0] = readByte(); - } + /** + Read a 64-bit double-precision floating point number. - return cs.system.BitConverter.ToDouble(helper, 0); - #elseif java - if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8); - var helper = helper; - helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN); - - helper.put(0, cast readByte()); - helper.put(1, cast readByte()); - helper.put(2, cast readByte()); - helper.put(3, cast readByte()); - helper.put(4, cast readByte()); - helper.put(5, cast readByte()); - helper.put(6, cast readByte()); - helper.put(7, cast readByte()); - - return helper.getDouble(0); - #else - return throw "not implemented"; - #end + Endianness is specified by the `bigEndian` property. + **/ + public function readDouble() : Float { + var i1 = readInt32(); + var i2 = readInt32(); + return bigEndian ? FPHelper.i64ToDouble(i2,i1) : FPHelper.i64ToDouble(i1,i2); } - public function readInt8() { + /** + Read a 8-bit signed integer. + **/ + public function readInt8() : Int { var n = readByte(); if( n >= 128 ) return n - 256; return n; } - public function readInt16() { + /** + Read a 16-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ + public function readInt16() : Int { var ch1 = readByte(); var ch2 = readByte(); var n = bigEndian ? ch2 | (ch1 << 8) : ch1 | (ch2 << 8); @@ -284,13 +229,23 @@ class Input { return n; } - public function readUInt16() { + /** + Read a 16-bit unsigned integer. + + Endianness is specified by the `bigEndian` property. + **/ + public function readUInt16() : Int { var ch1 = readByte(); var ch2 = readByte(); return bigEndian ? ch2 | (ch1 << 8) : ch1 | (ch2 << 8); } - public function readInt24() { + /** + Read a 24-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ + public function readInt24() : Int { var ch1 = readByte(); var ch2 = readByte(); var ch3 = readByte(); @@ -300,21 +255,42 @@ class Input { return n; } - public function readUInt24() { + /** + Read a 24-bit unsigned integer. + + Endianness is specified by the `bigEndian` property. + **/ + public function readUInt24() : Int { var ch1 = readByte(); var ch2 = readByte(); var ch3 = readByte(); return bigEndian ? ch3 | (ch2 << 8) | (ch1 << 16) : ch1 | (ch2 << 8) | (ch3 << 16); } - public function readInt32() { + /** + Read a 32-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ + public function readInt32() : Int { var ch1 = readByte(); var ch2 = readByte(); var ch3 = readByte(); var ch4 = readByte(); +#if (php || python) + // php will overflow integers. Convert them back to signed 32-bit ints. + var n = bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24); + if (n & 0x80000000 != 0) + return ( n | 0x80000000); + else return n; +#else return bigEndian ? ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24) : ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24); +#end } + /** + Read and `len` bytes as a string. + **/ public function readString( len : Int ) : String { var b = Bytes.alloc(len); readFullBytes(b,0,len); @@ -336,7 +312,7 @@ class Input { static var _double_of_bytes = cpp.Lib.load("std","double_of_bytes",2); #end -#if (flash || js) +#if (flash || js || python) function getDoubleSig(bytes:Array) { return (((bytes[1]&0xF) << 16) | (bytes[2] << 8) | bytes[3] ) * 4294967296. + diff --git a/std/haxe/io/Int32Array.hx b/std/haxe/io/Int32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..29a04343c331e114e65fe6e690614b847bb06fd5 --- /dev/null +++ b/std/haxe/io/Int32Array.hx @@ -0,0 +1,85 @@ +/* + * Copyright (C)2005-2015 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; + +typedef Int32ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract Int32Array(Int32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength >> 2; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Int { + return this.bytes.getInt32((index<<2) + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + if( index >= 0 && index < length ) { + this.bytes.setInt32((index<<2) + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : Int32Array { + return fromData(this.sub(begin<<2,length == null ? null : length<<2)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Int32Array { + return fromData(this.subarray(begin==null?null:begin<<2,end==null?null:end<<2)); + } + + public inline function getData() : Int32ArrayData { + return this; + } + + public static function fromData( d : Int32ArrayData ) : Int32Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : Int32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new Int32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos = 0, ?length : Int ) : Int32Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,(length == null ? (bytes.length - bytePos)>>2 : length)<<2).getData()); + } +} + diff --git a/std/haxe/io/Output.hx b/std/haxe/io/Output.hx index c62fa98e986d4e7146ed7f724285d951dc2e2064..6147ee0638c129942432c68824c57a05b8bb9287 100644 --- a/std/haxe/io/Output.hx +++ b/std/haxe/io/Output.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2012 Haxe Foundation + * Copyright (C)2005-2014 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,22 +23,37 @@ package haxe.io; /** An Output is an abstract write. A specific output implementation will only - have to override the [writeChar] and maybe the [write], [flush] and [close] + have to override the [writeByte] and maybe the [write], [flush] and [close] methods. See [File.write] and [String.write] for two ways of creating an Output. **/ class Output { - private static var LN2 = Math.log(2); + + /** + Endianness (word byte order) used when writing numbers. + + If `true`, big-endian is used, otherwise `little-endian` is used. + **/ public var bigEndian(default, set) : Bool; #if java private var helper:java.nio.ByteBuffer; #end + /** + Write one byte. + **/ public function writeByte( c : Int ) : Void { throw "Not implemented"; } + /** + Write `len` bytes from `s` starting by position specified by `pos`. + + Returns the actual length of written data that can differ from `len`. + + See `writeFullBytes` that tries to write the exact amount of specified bytes. + **/ public function writeBytes( s : Bytes, pos : Int, len : Int ) : Int { var k = len; var b = s.getData(); @@ -62,9 +77,17 @@ class Output { return len; } + /** + Flush any buffered data. + **/ public function flush() { } + /** + Close the output. + + Behaviour while writing after calling this method is unspecified. + **/ public function close() { } @@ -75,6 +98,9 @@ class Output { /* ------------------ API ------------------ */ + /** + Write all bytes stored in `s`. + **/ public function write( s : Bytes ) : Void { var l = s.length; var p = 0; @@ -86,6 +112,11 @@ class Output { } } + /** + Write `len` bytes from `s` starting by position specified by `pos`. + + Unlike `writeBytes`, this method tries to write the exact `len` amount of bytes. + **/ public function writeFullBytes( s : Bytes, pos : Int, len : Int ) { while( len > 0 ) { var k = writeBytes(s,pos,len); @@ -94,148 +125,55 @@ class Output { } } - public function writeFloat( x : Float ) { - #if neko - write(untyped new Bytes(4,_float_bytes(x,bigEndian))); - #elseif cpp - write(Bytes.ofData(_float_bytes(x,bigEndian))); - #elseif php - write(untyped Bytes.ofString(__call__('pack', 'f', x))); - #elseif cs - var bytes = cs.system.BitConverter.GetBytes(cast(x, Single)); - if (bigEndian == cs.system.BitConverter.IsLittleEndian) - { - writeByte(bytes[3]); - writeByte(bytes[2]); - writeByte(bytes[1]); - writeByte(bytes[0]); - } else { - writeByte(bytes[0]); - writeByte(bytes[1]); - writeByte(bytes[2]); - writeByte(bytes[3]); - } - #elseif java - if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8); - var helper = helper; - helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN); - - helper.putFloat(0, x); - writeByte(untyped helper.get(0)); - writeByte(untyped helper.get(1)); - writeByte(untyped helper.get(2)); - writeByte(untyped helper.get(3)); - #else - if (x == 0.0) - { - writeByte(0); writeByte(0); writeByte(0); writeByte(0); - return; - } - var exp = Math.floor(Math.log(Math.abs(x)) / LN2); - var sig = (Math.floor(Math.abs(x) / Math.pow(2, exp) * (2 << 22)) & 0x7FFFFF); - var b1 = (exp + 0x7F) >> 1 | (exp>0 ? ((x<0) ? 1<<7 : 1<<6) : ((x<0) ? 1<<7 : 0)), - b2 = (exp + 0x7F) << 7 & 0xFF | (sig >> 16 & 0x7F), - b3 = (sig >> 8) & 0xFF, - b4 = sig & 0xFF; - if (bigEndian) - { - writeByte(b4); writeByte(b3); writeByte(b2); writeByte(b1); - } - else - { - writeByte(b1); writeByte(b2); writeByte(b3); writeByte(b4); - } - #end + /** + Write `x` as 32-bit floating point number. + + Endianness is specified by the `bigEndian` property. + **/ + public #if !(flash || python) inline #end function writeFloat( x : Float ) { + writeInt32(FPHelper.floatToI32(x)); } + /** + Write `x` as 64-bit double-precision floating point number. + + Endianness is specified by the `bigEndian` property. + **/ public function writeDouble( x : Float ) { - #if neko - write(untyped new Bytes(8,_double_bytes(x,bigEndian))); - #elseif cpp - write(Bytes.ofData(_double_bytes(x,bigEndian))); - #elseif php - write(untyped Bytes.ofString(__call__('pack', 'd', x))); - #elseif cs - var bytes = cs.system.BitConverter.GetBytes(x); - if (bigEndian == cs.system.BitConverter.IsLittleEndian) - { - writeByte(bytes[7]); - writeByte(bytes[6]); - writeByte(bytes[5]); - writeByte(bytes[4]); - writeByte(bytes[3]); - writeByte(bytes[2]); - writeByte(bytes[1]); - writeByte(bytes[0]); + var i64 = FPHelper.doubleToI64(x); + if( bigEndian ) { + writeInt32(i64.high); + writeInt32(i64.low); } else { - writeByte(bytes[0]); - writeByte(bytes[1]); - writeByte(bytes[2]); - writeByte(bytes[3]); - writeByte(bytes[4]); - writeByte(bytes[5]); - writeByte(bytes[6]); - writeByte(bytes[7]); - } - #elseif java - if (helper == null) helper = java.nio.ByteBuffer.allocateDirect(8); - var helper = helper; - helper.order(bigEndian ? java.nio.ByteOrder.BIG_ENDIAN : java.nio.ByteOrder.LITTLE_ENDIAN); - - helper.putDouble(0, x); - - writeByte(untyped helper.get(0)); - writeByte(untyped helper.get(1)); - writeByte(untyped helper.get(2)); - writeByte(untyped helper.get(3)); - writeByte(untyped helper.get(4)); - writeByte(untyped helper.get(5)); - writeByte(untyped helper.get(6)); - writeByte(untyped helper.get(7)); - #else - if (x == 0.0) - { - writeByte(0); writeByte(0); writeByte(0); writeByte(0); - writeByte(0); writeByte(0); writeByte(0); writeByte(0); - return; - } - - var exp = Math.floor(Math.log(Math.abs(x)) / LN2); - var sig : Int = Math.floor(Math.abs(x) / Math.pow(2, exp) * Math.pow(2, 52)); - var sig_h = (sig & cast 34359738367); - var sig_l = Math.floor((sig / Math.pow(2,32))); - var b1 = (exp + 0x3FF) >> 4 | (exp>0 ? ((x<0) ? 1<<7 : 1<<6) : ((x<0) ? 1<<7 : 0)), - b2 = (exp + 0x3FF) << 4 & 0xFF | (sig_l >> 16 & 0xF), - b3 = (sig_l >> 8) & 0xFF, - b4 = sig_l & 0xFF, - b5 = (sig_h >> 24) & 0xFF, - b6 = (sig_h >> 16) & 0xFF, - b7 = (sig_h >> 8) & 0xFF, - b8 = sig_h & 0xFF; - if (bigEndian) - { - writeByte(b8); writeByte(b7); writeByte(b6); writeByte(b5); - writeByte(b4); writeByte(b3); writeByte(b2); writeByte(b1); - } - else - { - writeByte(b1); writeByte(b2); writeByte(b3); writeByte(b4); - writeByte(b5); writeByte(b6); writeByte(b7); writeByte(b8); + writeInt32(i64.low); + writeInt32(i64.high); } - #end } + /** + Write `x` as 8-bit signed integer. + **/ public function writeInt8( x : Int ) { if( x < -0x80 || x >= 0x80 ) throw Error.Overflow; writeByte(x & 0xFF); } + /** + Write `x` as 16-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ public function writeInt16( x : Int ) { if( x < -0x8000 || x >= 0x8000 ) throw Error.Overflow; writeUInt16(x & 0xFFFF); } + /** + Write `x` as 16-bit unsigned integer. + + Endianness is specified by the `bigEndian` property. + **/ public function writeUInt16( x : Int ) { if( x < 0 || x >= 0x10000 ) throw Error.Overflow; if( bigEndian ) { @@ -247,11 +185,21 @@ class Output { } } + /** + Write `x` as 24-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ public function writeInt24( x : Int ) { if( x < -0x800000 || x >= 0x800000 ) throw Error.Overflow; writeUInt24(x & 0xFFFFFF); } + /** + Write `x` as 24-bit unsigned integer. + + Endianness is specified by the `bigEndian` property. + **/ public function writeUInt24( x : Int ) { if( x < 0 || x >= 0x1000000 ) throw Error.Overflow; if( bigEndian ) { @@ -265,6 +213,11 @@ class Output { } } + /** + Write `x` as 32-bit signed integer. + + Endianness is specified by the `bigEndian` property. + **/ public function writeInt32( x : Int ) { if( bigEndian ) { writeByte( x >>> 24 ); @@ -280,7 +233,8 @@ class Output { } /** - Inform that we are about to write at least a specified number of bytes. + Inform that we are about to write at least `nbytes` bytes. + The underlying implementation can allocate proper working space depending on this information, or simply ignore it. This is not a mandatory call but a tip and is only used in some specific cases. @@ -288,6 +242,12 @@ class Output { public function prepare( nbytes : Int ) { } + /** + Read all available data from `i` and write it. + + The `bufsize` optional argument specifies the size of chunks by + which data is read and written. Its default value is 4096. + **/ public function writeInput( i : Input, ?bufsize : Int ) { if( bufsize == null ) bufsize = 4096; @@ -310,6 +270,9 @@ class Output { } } + /** + Write `s` string. + **/ public function writeString( s : String ) { #if neko var b = untyped new Bytes(s.length,s.__s); @@ -320,14 +283,9 @@ class Output { } #if neko - static var _float_bytes = neko.Lib.load("std","float_bytes",2); - static var _double_bytes = neko.Lib.load("std","double_bytes",2); static function __init__() untyped { Output.prototype.bigEndian = false; } -#elseif cpp - static var _float_bytes = cpp.Lib.load("std","float_bytes",2); - static var _double_bytes = cpp.Lib.load("std","double_bytes",2); #end } diff --git a/std/haxe/io/Path.hx b/std/haxe/io/Path.hx index 11914fefd4247c4325d3d6baefdb4e896725d930..8a8e9ad9c018503acfabb280bbc101887fd57ebc 100644 --- a/std/haxe/io/Path.hx +++ b/std/haxe/io/Path.hx @@ -24,55 +24,62 @@ package haxe.io; /** This class provides a convenient way of working with paths. It supports the common path formats: - directory1/directory2/filename.extension - directory1\directory2\filename.excention + + - directory1/directory2/filename.extension + - directory1\directory2\filename.excention **/ class Path { /** The directory. - + This is the leading part of the path that is not part of the file name and the extension. - - Does not end with a / or \ separator. - + + Does not end with a `/` or `\` separator. + If the path has no directory, the value is null. **/ public var dir : String; - + /** The file name. - + This is the part of the part between the directory and the extension. - + If there is no file name, e.g. for ".htaccess" or "/dir/", the value is the empty String "". **/ public var file : String; - + /** The file extension. - + It is separated from the file name by a dot. This dot is not part of the extension. - + If the path has no extension, the value is null. **/ public var ext : String; - + /** True if the last directory separator is a backslash, false otherwise. **/ public var backslash : Bool; /** - Creates a new Path instance by parsing [path]. - + Creates a new Path instance by parsing `path`. + Path information can be retrieved by accessing the dir, file and ext properties. **/ public function new( path : String ) { + switch (path) { + case "." | "..": + dir = path; + file = ""; + return; + } var c1 = path.lastIndexOf("/"); var c2 = path.lastIndexOf("\\"); if( c1 < c2 ) { @@ -95,13 +102,13 @@ class Path { } /** - Returns a String representation of [this] path. - - If [this].backslash is true, backslash is used as directory separator, + Returns a String representation of `this` path. + + If `this.backslash` is true, backslash is used as directory separator, otherwise slash is used. This only affects the separator between - [this].dir and [this].file. - - If [this].directory or [this].extension is null, their representation + `this.dir` and `this.file`. + + If `this.directory` or `this.extension` is null, their representation is the empty String "". **/ public function toString() { @@ -109,9 +116,9 @@ class Path { } /** - Returns the String representation of [path] without the file extension. - - If [path] is null, the result is unspecified. + Returns the String representation of `path` without the file extension. + + If `path` is null, the result is unspecified. **/ public static function withoutExtension( path : String ) { var s = new Path(path); @@ -120,9 +127,9 @@ class Path { } /** - Returns the String representation of [path] without the directory. - - If [path] is null, the result is unspecified. + Returns the String representation of `path` without the directory. + + If `path` is null, the result is unspecified. **/ public static function withoutDirectory( path ) { var s = new Path(path); @@ -131,11 +138,11 @@ class Path { } /** - Returns the directory of [path]. - + Returns the directory of `path`. + If the directory is null, the empty String "" is returned. - - If [path] is null, the result is unspecified. + + If `path` is null, the result is unspecified. **/ public static function directory( path ) { var s = new Path(path); @@ -145,11 +152,11 @@ class Path { } /** - Returns the extension of [path]. - + Returns the extension of `path`. + If the extension is null, the empty String "" is returned. - - If [path] is null, the result is unspecified. + + If `path` is null, the result is unspecified. **/ public static function extension( path ) { var s = new Path(path); @@ -159,11 +166,11 @@ class Path { } /** - Returns a String representation of [path] where the extension is [ext]. - - If [path] has no extension, [ext] is added as extension. - - If [path] or [ext] are null, the result is unspecified. + Returns a String representation of `path` where the extension is `ext`. + + If `path` has no extension, `ext` is added as extension. + + If `path` or `ext` are null, the result is unspecified. **/ public static function withExtension( path, ext ) { var s = new Path(path); @@ -172,16 +179,88 @@ class Path { } /** - Adds a trailing slash to [path], if it does not have one already. - - If the last slash in [path] is a backslash, a backslash is appended to - [path]. - - If the last slash in [path] is a slash, or if no slash is found, a slash - is appended to [path]. In particular, this applies to the empty String + Joins all paths in `paths` together. + + If `paths` is empty, the empty String `""` is returned. Otherwise the + paths are joined with a slash between them. + + If `paths` is null, the result is unspecified. + **/ + public static function join(paths:Array) : String { + var paths = paths.filter(function(s) return s != null && s != ""); + if (paths.length == 0) { + return ""; + } + var path = paths[0]; + for (i in 1...paths.length) { + path = addTrailingSlash(path); + path += paths[i]; + } + return normalize(path); + } + + /** + Normalize a given `path` (e.g. make '/usr/local/../lib' to '/usr/lib'). + + Also replaces backslashes \ with slashes / and afterwards turns + multiple slashes into a single one. + + If `path` is null, the result is unspecified. + **/ + public static function normalize(path : String) : String { + var slash = '/'; + path = path.split("\\").join("/"); + if( path == null || path == slash ) { + return slash; + } + + var target = []; + + for( token in path.split(slash) ) { + if(token == '..' && target.length > 0 && target[target.length-1] != "..") { + target.pop(); + } else if(token != '.') { + target.push(token); + } + } + + var tmp = target.join(slash); + var regex = ~/([^:])\/+/g; + var result = regex.replace(tmp, "$1" +slash); + var acc = new StringBuf(); + var colon = false; + var slashes = false; + for (i in 0...tmp.length) { + switch (tmp.charCodeAt(i)) { + case ":".code: + acc.add(":"); + colon = true; + case "/".code if (colon == false): + slashes = true; + case i: + colon = false; + if (slashes) { + acc.add("/"); + slashes = false; + } + acc.add(String.fromCharCode(i)); + } + } + var result = acc.toString(); + return result; + } + + /** + Adds a trailing slash to `path`, if it does not have one already. + + If the last slash in `path` is a backslash, a backslash is appended to + `path`. + + If the last slash in `path` is a slash, or if no slash is found, a slash + is appended to `path`. In particular, this applies to the empty String "". - - If [path] is null, the result is unspecified. + + If `path` is null, the result is unspecified. **/ public static function addTrailingSlash( path : String ) : String { if (path.length == 0) @@ -196,4 +275,45 @@ class Path { else path; } } -} \ No newline at end of file + + /** + Removes trailing slashes from `path`. + + If `path` does not end with a `/` or `\`, `path` is returned unchanged. + + Otherwise the substring of `path` excluding the trailing slashes or + backslashes is returned. + + If `path` is null, the result is unspecified. + **/ + @:require(haxe_ver >= 3.1) + public static function removeTrailingSlashes ( path : String ) : String { + while (true) { + switch(path.charCodeAt(path.length - 1)) { + case '/'.code | '\\'.code: path = path.substr(0, -1); + case _: break; + } + } + return path; + } + + /** + Returns true if the path is an absolute path, and false otherwise. + **/ + @:require(haxe_ver >= 3.2) + public static function isAbsolute ( path : String ) : Bool { + if (StringTools.startsWith(path, '/')) return true; + if (path.charAt(1) == ':') return true; + return false; + } + + private static function unescape( path : String ) : String { + var regex = ~/-x([0-9][0-9])/g; + return regex.map(path, function(regex) return String.fromCharCode(Std.parseInt(regex.matched(1)))); + } + + private static function escape( path : String, allowSlashes : Bool = false ) : String { + var regex = allowSlashes ? ~/[^A-Za-z0-9_\/\\\.]/g : ~/[^A-Za-z0-9_\.]/g; + return regex.map(path, function(v) return '-x' + v.matched(0).charCodeAt(0)); + } +} diff --git a/std/haxe/io/UInt16Array.hx b/std/haxe/io/UInt16Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..6fad64a069bd9ea5a3b80b67f33ad6778548c395 --- /dev/null +++ b/std/haxe/io/UInt16Array.hx @@ -0,0 +1,85 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt16ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract UInt16Array(UInt16ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 2; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength >> 1; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Int { + return this.bytes.getUInt16((index<<1) + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + if( index >= 0 && index < length ) { + this.bytes.setUInt16((index<<1) + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : UInt16Array { + return fromData(this.sub(begin<<1,length == null ? null : length<<1)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt16Array { + return fromData(this.subarray(begin==null?null:begin<<1,end==null?null:end<<1)); + } + + public inline function getData() : UInt16ArrayData { + return this; + } + + public static function fromData( d : UInt16ArrayData ) : UInt16Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : UInt16Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new UInt16Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos = 0, ?length : Int ) : UInt16Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,(length == null ? (bytes.length - bytePos)>>1 : length)<<1).getData()); + } +} + diff --git a/std/haxe/io/UInt32Array.hx b/std/haxe/io/UInt32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..fe2c5a85c83b0353fede0e136e0a3f24d7740e53 --- /dev/null +++ b/std/haxe/io/UInt32Array.hx @@ -0,0 +1,85 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt32ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract UInt32Array(UInt32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength >> 2; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : UInt { + return this.bytes.getInt32((index<<2) + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : UInt ) : UInt { + if( index >= 0 && index < length ) { + this.bytes.setInt32((index<<2) + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : UInt32Array { + return fromData(this.sub(begin<<2,length == null ? null : length<<2)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt32Array { + return fromData(this.subarray(begin==null?null:begin<<2,end==null?null:end<<2)); + } + + public inline function getData() : UInt32ArrayData { + return this; + } + + public static function fromData( d : UInt32ArrayData ) : UInt32Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : UInt32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new UInt32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos = 0, ?length : Int ) : UInt32Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,(length == null ? (bytes.length - bytePos)>>2 : length)<<2).getData()); + } +} + diff --git a/std/haxe/io/UInt8Array.hx b/std/haxe/io/UInt8Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..e40a6727696f0478670e152b494d986244551d88 --- /dev/null +++ b/std/haxe/io/UInt8Array.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt8ArrayData = ArrayBufferView.ArrayBufferViewData; + +abstract UInt8Array(UInt8ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 1; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new ArrayBufferView(elements * BYTES_PER_ELEMENT).getData(); + } + + inline function get_length() { + return this.byteLength; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) { + return this.bytes.get(index + this.byteOffset); + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + if( index >= 0 && index < length ) { + this.bytes.set(index + this.byteOffset, value); + return value; + } + return 0; + } + + public inline function sub( begin : Int, ?length : Int ) : UInt8Array { + return fromData(this.sub(begin,length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt8Array { + return fromData(this.subarray(begin,end)); + } + + public inline function getData() : UInt8ArrayData { + return this; + } + + public static function fromData( d : UInt8ArrayData ) : UInt8Array { + return cast d; + } + + public static function fromArray( a : Array, pos = 0, ?length : Int ) : UInt8Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + var i = new UInt8Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : UInt8Array { + return fromData(ArrayBufferView.fromBytes(bytes,bytePos,length).getData()); + } + +} + diff --git a/std/haxe/macro/Compiler.hx b/std/haxe/macro/Compiler.hx index ffc48f20f7e0cb01da551a511b9343fedb4fecdc..b6be64944e7d2aeb4b356e03fe05ff4c302f96bf 100644 --- a/std/haxe/macro/Compiler.hx +++ b/std/haxe/macro/Compiler.hx @@ -1,315 +1,352 @@ -/* - * Copyright (C)2005-2012 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.macro; -import haxe.macro.Expr; - -/** - All these methods can be called for compiler configuration macros. -**/ -class Compiler { - - macro static public function getDefine( key : String ) { - return macro $v{haxe.macro.Context.definedValue(key)}; - } - -#if neko - - static var ident = ~/^[A-Za-z_][A-Za-z0-9_]*$/; - static var path = ~/^[A-Za-z_][A-Za-z0-9_.]*$/; - - public static function allowPackage( v : String ) { - untyped load("allow_package", 1)(v.__s); - } - - public static function define( flag : String, ?value : String ) untyped { - var v = flag + (value == null ? "" : "= " + value); - load("define", 1)(v.__s); - } - - public static function removeField( className : String, field : String, ?isStatic : Bool ) { - if( !path.match(className) ) throw "Invalid "+className; - if( !ident.match(field) ) throw "Invalid "+field; - untyped load("type_patch",4)(className.__s,field.__s,isStatic == true,null); - } - - public static function setFieldType( className : String, field : String, type : String, ?isStatic : Bool ) { - if( !path.match(className) ) throw "Invalid "+className; - if( !ident.match((field.charAt(0) == "$") ? field.substr(1) : field) ) throw "Invalid "+field; - untyped load("type_patch",4)(className.__s,field.__s,isStatic == true,type.__s); - } - - public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) { - if( !path.match(className) ) throw "Invalid "+className; - if( field != null && !ident.match(field) ) throw "Invalid "+field; - untyped load("meta_patch",4)(meta.__s,className.__s,(field == null)?null:field.__s,isStatic == true); - } - - public static function addClassPath( path : String ) { - untyped load("add_class_path",1)(path.__s); - } - - public static function getOutput() : String { - return new String(untyped load("get_output",0)()); - } - - public static function setOutput( fileOrDir : String ) { - untyped load("set_output",1)(untyped fileOrDir.__s); - } - - public static function getDisplayPos() : Null<{ file : String, pos : Int }> { - var o = untyped load("get_display_pos",0)(); - if( o != null ) - o.file = new String(o.file); - return o; - } - - /** - Adds a native library depending on the platform (eg : -swf-lib for Flash) - **/ - public static function addNativeLib( name : String ) { - untyped load("add_native_lib",1)(name.__s); - } - - /** - Include for compilation all classes defined in the given package excluding the ones referenced in the ignore list. - **/ - public static function include( pack : String, ?rec = true, ?ignore : Array, ?classPaths : Array ) { - var skip = if( ignore == null ) { - function(c) return false; - } else { - function(c) return Lambda.has(ignore, c); - } - if( classPaths == null ) { - classPaths = Context.getClassPath(); - // do not force inclusion when using completion - if( Context.defined("display") ) - return; - // normalize class path - for( i in 0...classPaths.length ) { - var cp = StringTools.replace(classPaths[i], "\\", "/"); - if(StringTools.endsWith(cp, "/")) - cp = cp.substr(0, -1); - if( cp == "" ) - cp = "."; - classPaths[i] = cp; - } - } - var prefix = pack == '' ? '' : pack + '.'; - for( cp in classPaths ) { - var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/"); - if( !sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path) ) - continue; - for( file in sys.FileSystem.readDirectory(path) ) { - if( StringTools.endsWith(file, ".hx") ) { - var cl = prefix + file.substr(0, file.length - 3); - if( skip(cl) ) - continue; - Context.getModule(cl); - } else if( rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file) ) - include(prefix + file, true, ignore, classPaths); - } - } - } - - /** - Exclude a given class or a complete package from being generated. - **/ - public static function exclude( pack : String, ?rec = true ) { - Context.onGenerate(function(types) { - for( t in types ) { - var b : Type.BaseType, name; - switch( t ) { - case TInst(c, _): - name = c.toString(); - b = c.get(); - case TEnum(e, _): - name = e.toString(); - b = e.get(); - default: continue; - } - var p = b.pack.join("."); - if( (p == pack || name == pack) || (rec && StringTools.startsWith(p, pack + ".")) ) - b.exclude(); - } - }); - } - - /** - Exclude classes listed in an extern file (one per line) from being generated. - **/ - public static function excludeFile( fileName : String ) { - fileName = Context.resolvePath(fileName); - var f = sys.io.File.read(fileName,true); - var classes = new haxe.ds.StringMap(); - try { - while( true ) { - var l = StringTools.trim(f.readLine()); - if( l == "" || !~/[A-Za-z0-9._]/.match(l) ) - continue; - classes.set(l,true); - } - } catch( e : haxe.io.Eof ) { - } - Context.onGenerate(function(types) { - for( t in types ) { - switch( t ) { - case TInst(c, _): if( classes.exists(c.toString()) ) c.get().exclude(); - case TEnum(e, _): if( classes.exists(e.toString()) ) e.get().exclude(); - default: - } - } - }); - } - - /** - Load a type patch file that can modify declared classes fields types - **/ - public static function patchTypes( file : String ) : Void { - var file = Context.resolvePath(file); - var f = sys.io.File.read(file, true); - try { - while( true ) { - var r = StringTools.trim(f.readLine()); - if( r == "" || r.substr(0,2) == "//" ) continue; - if( StringTools.endsWith(r,";") ) r = r.substr(0,-1); - if( r.charAt(0) == "-" ) { - r = r.substr(1); - var isStatic = StringTools.startsWith(r,"static "); - if( isStatic ) r = r.substr(7); - var p = r.split("."); - var field = p.pop(); - removeField(p.join("."),field,isStatic); - continue; - } - if( r.charAt(0) == "@" ) { - var rp = r.split(" "); - var type = rp.pop(); - var isStatic = rp[rp.length - 1] == "static"; - if( isStatic ) rp.pop(); - var meta = rp.join(" "); - var p = type.split("."); - var field = if( p.length > 1 && p[p.length-2].charAt(0) >= "a" ) null else p.pop(); - addMetadata(meta,p.join("."),field,isStatic); - continue; - } - if( StringTools.startsWith(r, "enum ") ) { - define("fakeEnum:" + r.substr(5)); - continue; - } - var rp = r.split(" : "); - if( rp.length > 1 ) { - r = rp.shift(); - var isStatic = StringTools.startsWith(r,"static "); - if( isStatic ) r = r.substr(7); - var p = r.split("."); - var field = p.pop(); - setFieldType(p.join("."),field,rp.join(" : "),isStatic); - continue; - } - throw "Invalid type patch "+r; - } - } catch( e : haxe.io.Eof ) { - } - } - - /** - Mark a class (or array of classes) with the metadata @:keep. - - Note that this does not imply inclusion of the class(es): If a class is - neither referenced nor added via [Compiler.include], it will not be part - of the output even if @:keep was added. - **/ - public static function keep(?path : String, ?paths : Array, rec = false) - { - if (null == paths) - paths = []; - if (null != path) - paths.push(path); - for (path in paths) - { - for ( p in Context.getClassPath() ) { - var p = p + path.split(".").join("/"); - if (sys.FileSystem.exists(p) && sys.FileSystem.isDirectory(p)) - { - for( file in sys.FileSystem.readDirectory(p) ) { - if( StringTools.endsWith(file, ".hx") ) { - var module = path + "." + file.substr(0, file.length - 3); - var types = Context.getModule(module); - for (type in types) - { - switch(type) - { - case TInst(cls, _): - addMetadata("@:keep", cls.toString()); - default: - // - } - } - } else if( rec && sys.FileSystem.isDirectory(p + "/" + file) ) - keep(path + "." + file, true); - } - } else { - addMetadata("@:keep", path); - break; - } - } - } - } - - /** - Change the default JS output by using a custom generator callback - **/ - public static function setCustomJSGenerator( callb : JSGenApi -> Void ) { - load("custom_js",1)(callb); - } - - static function load( f, nargs ) : Dynamic { - #if macro - return neko.Lib.load("macro", f, nargs); - #else - return Reflect.makeVarArgs(function(_) return throw "Can't be called outside of macro"); - #end - } - -#end - - #if (js || macro) - /** - Embed an on-disk javascript file (can be called into an __init__ method) - **/ - public static macro function includeFile( fileName : Expr ) { - var str = switch( fileName.expr ) { - case EConst(c): - switch( c ) { - case CString(str): str; - default: null; - } - default: null; - } - if( str == null ) Context.error("Should be a constant string", fileName.pos); - var f = try sys.io.File.getContent(Context.resolvePath(str)) catch( e : Dynamic ) Context.error(Std.string(e), fileName.pos); - var p = Context.currentPos(); - return { expr : EUntyped( { expr : ECall( { expr : EConst(CIdent("__js__")), pos : p }, [ { expr : EConst(CString(f)), pos : p } ]), pos : p } ), pos : p }; - } - #end - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.macro; +import haxe.macro.Expr; + +/** + All these methods can be called for compiler configuration macros. +**/ +class Compiler { + + macro static public function getDefine( key : String ) { + return macro $v{haxe.macro.Context.definedValue(key)}; + } + +#if neko + + static var ident = ~/^[A-Za-z_][A-Za-z0-9_]*$/; + static var path = ~/^[A-Za-z_][A-Za-z0-9_.]*$/; + + public static function allowPackage( v : String ) { + untyped load("allow_package", 1)(v.__s); + } + + public static function define( flag : String, ?value : String ) untyped { + var v = flag + (value == null ? "" : "=" + value); + load("define", 1)(v.__s); + } + + public static function removeField( className : String, field : String, ?isStatic : Bool ) { + if( !path.match(className) ) throw "Invalid "+className; + if( !ident.match(field) ) throw "Invalid "+field; + untyped load("type_patch",4)(className.__s,field.__s,isStatic == true,null); + } + + public static function setFieldType( className : String, field : String, type : String, ?isStatic : Bool ) { + if( !path.match(className) ) throw "Invalid "+className; + if( !ident.match((field.charAt(0) == "$") ? field.substr(1) : field) ) throw "Invalid "+field; + untyped load("type_patch",4)(className.__s,field.__s,isStatic == true,type.__s); + } + + public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) { + if( !path.match(className) ) throw "Invalid "+className; + if( field != null && !ident.match(field) ) throw "Invalid "+field; + untyped load("meta_patch",4)(meta.__s,className.__s,(field == null)?null:field.__s,isStatic == true); + } + + public static function addClassPath( path : String ) { + untyped load("add_class_path",1)(path.__s); + } + + public static function getOutput() : String { + return new String(untyped load("get_output",0)()); + } + + public static function setOutput( fileOrDir : String ) { + untyped load("set_output",1)(untyped fileOrDir.__s); + } + + public static function getDisplayPos() : Null<{ file : String, pos : Int }> { + var o = untyped load("get_display_pos",0)(); + if( o != null ) + o.file = new String(o.file); + return o; + } + + /** + Adds a native library depending on the platform (eg : -swf-lib for Flash) + **/ + public static function addNativeLib( name : String ) { + untyped load("add_native_lib",1)(name.__s); + } + + /** + Adds an argument to be passed to the native compiler (eg : -javac-arg for Java) + **/ + public static function addNativeArg( argument : String ) + { + untyped load("add_native_arg",1)(argument.__s); + } + + /** + Includes all modules in package `pack` in the compilation. + + In order to include single modules, their paths can be listed directly + on command line: `haxe ... ModuleName pack.ModuleName`. + + By default `Compiler.include` will search for modules in the directories defined with `-cp`. + If you want to specify a different set of paths to search for modules, you can use the optional + argument `classPath`. + + @param rec If true, recursively adds all sub-packages. + @param ignore Array of module names to ignore for inclusion. + @param classPaths An alternative array of paths (directory names) to use to search for modules to include. + Note that if you pass this argument, only the specified paths will be used for inclusion. + **/ + public static function include( pack : String, ?rec = true, ?ignore : Array, ?classPaths : Array ) { + var skip = if( ignore == null ) { + function(c) return false; + } else { + function(c) return Lambda.has(ignore, c); + } + var displayValue = Context.definedValue("display"); + if( classPaths == null ) { + classPaths = Context.getClassPath(); + // do not force inclusion when using completion + switch (displayValue) { + case null: + case "usage": + case _: return; + } + // normalize class path + for( i in 0...classPaths.length ) { + var cp = StringTools.replace(classPaths[i], "\\", "/"); + if(StringTools.endsWith(cp, "/")) + cp = cp.substr(0, -1); + if( cp == "" ) + cp = "."; + classPaths[i] = cp; + } + } + var prefix = pack == '' ? '' : pack + '.'; + for( cp in classPaths ) { + var path = pack == '' ? cp : cp + "/" + pack.split(".").join("/"); + if( !sys.FileSystem.exists(path) || !sys.FileSystem.isDirectory(path) ) + continue; + for( file in sys.FileSystem.readDirectory(path) ) { + if( StringTools.endsWith(file, ".hx") ) { + var cl = prefix + file.substr(0, file.length - 3); + if( skip(cl) ) + continue; + Context.getModule(cl); + } else if( rec && sys.FileSystem.isDirectory(path + "/" + file) && !skip(prefix + file) ) + include(prefix + file, true, ignore, classPaths); + } + } + } + + /** + Exclude a class or a enum without changing it to @:nativeGen. + **/ + static function excludeBaseType( baseType : Type.BaseType ) : Void { + if (!baseType.isExtern) { + var meta = baseType.meta; + if (!meta.has(":nativeGen")) { + meta.add(":hxGen", [], baseType.pos); + } + baseType.exclude(); + } + } + + /** + Exclude a given class or a complete package from being generated. + **/ + public static function exclude( pack : String, ?rec = true ) { + Context.onGenerate(function(types) { + for( t in types ) { + var b : Type.BaseType, name; + switch( t ) { + case TInst(c, _): + name = c.toString(); + b = c.get(); + case TEnum(e, _): + name = e.toString(); + b = e.get(); + default: continue; + } + var p = b.pack.join("."); + if( (p == pack || name == pack) || (rec && StringTools.startsWith(p, pack + ".")) ) + excludeBaseType(b); + } + }); + } + + /** + Exclude classes listed in an extern file (one per line) from being generated. + **/ + public static function excludeFile( fileName : String ) { + fileName = Context.resolvePath(fileName); + var f = sys.io.File.read(fileName,true); + var classes = new haxe.ds.StringMap(); + try { + while( true ) { + var l = StringTools.trim(f.readLine()); + if( l == "" || !~/[A-Za-z0-9._]/.match(l) ) + continue; + classes.set(l,true); + } + } catch( e : haxe.io.Eof ) { + } + Context.onGenerate(function(types) { + for( t in types ) { + switch( t ) { + case TInst(c, _): if( classes.exists(c.toString()) ) excludeBaseType(c.get()); + case TEnum(e, _): if( classes.exists(e.toString()) ) excludeBaseType(e.get()); + default: + } + } + }); + } + + /** + Load a type patch file that can modify declared classes fields types + **/ + public static function patchTypes( file : String ) : Void { + var file = Context.resolvePath(file); + var f = sys.io.File.read(file, true); + try { + while( true ) { + var r = StringTools.trim(f.readLine()); + if( r == "" || r.substr(0,2) == "//" ) continue; + if( StringTools.endsWith(r,";") ) r = r.substr(0,-1); + if( r.charAt(0) == "-" ) { + r = r.substr(1); + var isStatic = StringTools.startsWith(r,"static "); + if( isStatic ) r = r.substr(7); + var p = r.split("."); + var field = p.pop(); + removeField(p.join("."),field,isStatic); + continue; + } + if( r.charAt(0) == "@" ) { + var rp = r.split(" "); + var type = rp.pop(); + var isStatic = rp[rp.length - 1] == "static"; + if( isStatic ) rp.pop(); + var meta = rp.join(" "); + var p = type.split("."); + var field = if( p.length > 1 && p[p.length-2].charAt(0) >= "a" ) null else p.pop(); + addMetadata(meta,p.join("."),field,isStatic); + continue; + } + if( StringTools.startsWith(r, "enum ") ) { + define("fakeEnum:" + r.substr(5)); + continue; + } + var rp = r.split(" : "); + if( rp.length > 1 ) { + r = rp.shift(); + var isStatic = StringTools.startsWith(r,"static "); + if( isStatic ) r = r.substr(7); + var p = r.split("."); + var field = p.pop(); + setFieldType(p.join("."),field,rp.join(" : "),isStatic); + continue; + } + throw "Invalid type patch "+r; + } + } catch( e : haxe.io.Eof ) { + } + } + + /** + Marks types or packages to be kept by DCE. + + This also extends to the sub-types of resolved modules. + + In order to include module sub-types directly, their full dot path + including the containing module has to be used + (e.g. msignal.Signal.Signal0). + + This operation has no effect if the type has already been loaded, e.g. + through `Context.getType`. + + @param path A package, module or sub-type dot path to keep. + @param paths An Array of package, module or sub-type dot paths to keep. + @param recursive If true, recurses into sub-packages for package paths. + **/ + public static function keep(?path : String, ?paths : Array, ?recursive:Bool = true) { + if (null == paths) + paths = []; + if (null != path) + paths.push(path); + for (path in paths) { + addGlobalMetadata(path, "@:keep", recursive, true, true); + } + } + + /** + Adds metadata `meta` to all types (if `toTypes = true`) or fields (if + `toFields = true`) whose dot-path matches `pathFilter`. + + If `recursive` is true a dot-path is considered matched if it starts + with `pathFilter`. This automatically applies to path filters of + packages. Otherwise an exact match is required. + + If `pathFilter` is the empty String `""` it matches everything (if + `recursive = true`) or only top-level types (if `recursive = false`). + + This operation has no effect if the type has already been loaded, e.g. + through `Context.getType`. + **/ + public static function addGlobalMetadata(pathFilter:String, meta:String, ?recursive:Bool = true, ?toTypes:Bool = true, ?toFields:Bool = false) { + untyped load("add_global_metadata",5)(untyped pathFilter.__s, meta.__s, recursive, toTypes, toFields); + } + + /** + Change the default JS output by using a custom generator callback + **/ + public static function setCustomJSGenerator( callb : JSGenApi -> Void ) { + load("custom_js",1)(callb); + } + + static function load( f, nargs ) : Dynamic { + #if macro + return neko.Lib.load("macro", f, nargs); + #else + return Reflect.makeVarArgs(function(_) return throw "Can't be called outside of macro"); + #end + } + +#end + + #if (js || macro) + /** + Embed an on-disk javascript file (can be called into an __init__ method) + **/ + public static macro function includeFile( fileName : Expr ) { + var str = switch( fileName.expr ) { + case EConst(c): + switch( c ) { + case CString(str): str; + default: null; + } + default: null; + } + if( str == null ) Context.error("Should be a constant string", fileName.pos); + var f = try sys.io.File.getContent(Context.resolvePath(str)) catch( e : Dynamic ) Context.error(Std.string(e), fileName.pos); + var p = Context.currentPos(); + return { expr : EUntyped( { expr : ECall( { expr : EConst(CIdent("__js__")), pos : p }, [ { expr : EConst(CString(f)), pos : p } ]), pos : p } ), pos : p }; + } + #end + +} diff --git a/std/haxe/macro/ComplexTypeTools.hx b/std/haxe/macro/ComplexTypeTools.hx index 591a23d5143b66fc8ef9c356bf3ce7ab5603c426..e4682f004954dfb8f775c8a0f66549a0312c784a 100644 --- a/std/haxe/macro/ComplexTypeTools.hx +++ b/std/haxe/macro/ComplexTypeTools.hx @@ -1,54 +1,54 @@ -/* - * Copyright (C)2005-2013 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.macro; - -import haxe.macro.Expr; - -/** - This class provides some utility methods to work with AST-level types. It is - best used through 'using haxe.macro.ComplexTypeTools' syntax and then provides - additional methods on haxe.macro.Expr.ComplexType instances. -**/ -class ComplexTypeTools { - - /** - Converts type [c] to a human-readable String representation. - - The result is guaranteed to be valid haxe code, but there may be - differences from the original lexical syntax. - **/ - static public function toString( c : ComplexType ) : String - return new Printer().printComplexType(c); - - #if macro - - /** - Returns a type corresponding to [c]. - - If [c] is null, the result is null. - **/ - static public function toType( c : ComplexType ) : Null - return c == null ? null : haxe.macro.Context.typeof( { expr: ECheckType(macro null, c), pos: Context.currentPos() } ); - - #end +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Expr; + +/** + This class provides some utility methods to work with AST-level types. It is + best used through 'using haxe.macro.ComplexTypeTools' syntax and then provides + additional methods on haxe.macro.Expr.ComplexType instances. +**/ +class ComplexTypeTools { + + /** + Converts type [c] to a human-readable String representation. + + The result is guaranteed to be valid haxe code, but there may be + differences from the original lexical syntax. + **/ + static public function toString( c : ComplexType ) : String + return new Printer().printComplexType(c); + + #if macro + + /** + Returns a type corresponding to [c]. + + If [c] is null, the result is null. + **/ + static public function toType( c : ComplexType ) : Null + return c == null ? null : haxe.macro.Context.typeof( { expr: ECheckType(macro null, c), pos: Context.currentPos() } ); + + #end } \ No newline at end of file diff --git a/std/haxe/macro/Context.hx b/std/haxe/macro/Context.hx index 38f52a444a9cd59ef843d1ebb325dda5508e09db..f38b45d54650cad04aae5b9cae24ab378c0d19db 100644 --- a/std/haxe/macro/Context.hx +++ b/std/haxe/macro/Context.hx @@ -1,293 +1,528 @@ -/* - * Copyright (C)2005-2012 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.macro; -import haxe.macro.Expr; - -/** - This is an API that can be used by macros implementations. -**/ -#if !neko @:noDoc #end -class Context { - -#if neko - /** - Display a compilation error at the given position in code and abort the current macro call - **/ - public static function error( msg : String, pos : Position ) : Dynamic { - return load("error",2)(untyped msg.__s, pos); - } - - /** - Display a compilation warning at the given position in code - **/ - public static function warning( msg : String, pos : Position ) { - load("warning",2)(untyped msg.__s, pos); - } - - /** - Resolve a filename based on current classpath. - **/ - public static function resolvePath( file : String ) { - return new String(load("resolve",1)(untyped file.__s)); - } - - /** - Return the current classpath - **/ - public static function getClassPath() : Array { - var c : neko.NativeArray = load("class_path",0)(); - var a = new Array(); - for( i in 0...neko.NativeArray.length(c) ) - a.push(Std.string(c[i])); - return a; - } - - /** - Returns the position at which the macro is called - **/ - public static function currentPos() : Position { - return load("curpos", 0)(); - } - - /** - Returns the current class in which the macro is called - **/ - public static function getLocalClass() : Null> { - var l : Type = load("local_type", 0)(); - if( l == null ) return null; - return switch( l ) { - case TInst(c,_): c; - default: null; - } - } - - /** - Returns the current type in/on which the macro is called - **/ - public static function getLocalType() : Null { - var l : Type = load("local_type", 0)(); - if( l == null ) return null; - return l; - } - - /** - Returns the name of the method from which the macro was called - **/ - public static function getLocalMethod() : Null { - var l : String = load("local_method", 0)(); - if (l == "") return null; - return new String(l); - } - - /** - Returns classes which are available for "using" where the macro was called - **/ - public static function getLocalUsing() : Array> { - return load("local_using", 0)(); - } - - /** - Returns local variables accessible where the macro was called - **/ - public static function getLocalVars() : haxe.ds.StringMap { - return load("local_vars", 0)(); - } - - /** - Tells is the given compiler directive has been defined with -D - **/ - public static function defined( s : String ) : Bool { - return load("defined", 1)(untyped s.__s); - } - - /** - Returns the value defined through -D key=value - **/ - public static function definedValue( key : String ) : String { - return new String(load("defined_value", 1)(untyped key.__s)); - } - - /** - Resolve a type from its name. - **/ - public static function getType( name : String ) : Type { - return load("get_type", 1)(untyped name.__s); - } - - /** - Return the list of types defined in the given compilation unit module - **/ - public static function getModule( name : String ) : Array { - return load("get_module", 1)(untyped name.__s); - } - - /** - Parse a constructed string into the corresponding expression. - **/ - public static function parse( expr : String, pos : Position ) : Expr { - return load("parse", 3)(untyped expr.__s, pos, false); - } - - /** - Parse a string contained into source code into the corresponding expression. Errors positions are reported within this string - **/ - public static function parseInlineString( expr : String, pos : Position ) : Expr { - return load("parse", 3)(untyped expr.__s, pos, true); - } - - /** - Build an expression corresponding to the given runtime value. Only basic types + enums are supported. - **/ - public static function makeExpr( v : Dynamic, pos : Position ) : Expr { - return load("make_expr", 2)(v, pos); - } - - /** - Quickly build an hashed MD5 signature for any given value - **/ - public static function signature( v : Dynamic ) : String { - return new String(load("signature", 1)(v)); - } - - /** - Set a callback function that will return all the types compiled before they get generated. - **/ - public static function onGenerate( callb : Array -> Void ) { - load("on_generate",1)(callb); - } - - /** - Set a callback function that will be called when a type cannot be found. - **/ - public static function onTypeNotFound ( callb : String -> TypeDefinition ) { - load("on_type_not_found",1)(callb); - } - - /** - Evaluate the type a given expression would have in the context of the current macro call. - **/ - public static function typeof( e : Expr ) : Type { - return load("typeof", 1)(e); - } - - /** - Returns the ComplexType corresponding to the given Type. - **/ - public static function toComplexType( t : Type ) : Null { - return load("to_complex", 1)(t); - } - - /** - Returns true if t1 and t2 unify, false otherwise - **/ - public static function unify( t1 : Type, t2 : Type) : Bool { - return load("unify", 2)(t1, t2); - } - - /** - Follow all typedefs to reach the actual real type - **/ - public static function follow( t : Type, ?once : Bool ) : Type { - return load("follow", 2)(t,once); - } - - /** - Get the informations stored into a given position. - **/ - public static function getPosInfos( p : Position ) : { min : Int, max : Int, file : String } { - var i = load("get_pos_infos",1)(p); - i.file = new String(i.file); - return i; - } - - /** - Build a position with the given informations. - **/ - public static function makePosition( inf : { min : Int, max : Int, file : String } ) : Position { - return load("make_pos",3)(inf.min,inf.max,untyped inf.file.__s); - } - - /** - Add or modify a resource that will be accessible with haxe.Resource api. - **/ - public static function addResource( name : String, data : haxe.io.Bytes ) { - load("add_resource",2)(untyped name.__s,data.getData()); - } - - /** - Returns the list of fields for the current type inside the build macro. - **/ - public static function getBuildFields() : Array { - return load("build_fields", 0)(); - } - - /** - Define a new type based on the given definition. - **/ - public static function defineType( t : TypeDefinition ) : Void { - load("define_type", 1)(t); - } - - - /** - Return the raw expression corresponding to the given typed expression. - **/ - public static function getTypedExpr( t : Type.TypedExpr ) : Expr { - return load("get_typed_expr",1)(t); - } - - /** - Manually add a dependency between a module and a third party file : - make sure the module gets recompiled (if it was cached) in case the extern file has been modified as well. - **/ - public static function registerModuleDependency( modulePath : String, externFile : String ) { - load("module_dependency", 2)(untyped modulePath.__s,untyped externFile.__s); - } - - /** - Add a macro call to perform in case the module is reused by the compilation cache. - **/ - public static function registerModuleReuseCall( modulePath : String, macroCall : String ) { - load("module_reuse_call", 2)(untyped modulePath.__s,untyped macroCall.__s); - } - - /** - Register a callback function that will be called everytime the macro context cached is reused with a new - compilation. This enable to reset some static vars since the code might have been changed. If the callback - returns false, the macro context is discarded and another one is created. - **/ - public static function onMacroContextReused( callb : Void -> Bool ) { - load("macro_context_reused", 1)(callb); - } - - @:allow(haxe.macro.TypeTools) - static function load( f, nargs ) : Dynamic { - #if macro - return neko.Lib.load("macro", f, nargs); - #else - return Reflect.makeVarArgs(function(_) return throw "Can't be called outside of macro"); - #end - } - -#end - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.macro; + +import haxe.macro.Expr; +import haxe.macro.Type.TypedExpr; + +/** + Context provides an API for macro programming. + + It contains common functions that interact with the macro interpreter to + query or set information. Other API functions are available in the tools + classes: + + - `haxe.macro.ComplexTypeTools` + - `haxe.macro.ExprTools` + - `haxe.macro.TypeTools` +**/ +#if !neko @:noDoc #end +class Context { + +#if neko + /** + Displays a compilation error `msg` at the given `Position` `pos` + and aborts the current macro call. + **/ + public static function error( msg : String, pos : Position ) : Dynamic { + return load("error",2)(untyped msg.__s, pos); + } + + /** + Displays a compilation error `msg` at the given `Position` `pos` + and aborts the compilation. + **/ + public static function fatalError( msg : String, pos : Position ) : Dynamic { + return load("fatal_error",2)(untyped msg.__s, pos); + } + + /** + Displays a compilation warning `msg` at the given `Position` `pos`. + **/ + public static function warning( msg : String, pos : Position ) { + load("warning",2)(untyped msg.__s, pos); + } + + /** + Resolves a file name `file` based on the current class paths. + + The resolution follows the usual class path rules where the last + declared class path has priority. + + If a class path was declared relative, this method returns the relative + file path. Otherwise it returns the absolute file path. + **/ + public static function resolvePath( file : String ) { + return new String(load("resolve",1)(untyped file.__s)); + } + + /** + Returns an `Array` of current class paths in the order of their + declaration. + + Modifying the returned array has no effect on the compiler. Class paths + can be added using `haxe.macro.Compiler.addClassPath`. + **/ + public static function getClassPath() : Array { + var c : neko.NativeArray = load("class_path",0)(); + var a = new Array(); + for( i in 0...neko.NativeArray.length(c) ) + a.push(Std.string(c[i])); + return a; + } + + /** + Returns the position at which the macro was called. + **/ + public static function currentPos() : Position { + return load("curpos", 0)(); + } + + /** + Returns the type which is expected at the place the macro is called. + + This affects usages such as `var x:Int = macroCall()`, where the + expected type will be reported as Int. + + Might return null if no specific type is expected or if the calling + macro is not an expression-macro. + **/ + @:require(haxe_ver >= 3.1) + public static function getExpectedType():Null { + var l : Type = load("expected_type", 0)(); + if( l == null ) return null; + return l; + } + + /** + Returns the call arguments that lead to the invocation of the current + `@:genericBuild` macro, if available. + + Returns `null` if the current macro is not a `@:genericBuild` macro. + **/ + @:require(haxe_ver >= 3.2) + public static function getCallArguments():Null> { + return load("call_arguments", 0)(); + } + + /** + Returns the current class in which the macro was called. + + If no such class exists, null is returned. + **/ + public static function getLocalClass() : Null> { + var l : Type = load("local_type", 0)(); + if( l == null ) return null; + return switch( l ) { + case TInst(c,_): c; + default: null; + } + } + + /** + Returns the current module path in/on which the macro was called. + **/ + public static function getLocalModule() : String { + return new String(load("local_module", 0)()); + } + + /** + Returns the current type in/on which the macro was called. + + If no such type exists, null is returned. + **/ + public static function getLocalType() : Null { + var l : Type = load("local_type", 0)(); + if( l == null ) return null; + return l; + } + + /** + Returns the name of the method from which the macro was called. + + If no such method exists, null is returned. + **/ + public static function getLocalMethod() : Null { + var l : String = load("local_method", 0)(); + if (l == "") return null; + return new String(l); + } + + /** + Returns an `Array` of classes which are available for `using` usage in + the context the macro was called. + + Modifying the returned array has no effect on the compiler. + **/ + public static function getLocalUsing() : Array> { + return load("local_using", 0)(); + } + + /** + Returns a map of local variables accessible in the context the macro was + called. + + The keys of the returned map are the variable names, the values are + their types. + + Modifying the returned map has no effect on the compiler. + **/ + @:deprecated("Use Context.getLocalTVars() instead") + public static function getLocalVars() : Map { + return load("local_vars", 1)(false); + } + + /** + Similar to `getLocalVars`, but returns elements of type `TVar` instead + of `Type`. + **/ + @:require(haxe_ver >= 3.102) + public static function getLocalTVars() : Map { + return load("local_vars", 1)(true); + } + + /** + Tells if compiler directive `s` has been set. + + Compiler directives are set using the `-D` command line parameter, or + by calling `haxe.macro.Compiler.define`. + **/ + public static function defined( s : String ) : Bool { + return load("defined", 1)(untyped s.__s); + } + + /** + Returns the value defined for compiler directive `key`. + + If no value is defined for `key`, null is returned. + + Compiler directive values are set using the `-D key=value` command line + parameter, or by calling `haxe.macro.Compiler.define`. + + The default value is `"1"`. + **/ + public static function definedValue( key : String ) : String { + var d = load("defined_value", 1)(untyped key.__s); + return d == null ? null : new String(d); + } + + /** + Returns a map of all compiler directives that have been set. + + Compiler directives are set using the `-D` command line parameter, or + by calling `haxe.macro.Compiler.define`. + + Modifying the returned map has no effect on the compiler. + */ + public static function getDefines() : Map { + return load("get_defines", 0)(); + } + + /** + Resolves a type identified by `name`. + + The resolution follows the usual class path rules where the last + declared class path has priority. + + If no type can be found, an exception of type `String` is thrown. + **/ + public static function getType( name : String ) : Type { + return load("get_type", 1)(untyped name.__s); + } + + /** + Resolves a module identified by `name` and returns an `Array` of all + its contained types. + + 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. + **/ + public static function getModule( name : String ) : Array { + return load("get_module", 1)(untyped name.__s); + } + + /** + Parses `expr` as haxe code, returning the corresponding AST. + + String interpolation of single quote strings within `expr` is not + supported. + + The provided `Position` `pos` is used for all generated inner AST nodes. + **/ + public static function parse( expr : String, pos : Position ) : Expr { + return load("parse", 3)(untyped expr.__s, pos, false); + } + + /** + Similar to `parse`, but error positions are reported within the provided + String `expr`. + **/ + public static function parseInlineString( expr : String, pos : Position ) : Expr { + return load("parse", 3)(untyped expr.__s, pos, true); + } + + /** + Builds an expression from `v`. + + This method generates AST nodes depending on the macro-runtime value of + `v`. As such, only basic types and enums are supported and the behavior + for other types is undefined. + + The provided `Position` `pos` is used for all generated inner AST nodes. + **/ + public static function makeExpr( v : Dynamic, pos : Position ) : Expr { + return load("make_expr", 2)(v, pos); + } + + /** + Returns a hashed MD5 signature of value `v`. + **/ + public static function signature( v : Dynamic ) : String { + return new String(load("signature", 1)(v)); + } + + /** + Adds a callback function `callback` which is invoked after the + compiler's typing phase, just before its generation phase. + + The callback receives an `Array` containing all types which are about + to be generated. Modifications are limited to metadata, it is mainly + intended to obtain information. + **/ + public static function onGenerate( callback : Array -> Void ) { + load("on_generate",1)(callback); + } + + /** + Adds a callback function `callback` which is invoked after the compiler + generation phase. + + Compilation has completed at this point and cannot be influenced + anymore. However, contextual information is still available. + **/ + @:require(haxe_ver >= 3.1) + public static function onAfterGenerate( callback : Void -> Void ) { + load("after_generate",1)(callback); + } + + /** + Adds a callback function `callback` which is invoked when a type name + cannot be resolved. + + The callback may return a type definition, which is then used for the + expected type. If it returns null, the type is considered to still not + exist. + **/ + public static function onTypeNotFound ( callback : String -> TypeDefinition ) { + load("on_type_not_found",1)(callback); + } + + /** + Types expression `e` and returns its type. + + Typing the expression may result in an compiler error which can be + caught using `try ... catch`. + **/ + public static function typeof( e : Expr ) : Type { + return load("typeof", 1)(e); + } + + /** + Types expression `e` and returns the corresponding `TypedExpr`. + + Typing the expression may result in an compiler error which can be + caught using `try ... catch`. + **/ + @:require(haxe_ver >= 3.1) + public static function typeExpr( e : Expr ) : TypedExpr { + return load("type_expr", 1)(e); + } + + /** + Returns the `ComplexType` corresponding to the given `Type` `t`. + + See `haxe.macro.TypeTools.toComplexType` for details. + **/ + public static function toComplexType( t : Type ) : Null { + return load("to_complex", 1)(t); + } + + /** + Returns true if `t1` and `t2` unify, false otherwise. + **/ + public static function unify( t1 : Type, t2 : Type) : Bool { + return load("unify", 2)(t1, t2); + } + + /** + Follows a type. + + See `haxe.macro.TypeTools.follow` for details. + **/ + public static function follow( t : Type, ?once : Bool ) : Type { + return load("follow", 2)(t,once); + } + + /** + Returns the information stored in `Position` `p`. + **/ + public static function getPosInfos( p : Position ) : { min : Int, max : Int, file : String } { + var i = load("get_pos_infos",1)(p); + i.file = new String(i.file); + return i; + } + + /** + Builds a `Position` from `inf`. + **/ + public static function makePosition( inf : { min : Int, max : Int, file : String } ) : Position { + return load("make_pos",3)(inf.min,inf.max,untyped inf.file.__s); + } + + /** + Returns a map of all registered resources for this compilation unit. + + Modifying the returned map has no effect on the compilation, use + `haxe.macro.Context.addResource` to add new resources to the compilation unit. + **/ + public static function getResources():Map { + var x:haxe.ds.StringMap = load("get_resources",0)(); + var r = new haxe.ds.StringMap(); + for (k in x.keys()) { + r.set(k, haxe.io.Bytes.ofData(x.get(k))); + } + return r; + } + + /** + Makes resource `data` available as `name`. + + The resource is then available using the `haxe.macro.Resource` API. + + If a previous resource was bound to `name`, it is overwritten. + **/ + public static function addResource( name : String, data : haxe.io.Bytes ) { + load("add_resource",2)(untyped name.__s,data.getData()); + } + + /** + Returns an `Array` of fields of the class which is to be built. + + This is only defined for `@:build/@:autoBuild` macros. + **/ + public static function getBuildFields() : Array { + return load("build_fields", 0)(); + } + + /** + Defines a new type from `TypeDefinition` `t`. + **/ + public static function defineType( t : TypeDefinition ) : Void { + load("define_type", 1)(t); + } + + /** + Defines a new module as `modulePath` with several `TypeDefinition` + `types`. This is analogous to defining a .hx file. + + The individial `types` can reference each other and any identifier + respects the `imports` and `usings` as usual, expect that imports are + not allowed to have `.*` wildcards or `in s` shorthands. + **/ + public static function defineModule( modulePath : String, types : Array, ?imports: Array, ?usings : Array ) : Void { + if (imports == null) imports = []; + if (usings == null) usings = []; + load("define_module", 4)(untyped modulePath.__s, untyped types.__neko(), untyped imports.__neko(), untyped usings.__neko()); + } + + /** + Returns a syntax-level expression corresponding to typed expression `t`. + + This process may lose some information. + **/ + public static function getTypedExpr( t : Type.TypedExpr ) : Expr { + return load("get_typed_expr",1)(t); + } + + + /** + Store typed expression `t` internally and give a syntax-level expression + that can be returned from a macro and will be replaced by the stored + typed expression. + + If `t` is null or invalid, an exception is thrown. + + NOTE: the returned value references an internally stored typed expression + that is reset between compilations, so care should be taken when storing + the expression returned by this method in a static variable and using the + compilation server. + **/ + @:require(haxe_ver >= 3.2) + public static function storeTypedExpr( t : Type.TypedExpr ) : Expr { + return load("store_typed_expr",1)(t); + } + + /** + Manually adds a dependency between module `modulePath` and an external + file `externFile`. + + This affects the compilation cache, causing the module to be typed if + `externFile` has changed. + + Has no effect if the compilation cache is not used. + **/ + public static function registerModuleDependency( modulePath : String, externFile : String ) { + load("module_dependency", 2)(untyped modulePath.__s,untyped externFile.__s); + } + + /** + Add a macro call to perform in case the module is reused by the compilation cache. + **/ + public static function registerModuleReuseCall( modulePath : String, macroCall : String ) { + load("module_reuse_call", 2)(untyped modulePath.__s,untyped macroCall.__s); + } + + /** + Register a callback function that will be called everytime the macro context cached is reused with a new + compilation. This enable to reset some static vars since the code might have been changed. If the callback + returns false, the macro context is discarded and another one is created. + **/ + public static function onMacroContextReused( callb : Void -> Bool ) { + load("macro_context_reused", 1)(callb); + } + + @:allow(haxe.macro.TypeTools) + @:allow(haxe.macro.MacroStringTools) + @:allow(haxe.macro.TypedExprTools) + static function load( f, nargs ) : Dynamic { + #if macro + return neko.Lib.load("macro", f, nargs); + #else + return Reflect.makeVarArgs(function(_) return throw "Can't be called outside of macro"); + #end + } + +#end + +} diff --git a/std/haxe/macro/ExampleJSGenerator.hx b/std/haxe/macro/ExampleJSGenerator.hx index 494e0bb7159358dde0ac7fcb02ec4aa87cc4f9d8..389a766fe34b6b6aa861f6d84c04bb0fa736e46d 100644 --- a/std/haxe/macro/ExampleJSGenerator.hx +++ b/std/haxe/macro/ExampleJSGenerator.hx @@ -1,252 +1,253 @@ -/* - * Copyright (C)2005-2012 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.macro; -import haxe.macro.Type; -import haxe.macro.Expr; -using Lambda; - -class ExampleJSGenerator { - - var api : JSGenApi; - var buf : StringBuf; - var inits : List; - var statics : List<{ c : ClassType, f : ClassField }>; - var packages : haxe.ds.StringMap; - var forbidden : haxe.ds.StringMap; - - public function new(api) { - this.api = api; - buf = new StringBuf(); - inits = new List(); - statics = new List(); - packages = new haxe.ds.StringMap(); - forbidden = new haxe.ds.StringMap(); - for( x in ["prototype", "__proto__", "constructor"] ) - forbidden.set(x, true); - api.setTypeAccessor(getType); - } - - function getType( t : Type ) { - return switch(t) { - case TInst(c, _): getPath(c.get()); - case TEnum(e, _): getPath(e.get()); - default: throw "assert"; - }; - } - - inline function print(str) { - buf.add(str); - } - - inline function newline() { - buf.add(";\n"); - } - - inline function genExpr(e) { - print(api.generateValue(e)); - } - - function field(p) { - return api.isKeyword(p) ? '["' + p + '"]' : "." + p; - } - - function genPackage( p : Array ) { - var full = null; - for( x in p ) { - var prev = full; - if( full == null ) full = x else full += "." + x; - if( packages.exists(full) ) - continue; - packages.set(full, true); - if( prev == null ) - print('if(typeof $x==\'undefined\') $x = {}'); - else { - var p = prev + field(x); - print('if(!$p) $p = {}'); - } - newline(); - } - } - - function getPath( t : BaseType ) { - return (t.pack.length == 0) ? t.name : t.pack.join(".") + "." + t.name; - } - - function checkFieldName( c : ClassType, f : ClassField ) { - if( forbidden.exists(f.name) ) - Context.error("The field " + f.name + " is not allowed in JS", c.pos); - } - - function genClassField( c : ClassType, p : String, f : ClassField ) { - checkFieldName(c, f); - var field = field(f.name); - print('$p.prototype$field = '); - var e = f.expr(); - if( e == null ) - print("null"); - else { - genExpr(e); - } - newline(); - } - - function genStaticField( c : ClassType, p : String, f : ClassField ) { - checkFieldName(c, f); - var field = field(f.name); - var e = f.expr(); - if( e == null ) { - print('$p$field = null'); - newline(); - } else switch( f.kind ) { - case FMethod(_): - print('$p$field = '); - genExpr(e); - newline(); - default: - statics.add( { c : c, f : f } ); - } - } - - function genClass( c : ClassType ) { - genPackage(c.pack); - api.setCurrentClass(c); - var p = getPath(c); - print('$p = $$hxClasses[\'$p\'] = '); - if( c.constructor != null ) - genExpr(c.constructor.get().expr()); - else - print("function() { }"); - newline(); - var name = p.split(".").map(api.quoteString).join(","); - print('$p.__name__ = [$name]'); - newline(); - if( c.superClass != null ) { - var psup = getPath(c.superClass.t.get()); - print('$p.__super__ = $psup'); - newline(); - print('for(var k in $psup.prototype ) $p.prototype[k] = $psup.prototype[k]'); - newline(); - } - for( f in c.statics.get() ) - genStaticField(c, p, f); - for( f in c.fields.get() ) { - switch( f.kind ) { - case FVar(r, _): - if( r == AccResolve ) continue; - default: - } - genClassField(c, p, f); - } - print('$p.prototype.__class__ = $p'); - newline(); - if( c.interfaces.length > 0 ) { - var me = this; - var inter = c.interfaces.map(function(i) return me.getPath(i.t.get())).join(","); - print('$p.__interfaces__ = [$inter]'); - newline(); - } - } - - function genEnum( e : EnumType ) { - genPackage(e.pack); - var p = getPath(e); - var names = p.split(".").map(api.quoteString).join(","); - var constructs = e.names.map(api.quoteString).join(","); - print('$p = $$hxClasses[\'$p\'] = { __ename__ : [$names], __constructs__ : [$constructs] }'); - newline(); - for( c in e.constructs.keys() ) { - var c = e.constructs.get(c); - var f = field(c.name); - print('$p$f = '); - switch( c.type ) { - case TFun(args, _): - var sargs = args.map(function(a) return a.name).join(","); - print('function($sargs) { var $$x = ["${c.name}",${c.index},$sargs]; $$x.__enum__ = $p; $$x.toString = $$estr; return $$x; }'); - default: - print("[" + api.quoteString(c.name) + "," + c.index + "]"); - newline(); - print('$p$f.toString = $$estr'); - newline(); - print('$p$f.__enum__ = $p'); - } - newline(); - } - var meta = api.buildMetaData(e); - if( meta != null ) { - print('$p.__meta__ = '); - genExpr(meta); - newline(); - } - } - - - function genStaticValue( c : ClassType, cf : ClassField ) { - var p = getPath(c); - var f = field(cf.name); - print('$p$f = '); - genExpr(cf.expr()); - newline(); - } - - function genType( t : Type ) { - switch( t ) { - case TInst(c, _): - var c = c.get(); - if( c.init != null ) - inits.add(c.init); - if( !c.isExtern ) genClass(c); - case TEnum(r, _): - var e = r.get(); - if( !e.isExtern ) genEnum(e); - default: - } - } - - public function generate() { - print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }"); - newline(); - print("function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; };"); - newline(); - for( t in api.types ) - genType(t); - for( e in inits ) { - print(api.generateStatement(e)); - newline(); - } - for( s in statics ) { - genStaticValue(s.c,s.f); - newline(); - } - if( api.main != null ) { - genExpr(api.main); - newline(); - } - sys.io.File.saveContent(api.outputFile, buf.toString()); - } - - #if macro - public static function use() { - Compiler.setCustomJSGenerator(function(api) new ExampleJSGenerator(api).generate()); - } - #end - -} +/* + * Copyright (C)2005-2012 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.macro; +import haxe.macro.Type; +import haxe.macro.Expr; +using Lambda; + +class ExampleJSGenerator { + + var api : JSGenApi; + var buf : StringBuf; + var inits : List; + var statics : List<{ c : ClassType, f : ClassField }>; + var packages : haxe.ds.StringMap; + var forbidden : haxe.ds.StringMap; + + public function new(api) { + this.api = api; + buf = new StringBuf(); + inits = new List(); + statics = new List(); + packages = new haxe.ds.StringMap(); + forbidden = new haxe.ds.StringMap(); + for( x in ["prototype", "__proto__", "constructor"] ) + forbidden.set(x, true); + api.setTypeAccessor(getType); + } + + function getType( t : Type ) { + return switch(t) { + case TInst(c, _): getPath(c.get()); + case TEnum(e, _): getPath(e.get()); + case TAbstract(a, _): getPath(a.get()); + default: throw "assert"; + }; + } + + inline function print(str) { + buf.add(str); + } + + inline function newline() { + buf.add(";\n"); + } + + inline function genExpr(e) { + print(api.generateValue(e)); + } + + function field(p) { + return api.isKeyword(p) ? '["' + p + '"]' : "." + p; + } + + function genPackage( p : Array ) { + var full = null; + for( x in p ) { + var prev = full; + if( full == null ) full = x else full += "." + x; + if( packages.exists(full) ) + continue; + packages.set(full, true); + if( prev == null ) + print('if(typeof $x==\'undefined\') $x = {}'); + else { + var p = prev + field(x); + print('if(!$p) $p = {}'); + } + newline(); + } + } + + function getPath( t : BaseType ) { + return (t.pack.length == 0) ? t.name : t.pack.join(".") + "." + t.name; + } + + function checkFieldName( c : ClassType, f : ClassField ) { + if( forbidden.exists(f.name) ) + Context.error("The field " + f.name + " is not allowed in JS", c.pos); + } + + function genClassField( c : ClassType, p : String, f : ClassField ) { + checkFieldName(c, f); + var field = field(f.name); + print('$p.prototype$field = '); + var e = f.expr(); + if( e == null ) + print("null"); + else { + genExpr(e); + } + newline(); + } + + function genStaticField( c : ClassType, p : String, f : ClassField ) { + checkFieldName(c, f); + var field = field(f.name); + var e = f.expr(); + if( e == null ) { + print('$p$field = null'); + newline(); + } else switch( f.kind ) { + case FMethod(_): + print('$p$field = '); + genExpr(e); + newline(); + default: + statics.add( { c : c, f : f } ); + } + } + + function genClass( c : ClassType ) { + genPackage(c.pack); + api.setCurrentClass(c); + var p = getPath(c); + print('$p = $$hxClasses[\'$p\'] = '); + if( c.constructor != null ) + genExpr(c.constructor.get().expr()); + else + print("function() { }"); + newline(); + var name = p.split(".").map(api.quoteString).join(","); + print('$p.__name__ = [$name]'); + newline(); + if( c.superClass != null ) { + var psup = getPath(c.superClass.t.get()); + print('$p.__super__ = $psup'); + newline(); + print('for(var k in $psup.prototype ) $p.prototype[k] = $psup.prototype[k]'); + newline(); + } + for( f in c.statics.get() ) + genStaticField(c, p, f); + for( f in c.fields.get() ) { + switch( f.kind ) { + case FVar(r, _): + if( r == AccResolve ) continue; + default: + } + genClassField(c, p, f); + } + print('$p.prototype.__class__ = $p'); + newline(); + if( c.interfaces.length > 0 ) { + var me = this; + var inter = c.interfaces.map(function(i) return me.getPath(i.t.get())).join(","); + print('$p.__interfaces__ = [$inter]'); + newline(); + } + } + + function genEnum( e : EnumType ) { + genPackage(e.pack); + var p = getPath(e); + var names = p.split(".").map(api.quoteString).join(","); + var constructs = e.names.map(api.quoteString).join(","); + print('$p = $$hxClasses[\'$p\'] = { __ename__ : [$names], __constructs__ : [$constructs] }'); + newline(); + for( c in e.constructs.keys() ) { + var c = e.constructs.get(c); + var f = field(c.name); + print('$p$f = '); + switch( c.type ) { + case TFun(args, _): + var sargs = args.map(function(a) return a.name).join(","); + print('function($sargs) { var $$x = ["${c.name}",${c.index},$sargs]; $$x.__enum__ = $p; $$x.toString = $$estr; return $$x; }'); + default: + print("[" + api.quoteString(c.name) + "," + c.index + "]"); + newline(); + print('$p$f.toString = $$estr'); + newline(); + print('$p$f.__enum__ = $p'); + } + newline(); + } + var meta = api.buildMetaData(e); + if( meta != null ) { + print('$p.__meta__ = '); + genExpr(meta); + newline(); + } + } + + + function genStaticValue( c : ClassType, cf : ClassField ) { + var p = getPath(c); + var f = field(cf.name); + print('$p$f = '); + genExpr(cf.expr()); + newline(); + } + + function genType( t : Type ) { + switch( t ) { + case TInst(c, _): + var c = c.get(); + if( c.init != null ) + inits.add(c.init); + if( !c.isExtern ) genClass(c); + case TEnum(r, _): + var e = r.get(); + if( !e.isExtern ) genEnum(e); + default: + } + } + + public function generate() { + print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }"); + newline(); + print("function $bind(o,m) { var f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; return f; };"); + newline(); + for( t in api.types ) + genType(t); + for( e in inits ) { + print(api.generateStatement(e)); + newline(); + } + for( s in statics ) { + genStaticValue(s.c,s.f); + newline(); + } + if( api.main != null ) { + genExpr(api.main); + newline(); + } + sys.io.File.saveContent(api.outputFile, buf.toString()); + } + + #if macro + public static function use() { + Compiler.setCustomJSGenerator(function(api) new ExampleJSGenerator(api).generate()); + } + #end + +} diff --git a/std/haxe/macro/Expr.hx b/std/haxe/macro/Expr.hx index 91c6d7180b9484e224dc9c1f49c343068cb00f5c..fff72d4c48f71885e6f6cf50de4c99e05ad74a50 100644 --- a/std/haxe/macro/Expr.hx +++ b/std/haxe/macro/Expr.hx @@ -1,242 +1,347 @@ -/* - * Copyright (C)2005-2012 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.macro; - -#if macro -extern enum Position { -} -#else -typedef Position = { - var file : String; - var min : Int; - var max : Int; -} -#end - -enum Constant { - CInt( v : String ); - CFloat( f : String ); - CString( s : String ); - CIdent( s : String ); - CRegexp( r : String, opt : String ); -} - -enum Binop { - OpAdd; - OpMult; - OpDiv; - OpSub; - OpAssign; - OpEq; - OpNotEq; - OpGt; - OpGte; - OpLt; - OpLte; - OpAnd; - OpOr; - OpXor; - OpBoolAnd; - OpBoolOr; - OpShl; - OpShr; - OpUShr; - OpMod; - OpAssignOp( op : Binop ); - OpInterval; - OpArrow; -} - - -enum Unop { - OpIncrement; - OpDecrement; - OpNot; - OpNeg; - OpNegBits; -} - -typedef Expr = { - var expr : ExprDef; - var pos : Position; -} - -typedef ExprOf = Expr; - -typedef Case = { - var values : Array; - @:optional var guard : Null; - var expr: Null; -} - -typedef Var = { - name : String, - type : Null, - expr : Null -} - -typedef Catch = { - name : String, - type : ComplexType, - expr : Expr -} - -enum ExprDef { - EConst( c : Constant ); - EArray( e1 : Expr, e2 : Expr ); - EBinop( op : Binop, e1 : Expr, e2 : Expr ); - EField( e : Expr, field : String ); - EParenthesis( e : Expr ); - EObjectDecl( fields : Array<{ field : String, expr : Expr }> ); - EArrayDecl( values : Array ); - ECall( e : Expr, params : Array ); - ENew( t : TypePath, params : Array ); - EUnop( op : Unop, postFix : Bool, e : Expr ); - EVars( vars : Array ); - EFunction( name : Null, f : Function ); - EBlock( exprs : Array ); - EFor( it : Expr, expr : Expr ); - EIn( e1 : Expr, e2 : Expr ); - EIf( econd : Expr, eif : Expr, eelse : Null ); - EWhile( econd : Expr, e : Expr, normalWhile : Bool ); - ESwitch( e : Expr, cases : Array, edef : Null> ); - ETry( e : Expr, catches : Array ); - EReturn( ?e : Null ); - EBreak; - EContinue; - EUntyped( e : Expr ); - EThrow( e : Expr ); - ECast( e : Expr, t : Null ); - EDisplay( e : Expr, isCall : Bool ); - EDisplayNew( t : TypePath ); - ETernary( econd : Expr, eif : Expr, eelse : Expr ); - ECheckType( e : Expr, t : ComplexType ); - EMeta( s : MetadataEntry, e : Expr ); -} - -enum ComplexType { - TPath( p : TypePath ); - TFunction( args : Array, ret : ComplexType ); - TAnonymous( fields : Array ); - TParent( t : ComplexType ); - TExtend( p : TypePath, fields : Array ); - TOptional( t : ComplexType ); -} - -typedef TypePath = { - var pack : Array; - var name : String; - var params : Array; - @:optional var sub : Null; -} - -enum TypeParam { - TPType( t : ComplexType ); - TPExpr( e : Expr ); -} - -typedef TypeParamDecl = { - var name : String; - @:optional var constraints : Array; - @:optional var params : Array; -} - -typedef Function = { - var args : Array; - var ret : Null; - var expr : Null; - var params : Array; -} - -typedef FunctionArg = { - var name : String; - var opt : Bool; - var type : Null; - @:optional var value : Null; -} - -typedef MetadataEntry = { - name : String, - params : Array, - pos : Position -} - -typedef Metadata = Array; - -typedef Field = { - var name : String; - @:optional var doc : Null; - @:optional var access : Array; - var kind : FieldType; - var pos : Position; - @:optional var meta : Metadata; -} - -enum Access { - APublic; - APrivate; - AStatic; - AOverride; - ADynamic; - AInline; - AMacro; -} - -enum FieldType { - FVar( t : Null, ?e : Null ); - FFun( f : Function ); - FProp( get : String, set : String, ?t : Null, ?e : Null ); -} - -typedef TypeDefinition = { - var pack : Array; - var name : String; - var pos : Position; - var meta : Metadata; - var params : Array; - var isExtern : Bool; - var kind : TypeDefKind; - var fields : Array; -} - -enum TypeDefKind { - TDEnum; - TDStructure; - TDClass( ?superClass : TypePath, ?interfaces : Array, ?isInterface : Bool ); - TDAlias( t : ComplexType ); // ignore TypeDefinition.fields - TDAbstract( tthis : Null, ?from : Array, ?to: Array ); -} - -/** - This error can be used to handle or produce compilation errors in macros. -**/ -class Error { - public var message : String; - public var pos : Expr.Position; - public function new(m,p) { - this.message = m; - this.pos = p; - } - function toString() { - return message; - } -} +/* + * Copyright (C)2005-2012 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.macro; + +#if (macro && !doc_gen) +extern enum Position { +} +#else +typedef Position = { + var file : String; + var min : Int; + var max : Int; +} +#end + +enum Constant { + CInt( v : String ); + CFloat( f : String ); + CString( s : String ); + CIdent( s : String ); + CRegexp( r : String, opt : String ); +} + +enum Binop { + /** + `+` + **/ + OpAdd; + /** + `*` + **/ + OpMult; + /** + `/` + **/ + OpDiv; + /** + `-` + **/ + OpSub; + /** + `=` + **/ + OpAssign; + /** + `==` + **/ + OpEq; + /** + `!=` + **/ + OpNotEq; + /** + `>` + **/ + OpGt; + /** + `>=` + **/ + OpGte; + /** + `<` + **/ + OpLt; + /** + `<=` + **/ + OpLte; + /** + `&` + **/ + OpAnd; + /** + `|` + **/ + OpOr; + /** + `^` + **/ + OpXor; + /** + `&&` + **/ + OpBoolAnd; + /** + `||` + **/ + OpBoolOr; + /** + `<<` + **/ + OpShl; + /** + `>>` + **/ + OpShr; + /** + `>>>` + **/ + OpUShr; + /** + `%` + **/ + OpMod; + /** + `+=` + `-=` + `/=` + `*=` + `<<=` + `>>=` + `>>>=` + `|=` + `&=` + `^=` + `%=` + **/ + OpAssignOp( op : Binop ); + /** + `...` + **/ + OpInterval; + /** + `=>` + **/ + OpArrow; +} + + +enum Unop { + /** + `++` + **/ + OpIncrement; + /** + `--` + **/ + OpDecrement; + /** + `!` + **/ + OpNot; + /** + `-` + **/ + OpNeg; + /** + `~` + **/ + OpNegBits; +} + +typedef Expr = { + var expr : ExprDef; + var pos : Position; +} + +typedef ExprOf = Expr; + +typedef Case = { + var values : Array; + @:optional var guard : Null; + var expr: Null; +} + +typedef Var = { + name : String, + type : Null, + expr : Null +} + +typedef Catch = { + name : String, + type : ComplexType, + expr : Expr +} + +enum ExprDef { + EConst( c : Constant ); + EArray( e1 : Expr, e2 : Expr ); + EBinop( op : Binop, e1 : Expr, e2 : Expr ); + EField( e : Expr, field : String ); + EParenthesis( e : Expr ); + EObjectDecl( fields : Array<{ field : String, expr : Expr }> ); + EArrayDecl( values : Array ); + ECall( e : Expr, params : Array ); + ENew( t : TypePath, params : Array ); + EUnop( op : Unop, postFix : Bool, e : Expr ); + EVars( vars : Array ); + EFunction( name : Null, f : Function ); + EBlock( exprs : Array ); + EFor( it : Expr, expr : Expr ); + EIn( e1 : Expr, e2 : Expr ); + EIf( econd : Expr, eif : Expr, eelse : Null ); + EWhile( econd : Expr, e : Expr, normalWhile : Bool ); + ESwitch( e : Expr, cases : Array, edef : Null> ); + ETry( e : Expr, catches : Array ); + EReturn( ?e : Null ); + EBreak; + EContinue; + EUntyped( e : Expr ); + EThrow( e : Expr ); + ECast( e : Expr, t : Null ); + EDisplay( e : Expr, isCall : Bool ); + EDisplayNew( t : TypePath ); + ETernary( econd : Expr, eif : Expr, eelse : Expr ); + ECheckType( e : Expr, t : ComplexType ); + EMeta( s : MetadataEntry, e : Expr ); +} + +enum ComplexType { + TPath( p : TypePath ); + TFunction( args : Array, ret : ComplexType ); + TAnonymous( fields : Array ); + TParent( t : ComplexType ); + TExtend( p : Array, fields : Array ); + TOptional( t : ComplexType ); +} + +typedef TypePath = { + var pack : Array; + var name : String; + @:optional var params : Array; + @:optional var sub : Null; +} + +enum TypeParam { + TPType( t : ComplexType ); + TPExpr( e : Expr ); +} + +typedef TypeParamDecl = { + var name : String; + @:optional var constraints : Array; + @:optional var params : Array; +} + +typedef Function = { + var args : Array; + var ret : Null; + var expr : Null; + @:optional var params : Array; +} + +typedef FunctionArg = { + var name : String; + @:optional var opt : Bool; + var type : Null; + @:optional var value : Null; +} + +typedef MetadataEntry = { + name : String, + ?params : Array, + pos : Position +} + +typedef Metadata = Array; + +typedef Field = { + var name : String; + @:optional var doc : Null; + @:optional var access : Array; + var kind : FieldType; + var pos : Position; + @:optional var meta : Metadata; +} + +enum Access { + APublic; + APrivate; + AStatic; + AOverride; + ADynamic; + AInline; + AMacro; +} + +enum FieldType { + FVar( t : Null, ?e : Null ); + FFun( f : Function ); + FProp( get : String, set : String, ?t : Null, ?e : Null ); +} + +typedef TypeDefinition = { + var pack : Array; + var name : String; + var pos : Position; + @:optional var meta : Metadata; + @:optional var params : Array; + @:optional var isExtern : Bool; + var kind : TypeDefKind; + var fields : Array; +} + +enum TypeDefKind { + TDEnum; + TDStructure; + TDClass( ?superClass : TypePath, ?interfaces : Array, ?isInterface : Bool ); + TDAlias( t : ComplexType ); // ignore TypeDefinition.fields + TDAbstract( tthis : Null, ?from : Array, ?to: Array ); +} + +/** + This error can be used to handle or produce compilation errors in macros. +**/ +class Error { + public var message : String; + public var pos : Expr.Position; + public function new(m,p) { + this.message = m; + this.pos = p; + } + function toString() { + return message; + } +} + +enum ImportMode { + INormal; + IAsName(alias:String); + IAll; +} + +typedef ImportExpr = { + var path: Array< { pos: Position, name: String } >; + var mode: ImportMode; +} diff --git a/std/haxe/macro/ExprTools.hx b/std/haxe/macro/ExprTools.hx index 439709264f8413571937d17f5f81eda0fdebd3d6..0352e3a439eefb9068104198ceab8ee0311409cc 100644 --- a/std/haxe/macro/ExprTools.hx +++ b/std/haxe/macro/ExprTools.hx @@ -1,238 +1,313 @@ -/* - * Copyright (C)2005-2013 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.macro; - -import haxe.macro.Expr; -using Lambda; - -/** - This class provides some utility methods to work with expressions. It is - best used through 'using haxe.macro.ExprTools' syntax and then provides - additional methods on haxe.macro.Expr instances. - - While mainly intended to be used in macros, it works in non-macro code as - well. -**/ -class ExprTools { - - static public function toFieldExpr ( sl : Array ) : Expr - return sl.fold(function(s, e) return e == null ? (macro $i{s}) : (macro $e.$s), null); - - /** - Converts expression [e] to a human-readable String representation. - - The result is guaranteed to be valid haxe code, but there may be - differences from the original lexical syntax. - **/ - static public function toString( e : Expr ) : String - return new Printer().printExpr(e); - - /** - Calls function [f] on each sub-expression of [e]. - - If [e] has no sub-expressions, this operation has no effect. - - Otherwise [f] is called once per sub-expression of [e], with the - sub-expression as argument. These calls are done in order of the - sub-expression declarations. - - This method does not call itself recursively. It should instead be used - in a recursive function which handles the expression nodes of interest. - - Usage example: - - function findStrings(e:Expr) { - switch(e.expr) { - case EConst(CString(s)): - // handle s - case _: - ExprTools.iter(e, findStrings); - } - } - **/ - static public function iter( e : Expr, f : Expr -> Void ) : Void { - switch(e.expr) { - case EConst(_), - EContinue, - EBreak, - EDisplayNew(_): - case EField(e, _), - EParenthesis(e), - EUntyped(e), - EThrow(e), - EDisplay(e, _), - ECheckType(e, _), - EUnop(_, _, e), - ECast(e, _), - EMeta(_, e): - f(e); - case EArray(e1, e2), - EWhile(e1, e2, _), - EBinop(_, e1, e2), - EFor(e1, e2), - EIn(e1, e2): - f(e1); - f(e2); - case EVars(vl): - for (v in vl) - opt2(v.expr, f); - case ETry(e, cl): - f(e); - for (c in cl) - f(c.expr); - case ETernary(e1, e2, e3) - | EIf(e1, e2, e3): - f(e1); - f(e2); - opt2(e3, f); - case EArrayDecl(el), - ENew(_, el), - EBlock(el): - ExprArrayTools.iter(el, f); - case EObjectDecl(fl): - for (fd in fl) - f(fd.expr); - case ECall(e, el): - f(e); - ExprArrayTools.iter(el, f); - case EReturn(e): - opt2(e, f); - case EFunction(_, func): - for (arg in func.args) - opt2(arg.value, f); - opt2(func.expr, f); - case ESwitch(e, cl, edef): - f(e); - for (c in cl) { - ExprArrayTools.iter(c.values, f); - opt2(c.guard, f); - opt2(c.expr, f); - } - if (edef != null && edef.expr != null) - f(edef); - } - } - - /** - Transforms the sub-expressions of [e] by calling [f] on each of them. - - If [e] has no sub-expressions, this operation returns [e] unchanged. - - Otherwise [f] is called once per sub-expression of [e], with the - sub-expression as argument. These calls are done in order of the - sub-expression declarations. - - This method does not call itself recursively. It should instead be used - in a recursive function which handles the expression nodes of interest. - - Usage example: - - function capitalizeStrings(e:Expr) { - return switch(e.expr) { - case EConst(CString(s)): - { expr: EConst(CString(s.toUpperCase())), pos: e.pos }; - case _: - ExprTools.map(e, capitalizeStrings); - } - } - **/ - static public function map( e : Expr, f : Expr -> Expr ) : Expr { - return {pos: e.pos, expr: switch(e.expr) { - case EConst(_): e.expr; - case EArray(e1, e2): EArray(f(e1), f(e2)); - case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); - case EField(e, field): EField(f(e), field); - case EParenthesis(e): EParenthesis(f(e)); - case EObjectDecl(fields): - var ret = []; - for (field in fields) - ret.push( { field: field.field, expr: f(field.expr) } ); - EObjectDecl(ret); - case EArrayDecl(el): EArrayDecl(ExprArrayTools.map(el, f)); - case ECall(e, params): ECall(f(e), ExprArrayTools.map(params, f)); - case ENew(tp, params): ENew(tp, ExprArrayTools.map(params, f)); - case EUnop(op, postFix, e): EUnop(op, postFix, f(e)); - case EVars(vars): - var ret = []; - for (v in vars) - ret.push( { name: v.name, type:v.type, expr: opt(v.expr, f) } ); - EVars(ret); - case EBlock(el): EBlock(ExprArrayTools.map(el, f)); - case EFor(it, expr): EFor(f(it), f(expr)); - case EIn(e1, e2): EIn(f(e1), f(e2)); - case EIf(econd, eif, eelse): EIf(f(econd), f(eif), opt(eelse, f)); - case EWhile(econd, e, normalWhile): EWhile(f(econd), f(e), normalWhile); - case EReturn(e): EReturn(opt(e,f)); - case EUntyped(e): EUntyped(f(e)); - case EThrow(e): EThrow(f(e)); - case ECast(e, t): ECast(f(e), t); - case EDisplay(e, isCall): EDisplay(f(e), isCall); - case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse)); - case ECheckType(e, t): ECheckType(f(e), t); - case EDisplayNew(_), - EContinue, - EBreak: - e.expr; - case ETry(e, catches): - var ret = []; - for (c in catches) - ret.push( { name:c.name, type:c.type, expr:f(c.expr) } ); - ETry(f(e), ret); - case ESwitch(e, cases, edef): - var ret = []; - for (c in cases) - ret.push( { expr: opt (c.expr, f), guard: opt(c.guard, f), values: ExprArrayTools.map(c.values, f) } ); - ESwitch(f(e), ret, edef == null || edef.expr == null ? edef : f(edef)); - case EFunction(name, func): - var ret = []; - for (arg in func.args) - ret.push( { name: arg.name, opt: arg.opt, type: arg.type, value: opt(arg.value, f) } ); - EFunction(name, { args: ret, ret: func.ret, params: func.params, expr: f(func.expr) } ); - case EMeta(m, e): EMeta(m, f(e)); - }}; - } - - static inline function opt(e:Null, f : Expr -> Expr):Expr - return e == null ? null : f(e); - - static inline function opt2(e:Null, f : Expr -> Void):Void - if (e != null) f(e); -} - -/** - This class provides functions on expression arrays for convenience. For a - detailed reference on each method, see the documentation of ExprTools. - */ -class ExprArrayTools { - static public function map( el : Array, f : Expr -> Expr):Array { - var ret = []; - for (e in el) - ret.push(f(e)); - return ret; - } - - static public function iter( el : Array, f : Expr -> Void):Void { - for (e in el) - f(e); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Expr; +using Lambda; + +/** + This class provides some utility methods to work with expressions. It is + best used through 'using haxe.macro.ExprTools' syntax and then provides + additional methods on haxe.macro.Expr instances. + + While mainly intended to be used in macros, it works in non-macro code as + well. +**/ +class ExprTools { + + /** + Converts expression [e] to a human-readable String representation. + + The result is guaranteed to be valid haxe code, but there may be + differences from the original lexical syntax. + **/ + static public function toString( e : Expr ) : String + return new Printer().printExpr(e); + + /** + Calls function [f] on each sub-expression of [e]. + + If [e] has no sub-expressions, this operation has no effect. + + Otherwise [f] is called once per sub-expression of [e], with the + sub-expression as argument. These calls are done in order of the + sub-expression declarations. + + This method does not call itself recursively. It should instead be used + in a recursive function which handles the expression nodes of interest. + + Usage example: + + function findStrings(e:Expr) { + switch(e.expr) { + case EConst(CString(s)): + // handle s + case _: + ExprTools.iter(e, findStrings); + } + } + **/ + static public function iter( e : Expr, f : Expr -> Void ) : Void { + switch(e.expr) { + case EConst(_), + EContinue, + EBreak, + EDisplayNew(_): + case EField(e, _), + EParenthesis(e), + EUntyped(e), + EThrow(e), + EDisplay(e, _), + ECheckType(e, _), + EUnop(_, _, e), + ECast(e, _), + EMeta(_, e): + f(e); + case EArray(e1, e2), + EWhile(e1, e2, _), + EBinop(_, e1, e2), + EFor(e1, e2), + EIn(e1, e2): + f(e1); + f(e2); + case EVars(vl): + for (v in vl) + opt2(v.expr, f); + case ETry(e, cl): + f(e); + for (c in cl) + f(c.expr); + case ETernary(e1, e2, e3) + | EIf(e1, e2, e3): + f(e1); + f(e2); + opt2(e3, f); + case EArrayDecl(el), + ENew(_, el), + EBlock(el): + ExprArrayTools.iter(el, f); + case EObjectDecl(fl): + for (fd in fl) + f(fd.expr); + case ECall(e, el): + f(e); + ExprArrayTools.iter(el, f); + case EReturn(e): + opt2(e, f); + case EFunction(_, func): + for (arg in func.args) + opt2(arg.value, f); + opt2(func.expr, f); + case ESwitch(e, cl, edef): + f(e); + for (c in cl) { + ExprArrayTools.iter(c.values, f); + opt2(c.guard, f); + opt2(c.expr, f); + } + if (edef != null && edef.expr != null) + f(edef); + } + } + + /** + Transforms the sub-expressions of [e] by calling [f] on each of them. + + If [e] has no sub-expressions, this operation returns [e] unchanged. + + Otherwise [f] is called once per sub-expression of [e], with the + sub-expression as argument. These calls are done in order of the + sub-expression declarations. + + This method does not call itself recursively. It should instead be used + in a recursive function which handles the expression nodes of interest. + + Usage example: + + function capitalizeStrings(e:Expr) { + return switch(e.expr) { + case EConst(CString(s)): + { expr: EConst(CString(s.toUpperCase())), pos: e.pos }; + case _: + ExprTools.map(e, capitalizeStrings); + } + } + **/ + static public function map( e : Expr, f : Expr -> Expr ) : Expr { + return {pos: e.pos, expr: switch(e.expr) { + case EConst(_): e.expr; + case EArray(e1, e2): EArray(f(e1), f(e2)); + case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); + case EField(e, field): EField(f(e), field); + case EParenthesis(e): EParenthesis(f(e)); + case EObjectDecl(fields): + var ret = []; + for (field in fields) + ret.push( { field: field.field, expr: f(field.expr) } ); + EObjectDecl(ret); + case EArrayDecl(el): EArrayDecl(ExprArrayTools.map(el, f)); + case ECall(e, params): ECall(f(e), ExprArrayTools.map(params, f)); + case ENew(tp, params): ENew(tp, ExprArrayTools.map(params, f)); + case EUnop(op, postFix, e): EUnop(op, postFix, f(e)); + case EVars(vars): + var ret = []; + for (v in vars) + ret.push( { name: v.name, type:v.type, expr: opt(v.expr, f) } ); + EVars(ret); + case EBlock(el): EBlock(ExprArrayTools.map(el, f)); + case EFor(it, expr): EFor(f(it), f(expr)); + case EIn(e1, e2): EIn(f(e1), f(e2)); + case EIf(econd, eif, eelse): EIf(f(econd), f(eif), opt(eelse, f)); + case EWhile(econd, e, normalWhile): EWhile(f(econd), f(e), normalWhile); + case EReturn(e): EReturn(opt(e,f)); + case EUntyped(e): EUntyped(f(e)); + case EThrow(e): EThrow(f(e)); + case ECast(e, t): ECast(f(e), t); + case EDisplay(e, isCall): EDisplay(f(e), isCall); + case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse)); + case ECheckType(e, t): ECheckType(f(e), t); + case EDisplayNew(_), + EContinue, + EBreak: + e.expr; + case ETry(e, catches): + var ret = []; + for (c in catches) + ret.push( { name:c.name, type:c.type, expr:f(c.expr) } ); + ETry(f(e), ret); + case ESwitch(e, cases, edef): + var ret = []; + for (c in cases) + ret.push( { expr: opt (c.expr, f), guard: opt(c.guard, f), values: ExprArrayTools.map(c.values, f) } ); + ESwitch(f(e), ret, edef == null || edef.expr == null ? edef : f(edef)); + case EFunction(name, func): + var ret = []; + for (arg in func.args) + ret.push( { name: arg.name, opt: arg.opt, type: arg.type, value: opt(arg.value, f) } ); + EFunction(name, { args: ret, ret: func.ret, params: func.params, expr: f(func.expr) } ); + case EMeta(m, e): EMeta(m, f(e)); + }}; + } + + /** + Returns the value `e` represents. + + Supported expressions are: + - `Int`, `Float` and `String` literals + - identifiers `true`, `false` and `null` + - structure declarations if all their fields are values + - array declarations if all their elements are values + - unary operators `-`, `!` and `~` if the operand is a value + - binary operators except `=>`, `...` and assignments + + Parentheses, metadata and the `untyped` keyword are ignored. + + If any non-value is encountered, an exception of type `String` is + thrown. + + If `e` is null, the result is unspecified. + **/ + static public function getValue(e:Expr):Dynamic { + return switch (e.expr) { + case EConst(CInt(v)): Std.parseInt(v); + case EConst(CFloat(v)): Std.parseFloat(v); + case EConst(CString(s)): s; + case EConst(CIdent("true")): true; + case EConst(CIdent("false")): false; + case EConst(CIdent("null")): null; + case EParenthesis(e1) | EUntyped(e1) | EMeta(_, e1): getValue(e1); + case EObjectDecl(fields): + var obj = {}; + for (field in fields) { + Reflect.setField(obj, field.field, getValue(field.expr)); + } + obj; + case EArrayDecl(el): el.map(getValue); + case EIf(econd, eif, eelse) | ETernary(econd, eif, eelse): + if (eelse == null) { + throw "If statements only have a value if the else clause is defined"; + } else { + var econd:Dynamic = getValue(econd); + econd ? getValue(eif) : getValue(eelse); + } + case EUnop(op, false, e1): + var e1:Dynamic = getValue(e1); + switch (op) { + case OpNot: !e1; + case OpNeg: -e1; + case OpNegBits: ~e1; + case _: throw 'Unsupported expression: $e'; + } + case EBinop(op, e1, e2): + var e1:Dynamic = getValue(e1); + var e2:Dynamic = getValue(e2); + switch (op) { + case OpAdd: e1 + e2; + case OpSub: e1 - e2; + case OpMult: e1 * e2; + case OpDiv: e1 / e2; + case OpMod: e1 % e2; + case OpEq: e1 == e2; + case OpNotEq: e1 != e2; + case OpLt: e1 < e2; + case OpLte: e1 <= e2; + case OpGt: e1 > e2; + case OpGte: e1 >= e2; + case OpOr: e1 | e2; + case OpAnd: e1 & e2; + case OpXor: e1 ^ e2; + case OpBoolAnd: e1 && e2; + case OpBoolOr: e1 || e2; + case OpShl: e1 << e2; + case OpShr: e1 >> e2; + case OpUShr: e1 >>> e2; + case _: throw 'Unsupported expression: $e'; + } + case _: throw 'Unsupported expression: $e'; + } + } + + static inline function opt(e:Null, f : Expr -> Expr):Expr + return e == null ? null : f(e); + + static inline function opt2(e:Null, f : Expr -> Void):Void + if (e != null) f(e); +} + +/** + This class provides functions on expression arrays for convenience. For a + detailed reference on each method, see the documentation of ExprTools. + */ +class ExprArrayTools { + static public function map( el : Array, f : Expr -> Expr):Array { + var ret = []; + for (e in el) + ret.push(f(e)); + return ret; + } + + static public function iter( el : Array, f : Expr -> Void):Void { + for (e in el) + f(e); + } +} diff --git a/std/haxe/macro/Format.hx b/std/haxe/macro/Format.hx index 7a499ffafbebc2211a1539229d66a965d57e17f0..2cc7302884b23573d251c6f8d1d042122b04b90e 100644 --- a/std/haxe/macro/Format.hx +++ b/std/haxe/macro/Format.hx @@ -1,115 +1,115 @@ -/* - * Copyright (C)2005-2012 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.macro; -import haxe.macro.Expr; -import haxe.macro.Context; - -/** - The actual macro implemented for Std.format -**/ -class Format { - - #if macro - public static function format( estr : Expr ) { - var str = switch( estr.expr ) { - case EConst(c): switch(c) { case CString(s): s; default: null; } - default: null; - }; - if( str == null ) - Context.error("Constant string required", estr.pos); - var pos = Context.getPosInfos(estr.pos); - var min = pos.min; - pos.min++; - var expr = null; - function make(size) { - pos.max = pos.min + size; - var p = Context.makePosition(pos); - pos.min += size; - return p; - } - function add(e) { - if( expr == null ) - expr = e; - else - expr = { expr : EBinop(OpAdd,expr,e), pos : Context.makePosition({ min : min, max : pos.min, file : pos.file }) }; - } - var i = 0, start = 0; - var max = str.length; - while( i < max ) { - if( StringTools.fastCodeAt(str,i++) != '$'.code ) - continue; - var len = i - start - 1; - if( len > 0 || expr == null ) - add({ expr : EConst(CString(str.substr(start,len))), pos : make(len) }); - pos.min++; - start = i; - var c = StringTools.fastCodeAt(str, i); - if( c == '{'.code ) { - var count = 1; - i++; - while( i < max ) { - var c = StringTools.fastCodeAt(str,i++); - if( c == "}".code ) { - if( --count == 0 ) break; - } else if( c == "{".code ) - count++; - } - if( count > 0 ) - Context.error("Closing brace not found",make(1)); - pos.min++; - start++; - var len = i - start - 1; - var expr = str.substr(start, len); - add(Context.parseInlineString(expr, make(len))); - pos.min++; - start++; - } else if( (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || c == '_'.code ) { - i++; - while( true ) { - var c = StringTools.fastCodeAt(str, i); - if( (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == '_'.code ) - i++; - else - break; - } - var len = i - start; - var ident = str.substr(start, len); - add( { expr : EConst(CIdent(ident)), pos : make(len) } ); - } else if( c == '$'.code ) { - start = i++; - continue; - } else { - start = i - 1; - continue; - } - start = i; - } - var len = i - start; - if( len > 0 ) - add({ expr : EConst(CString(str.substr(start,len))), pos : make(len) }); - if( expr == null ) - expr = { expr : EConst(CString("")), pos : make(0) }; - return { expr : ECheckType(expr,TPath({ pack : [], name : "String", params : [] })), pos : expr.pos }; - } - #end - -} +/* + * Copyright (C)2005-2012 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.macro; +import haxe.macro.Expr; +import haxe.macro.Context; + +/** + The actual macro implemented for Std.format +**/ +class Format { + + #if macro + public static function format( estr : Expr ) { + var str = switch( estr.expr ) { + case EConst(c): switch(c) { case CString(s): s; default: null; } + default: null; + }; + if( str == null ) + Context.error("Constant string required", estr.pos); + var pos = Context.getPosInfos(estr.pos); + var min = pos.min; + pos.min++; + var expr = null; + function make(size) { + pos.max = pos.min + size; + var p = Context.makePosition(pos); + pos.min += size; + return p; + } + function add(e) { + if( expr == null ) + expr = e; + else + expr = { expr : EBinop(OpAdd,expr,e), pos : Context.makePosition({ min : min, max : pos.min, file : pos.file }) }; + } + var i = 0, start = 0; + var max = str.length; + while( i < max ) { + if( StringTools.fastCodeAt(str,i++) != '$'.code ) + continue; + var len = i - start - 1; + if( len > 0 || expr == null ) + add({ expr : EConst(CString(str.substr(start,len))), pos : make(len) }); + pos.min++; + start = i; + var c = StringTools.fastCodeAt(str, i); + if( c == '{'.code ) { + var count = 1; + i++; + while( i < max ) { + var c = StringTools.fastCodeAt(str,i++); + if( c == "}".code ) { + if( --count == 0 ) break; + } else if( c == "{".code ) + count++; + } + if( count > 0 ) + Context.error("Closing brace not found",make(1)); + pos.min++; + start++; + var len = i - start - 1; + var expr = str.substr(start, len); + add(Context.parseInlineString(expr, make(len))); + pos.min++; + start++; + } else if( (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || c == '_'.code ) { + i++; + while( true ) { + var c = StringTools.fastCodeAt(str, i); + if( (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == '_'.code ) + i++; + else + break; + } + var len = i - start; + var ident = str.substr(start, len); + add( { expr : EConst(CIdent(ident)), pos : make(len) } ); + } else if( c == '$'.code ) { + start = i++; + continue; + } else { + start = i - 1; + continue; + } + start = i; + } + var len = i - start; + if( len > 0 ) + add({ expr : EConst(CString(str.substr(start,len))), pos : make(len) }); + if( expr == null ) + expr = { expr : EConst(CString("")), pos : make(0) }; + return { expr : ECheckType(expr,TPath({ pack : [], name : "String", params : [] })), pos : expr.pos }; + } + #end + +} diff --git a/std/haxe/macro/JSGenApi.hx b/std/haxe/macro/JSGenApi.hx index 23103fca44d2ead42e2cf69bbb5ca42f0f5068ab..93e89c2a16302bf26c9711edbd2a9c4b6b7aa8f9 100644 --- a/std/haxe/macro/JSGenApi.hx +++ b/std/haxe/macro/JSGenApi.hx @@ -1,49 +1,53 @@ -/* - * Copyright (C)2005-2012 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.macro; -import haxe.macro.Type; - -/** - This is the api that is passed to the custom JS generator. -**/ -typedef JSGenApi = { - /** the file in which the JS code can be generated **/ - var outputFile : String; - /** all the types that were compiled by haXe **/ - var types : Array; - /** the main call expression, if a -main class is defined **/ - var main : Null; - /** generate the JS code for any given typed expression **/ - function generateStatement( e : TypedExpr ) : String; - /** generate the JS code for a given typed expression-value **/ - function generateValue( e : TypedExpr ) : String; - /** define the JS code that gets generated when a class or enum is accessed in a typed expression **/ - function setTypeAccessor( callb : Type -> String ) : Void; - /** tells if the given identifier is a JS keyword **/ - function isKeyword( ident : String ) : Bool; - /** quote and escape the given string constant **/ - function quoteString( s : String ) : String; - /** create the metadata expression for the given type **/ - function buildMetaData( t : BaseType ) : Null; - /** select the current classe **/ - function setCurrentClass( c : ClassType ) : Void; -} +/* + * Copyright (C)2005-2012 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.macro; +import haxe.macro.Type; + +/** + This is the api that is passed to the custom JS generator. +**/ +typedef JSGenApi = { + /** the file in which the JS code can be generated **/ + var outputFile : String; + /** all the types that were compiled by Haxe **/ + var types : Array; + /** the main call expression, if a -main class is defined **/ + var main : Null; + /** generate the JS code for any given typed expression **/ + function generateStatement( e : TypedExpr ) : String; + /** generate the JS code for a given typed expression-value **/ + function generateValue( e : TypedExpr ) : String; + /** define the JS code that gets generated when a class or enum is accessed in a typed expression **/ + function setTypeAccessor( callb : Type -> String ) : Void; + /** tells if the given identifier is a JS keyword **/ + function isKeyword( ident : String ) : Bool; + /** add a feature **/ + function addFeature( f : String ) : Bool; + /** check if a feature is used **/ + function hasFeature( f : String ) : Bool; + /** quote and escape the given string constant **/ + function quoteString( s : String ) : String; + /** create the metadata expression for the given type **/ + function buildMetaData( t : BaseType ) : Null; + /** select the current classe **/ + function setCurrentClass( c : ClassType ) : Void; +} diff --git a/std/haxe/macro/MacroStringTools.hx b/std/haxe/macro/MacroStringTools.hx new file mode 100644 index 0000000000000000000000000000000000000000..d22d5def7951c5acbbab8c7cbc584f825bd2626d --- /dev/null +++ b/std/haxe/macro/MacroStringTools.hx @@ -0,0 +1,96 @@ +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Expr; + +/** + This class provides some utility methods to work with strings in macro + context. +**/ +class MacroStringTools { + #if macro + + + /** + Formats `String` `s` using the usual interpolation rules. + + The returned expression is a concatenation of string parts and escaped + elements. + **/ + static public function formatString(s:String, pos:Position) { + return Context.load("format_string", 2)(untyped s.__s, pos); + } + + /** + Tells if `e` is a format string, i.e. uses single quotes `'` as + delimiters. + + This only works if `e` has a position which the compiler can find. While + this is true for any expressions appearing in real Haxe code (i.e. some + .hx file), it might not work for expressions generated by macros. + + This operation depends on the position of `e`. + **/ + static public function isFormatExpr(e:ExprOf) { + return Context.load("is_fmt_string", 1)(e.pos); + } + + #end + + /** + Converts an array of Strings `sl` to a field expression. + + If `sl` has no elements, the result is null. + + If `sl` has one element, the result is `EConst(CIdent(sl[0])`. + + Otherwise the result is a chain of `EField` nodes. + + If `sl` is null, the result is unspecified. + **/ + static public function toFieldExpr(sl:Array):Expr { + return Lambda.fold(sl, function(s, e) return e == null ? (macro $i{s}) : (macro $e.$s), null); + } + + /** + Converts a path given by package `pack` and name `name` to a `String` + separated by dots. + + If `pack` has no elements, the result is `name`. + + If `pack` is null, the result is unspecified. + + Otherwise the elements of `pack` are joined with a separating dot, with + an appended dot separating the result from `name`. + **/ + static public function toDotPath(pack:Array, name:String):String { + return if (pack.length == 0) name else pack.join(".") + "." +name; + } + + static public function toComplex( path : String ) : ComplexType { + var pack = path.split("."); + return TPath( { pack : pack, name : pack.pop(), params : [] } ); + } + +} diff --git a/std/haxe/macro/MacroType.hx b/std/haxe/macro/MacroType.hx index 10d233a24970dcf04a3f422861b9b38c9125fbb5..e95c20739242c9b54a1371415d6b9140c1ff4fb9 100644 --- a/std/haxe/macro/MacroType.hx +++ b/std/haxe/macro/MacroType.hx @@ -1,29 +1,29 @@ -/* - * Copyright (C)2005-2012 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.macro; - -/** - This type is meant to be used to generate custom types using a macro. - For instance by doing MacroType<[my.Class.myMacro(55)]> -**/ -extern class MacroType { +/* + * Copyright (C)2005-2012 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.macro; + +/** + This type is meant to be used to generate custom types using a macro. + For instance by doing MacroType<[my.Class.myMacro(55)]> +**/ +extern class MacroType { } \ No newline at end of file diff --git a/std/haxe/macro/PositionTools.hx b/std/haxe/macro/PositionTools.hx new file mode 100644 index 0000000000000000000000000000000000000000..2be5e608d8edf807a93ed1e13259319002e92f5a --- /dev/null +++ b/std/haxe/macro/PositionTools.hx @@ -0,0 +1,41 @@ +package haxe.macro; + +import haxe.macro.Expr; + +class PositionTools { + + /** + Returns the `Position` where the caller of `here` is. + **/ + macro public static function here():ExprOf { + var positionExpr = Context.makeExpr(Context.getPosInfos(Context.currentPos()), Context.currentPos()); + if (Context.defined("macro")) { + return macro Context.makePosition($positionExpr); + } else { + return positionExpr; + } + } + + /** + Like `Context.getPosInfos`, except this method is available on all platforms. + **/ + public static function getInfos( p : Position ) : { min : Int, max : Int, file : String } { + #if macro + return Context.getPosInfos(p); + #else + return p; + #end + } + + /** + Like `Context.makePosition`, except this method is available on all platforms. + **/ + public static function make( inf : { min : Int, max : Int, file : String } ) : Position { + #if macro + return Context.makePosition(inf); + #else + return inf; + #end + } + +} diff --git a/std/haxe/macro/Printer.hx b/std/haxe/macro/Printer.hx index fcce5a42068802fad7fb9e15a144254d0c6019a7..491930512be45f12f8714fe081b6603a25bf5cf0 100644 --- a/std/haxe/macro/Printer.hx +++ b/std/haxe/macro/Printer.hx @@ -1,278 +1,311 @@ -/* - * Copyright (C)2005-2013 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.macro; - -import haxe.macro.Expr; -using Lambda; - -class Printer { - var tabs:String; - var tabString:String; - - public function new(?tabString = "\t") { - tabs = ""; - this.tabString = tabString; - } - - public function printUnop(op:Unop) return switch(op) { - case OpIncrement: "++"; - case OpDecrement: "--"; - case OpNot: "!"; - case OpNeg: "-"; - case OpNegBits: "~"; - } - - public function printBinop(op:Binop) return switch(op) { - case OpAdd: "+"; - case OpMult: "*"; - case OpDiv: "/"; - case OpSub: "-"; - case OpAssign: "="; - case OpEq: "=="; - case OpNotEq: "!="; - case OpGt: ">"; - case OpGte: ">="; - case OpLt: "<"; - case OpLte: "<="; - case OpAnd: "&"; - case OpOr: "|"; - case OpXor: "^"; - case OpBoolAnd: "&&"; - case OpBoolOr: "||"; - case OpShl: "<<"; - case OpShr: ">>"; - case OpUShr: ">>>"; - case OpMod: "%"; - case OpInterval: "..."; - case OpArrow: "=>"; - case OpAssignOp(op): - printBinop(op) - + "="; - } - - public function printConstant(c:Constant) return switch(c) { - case CString(s): '"$s"'; - case CIdent(s), - CInt(s), - CFloat(s): - s; - case CRegexp(s,opt): '~/$s/$opt'; - } - - public function printTypeParam(param:TypeParam) return switch(param) { - case TPType(ct): printComplexType(ct); - case TPExpr(e): printExpr(e); - } - - public function printTypePath(tp:TypePath) return - (tp.pack.length > 0 ? tp.pack.join(".") + "." : "") - + tp.name - + (tp.sub != null ? '.${tp.sub}' : "") - + (tp.params.length > 0 ? "<" + tp.params.map(printTypeParam).join(",") + ">" : ""); - - // TODO: check if this can cause loops - public function printComplexType(ct:ComplexType) return switch(ct) { - case TPath(tp): printTypePath(tp); - case TFunction(args, ret): args.map(printComplexType).join("->") + "->" + printComplexType(ret); - case TAnonymous(fields): "{" + [for (f in fields) printField(f) + ";"].join("") + "}"; - case TParent(ct): "(" + printComplexType(ct) + ")"; - case TOptional(ct): "?" + printComplexType(ct); - case TExtend(tp, fields): '{${printTypePath(tp)} >, ${fields.map(printField).join(",")}}'; - } - - public function printMetadata(meta:MetadataEntry) return - '@${meta.name}' - + (meta.params.length > 0 ? '(${printExprs(meta.params,",")})' : ""); - - public function printAccess(access:Access) return switch(access) { - case AStatic: "static"; - case APublic: "public"; - case APrivate: "private"; - case AOverride: "override"; - case AInline: "inline"; - case ADynamic: "dynamic"; - case AMacro: "macro"; - } - - public function printField(field:Field) return - (field.doc != null && field.doc != "" ? "/**\n" + tabs + tabString + StringTools.replace(field.doc, "\n", "\n" + tabs + tabString) + "\n" + tabs + "**/\n" + tabs : "") - + (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join(" ") + " " : "") - + (field.access != null && field.access.length > 0 ? field.access.map(printAccess).join(" ") + " " : "") - + switch(field.kind) { - case FVar(t, eo): '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 - + (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(",") + ">" : "") - + (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(",") + ")" : ""); - - public function printFunctionArg(arg:FunctionArg) return - (arg.opt ? "?" : "") - + arg.name - + opt(arg.type, printComplexType, ":") - + opt(arg.value, printExpr, "="); - - public function printFunction(func:Function) return - (func.params.length > 0 ? "<" + func.params.map(printTypeParamDecl).join(",") + ">" : "") - + "(" + func.args.map(printFunctionArg).join(",") + ")" - + opt(func.ret, printComplexType, ":") - + opt(func.expr, printExpr, " "); - - public function printVar(v:Var) return - v.name - + opt(v.type, printComplexType, ":") - + opt(v.expr, printExpr, "="); - - - public function printExpr(e:Expr) return e == null ? "#NULL" : switch(e.expr) { - case EConst(c): printConstant(c); - case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]'; - case EBinop(op, e1, e2): '${printExpr(e1)}${printBinop(op)}${printExpr(e2)}'; - case EField(e1, n): '${printExpr(e1)}.$n'; - case EParenthesis(e1): '(${printExpr(e1)})'; - case EObjectDecl(fl): - "{" + fl.map(function(fld) return '${fld.field}:${printExpr(fld.expr)}').join(",") + "}"; - case EArrayDecl(el): '[${printExprs(el, ",")}]'; - case ECall(e1, el): '${printExpr(e1)}(${printExprs(el,",")})'; - case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el,",")})'; - case EUnop(op, true, e1): printExpr(e1) + printUnop(op); - case EUnop(op, false, e1): printUnop(op) + printExpr(e1); - case EFunction(no, func) if (no != null): 'function $no' + printFunction(func); - case EFunction(_, func): "function " +printFunction(func); - case EVars(vl): "var " +vl.map(printVar).join(","); - case EBlock([]): '{\n$tabs}'; - case EBlock(el): - var old = tabs; - tabs += tabString; - var s = '{\n$tabs' + printExprs(el, ';\n$tabs'); - tabs = old; - s + ';\n$tabs}'; - case EFor(e1, e2): 'for(${printExpr(e1)}) ${printExpr(e2)}'; - case EIn(e1, e2): '${printExpr(e1)} in ${printExpr(e2)}'; - case EIf(econd, eif, eelse): 'if(${printExpr(econd)}) ${printExpr(eif)} ${opt(eelse,printExpr,"else ")}'; - case EWhile(econd, e1, true): 'while(${printExpr(econd)}) ${printExpr(e1)}'; - case EWhile(econd, e1, false): 'do ${printExpr(e1)} while(${printExpr(econd)})'; - case ESwitch(e1, cl, edef): - var old = tabs; - tabs += tabString; - var s = 'switch ${printExpr(e1)} {\n$tabs' + - cl.map(function(c) - return 'case ${printExprs(c.values, ",")}' - + (c.guard != null ? 'if(${printExpr(c.guard)}):' : ":") - + (opt(c.expr, printExpr)) + ";") - .join('\n$tabs'); - if (edef != null) - s += '\n${tabs}default:' + (edef.expr == null ? "" : printExpr(edef)) + ";"; - 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(""); - case EReturn(eo): "return" + opt(eo, printExpr, " "); - case EBreak: "break"; - case EContinue: "continue"; - case EUntyped(e1): "untyped " +printExpr(e1); - case EThrow(e1): "throw " +printExpr(e1); - case ECast(e1, cto) if (cto != null): 'cast(${printExpr(e1)}, ${printComplexType(cto)})'; - case ECast(e1, _): "cast " +printExpr(e1); - case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})'; - case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})'; - case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse) }'; - case ECheckType(e1, ct): '#CHECK_TYPE(${printExpr(e1)}, ${printComplexType(ct)})'; - case EMeta(meta, e1): printMetadata(meta) + " " +printExpr(e1); - } - - public function printExprs(el:Array, sep:String) { - return el.map(printExpr).join(sep); - } - - public function printTypeDefinition(t:TypeDefinition, printPackage = true):String { - var old = tabs; - tabs = tabString; - - var str = t == null ? "#NULL" : - (printPackage && t.pack.length > 0 && t.pack[0] != "" ? "package " + t.pack.join(".") + ";\n" : "") + - (t.meta != null && t.meta.length > 0 ? t.meta.map(printMetadata).join(" ") + " " : "") + (t.isExtern ? "extern " : "") + switch (t.kind) { - case TDEnum: - "enum " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(",") + ">" : "") + " {\n" - + [for (field in t.fields) - tabs + (field.doc != null && field.doc != "" ? "/**\n" + tabs + tabString + StringTools.replace(field.doc, "\n", "\n" + tabs + tabString) + "\n" + tabs + "**/\n" + tabs : "") - + (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join(" ") + " " : "") - + (switch(field.kind) { - case FVar(_, _): field.name; - case FProp(_, _, _, _): throw "FProp is invalid for TDEnum."; - case FFun(func): field.name + printFunction(func); - }) + ";" - ].join("\n") - + "\n}"; - case TDStructure: - "typedef " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(",") + ">" : "") + " = {\n" - + [for (f in t.fields) { - tabs + printField(f) + ";"; - }].join("\n") - + "\n}"; - case TDClass(superClass, interfaces, isInterface): - (isInterface ? "interface " : "class ") + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(",") + ">" : "") - + (superClass != null ? " extends " + printTypePath(superClass) : "") - + (interfaces != null ? (isInterface ? [for (tp in interfaces) " extends " + printTypePath(tp)] : [for (tp in interfaces) " implements " + printTypePath(tp)]).join("") : "") - + " {\n" - + [for (f in t.fields) { - var fstr = printField(f); - tabs + fstr + switch(f.kind) { - case FVar(_, _), FProp(_, _, _, _): ";"; - case FFun(func) if (func.expr == null): ";"; - case _: ""; - }; - }].join("\n") - + "\n}"; - case TDAlias(ct): - "typedef " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(",") + ">" : "") + " = " - + printComplexType(ct) - + ";"; - case TDAbstract(tthis, from, to): - "abstract " + t.name - + (tthis == null ? "" : "(" + printComplexType(tthis) + ")") - + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(",") + ">" : "") - + (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join("")) - + (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join("")) - + " {\n" - + [for (f in t.fields) { - var fstr = printField(f); - tabs + fstr + switch(f.kind) { - case FVar(_, _), FProp(_, _, _, _): ";"; - case FFun(func) if (func.expr == null): ";"; - case _: ""; - }; - }].join("\n") - + "\n}"; - } - - tabs = old; - return str; - } - - function opt(v:T, f:T->String, prefix = "") return v == null ? "" : (prefix + f(v)); -} \ No newline at end of file +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Expr; +using Lambda; +using StringTools; + +class Printer { + var tabs:String; + var tabString:String; + + public function new(?tabString = "\t") { + tabs = ""; + this.tabString = tabString; + } + + public function printUnop(op:Unop) return switch(op) { + case OpIncrement: "++"; + case OpDecrement: "--"; + case OpNot: "!"; + case OpNeg: "-"; + case OpNegBits: "~"; + } + + public function printBinop(op:Binop) return switch(op) { + case OpAdd: "+"; + case OpMult: "*"; + case OpDiv: "/"; + case OpSub: "-"; + case OpAssign: "="; + case OpEq: "=="; + case OpNotEq: "!="; + case OpGt: ">"; + case OpGte: ">="; + case OpLt: "<"; + case OpLte: "<="; + case OpAnd: "&"; + case OpOr: "|"; + case OpXor: "^"; + case OpBoolAnd: "&&"; + case OpBoolOr: "||"; + case OpShl: "<<"; + case OpShr: ">>"; + case OpUShr: ">>>"; + case OpMod: "%"; + case OpInterval: "..."; + case OpArrow: "=>"; + case OpAssignOp(op): + printBinop(op) + + "="; + } + + function escapeString(s:String,delim:String) { + return delim + s.replace("\n","\\n").replace("\t","\\t").replace("'","\\'").replace('"',"\\\"") #if sys .replace("\x00","\\x00") #end + delim; + } + + public function printFormatString(s:String) { + return escapeString(s,"'"); + } + + public function printString(s:String) { + return escapeString(s,'"'); + } + + public function printConstant(c:Constant) return switch(c) { + case CString(s): printString(s); + case CIdent(s), + CInt(s), + CFloat(s): + s; + case CRegexp(s,opt): '~/$s/$opt'; + } + + public function printTypeParam(param:TypeParam) return switch(param) { + case TPType(ct): printComplexType(ct); + case TPExpr(e): printExpr(e); + } + + public function printTypePath(tp:TypePath) return + (tp.pack.length > 0 ? tp.pack.join(".") + "." : "") + + tp.name + + (tp.sub != null ? '.${tp.sub}' : "") + + (tp.params == null ? "" : tp.params.length > 0 ? "<" + tp.params.map(printTypeParam).join(", ") + ">" : ""); + + // TODO: check if this can cause loops + public function printComplexType(ct:ComplexType) return switch(ct) { + case TPath(tp): printTypePath(tp); + case TFunction(args, ret): (args.length>0 ? args.map(printComplexType).join(" -> ") : "Void") + " -> " + printComplexType(ret); + case TAnonymous(fields): "{ " + [for (f in fields) printField(f) + "; "].join("") + "}"; + case TParent(ct): "(" + printComplexType(ct) + ")"; + case TOptional(ct): "?" + printComplexType(ct); + case TExtend(tpl, fields): '{> ${tpl.map(printTypePath).join(" >, ")}, ${fields.map(printField).join(", ")} }'; + } + + public function printMetadata(meta:MetadataEntry) return + '@${meta.name}' + + ((meta.params != null && meta.params.length > 0) ? '(${printExprs(meta.params,", ")})' : ""); + + public function printAccess(access:Access) return switch(access) { + case AStatic: "static"; + case APublic: "public"; + case APrivate: "private"; + case AOverride: "override"; + case AInline: "inline"; + case ADynamic: "dynamic"; + case AMacro: "macro"; + } + + public function printField(field:Field) return + (field.doc != null && field.doc != "" ? "/**\n" + tabs + tabString + StringTools.replace(field.doc, "\n", "\n" + tabs + tabString) + "\n" + tabs + "**/\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(" ") + " " : "") + + switch(field.kind) { + case FVar(t, eo): '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 + + (tpd.params != null && tpd.params.length > 0 ? "<" + tpd.params.map(printTypeParamDecl).join(", ") + ">" : "") + + (tpd.constraints != null && tpd.constraints.length > 0 ? ":(" + tpd.constraints.map(printComplexType).join(", ") + ")" : ""); + + public function printFunctionArg(arg:FunctionArg) return + (arg.opt ? "?" : "") + + arg.name + + opt(arg.type, printComplexType, ":") + + opt(arg.value, printExpr, " = "); + + public function printFunction(func:Function) return + (func.params == null ? "" : func.params.length > 0 ? "<" + func.params.map(printTypeParamDecl).join(", ") + ">" : "") + + "(" + func.args.map(printFunctionArg).join(", ") + ")" + + opt(func.ret, printComplexType, ":") + + opt(func.expr, printExpr, " "); + + public function printVar(v:Var) return + v.name + + opt(v.type, printComplexType, ":") + + opt(v.expr, printExpr, " = "); + + + public function printExpr(e:Expr) return e == null ? "#NULL" : switch(e.expr) { + #if macro + case EConst(CString(s)): haxe.macro.MacroStringTools.isFormatExpr(e) ? printFormatString(s) : printString(s); + #end + case EConst(c): printConstant(c); + case EArray(e1, e2): '${printExpr(e1)}[${printExpr(e2)}]'; + case EBinop(op, e1, e2): '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}'; + case EField(e1, n): '${printExpr(e1)}.$n'; + case EParenthesis(e1): '(${printExpr(e1)})'; + case EObjectDecl(fl): + "{ " + fl.map(function(fld) return '${fld.field} : ${printExpr(fld.expr)}').join(", ") + " }"; + case EArrayDecl(el): '[${printExprs(el, ", ")}]'; + case ECall(e1, el): '${printExpr(e1)}(${printExprs(el,", ")})'; + case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el,", ")})'; + case EUnop(op, true, e1): printExpr(e1) + printUnop(op); + case EUnop(op, false, e1): printUnop(op) + printExpr(e1); + case EFunction(no, func) if (no != null): 'function $no' + printFunction(func); + case EFunction(_, func): "function" +printFunction(func); + case EVars(vl): "var " +vl.map(printVar).join(", "); + case EBlock([]): '{ }'; + case EBlock(el): + var old = tabs; + tabs += tabString; + var s = '{\n$tabs' + printExprs(el, ';\n$tabs'); + tabs = old; + s + ';\n$tabs}'; + case EFor(e1, e2): 'for (${printExpr(e1)}) ${printExpr(e2)}'; + case EIn(e1, e2): '${printExpr(e1)} in ${printExpr(e2)}'; + case EIf(econd, eif, null): 'if (${printExpr(econd)}) ${printExpr(eif)}'; + case EIf(econd, eif, eelse): 'if (${printExpr(econd)}) ${printExpr(eif)} else ${printExpr(eelse)}'; + case EWhile(econd, e1, true): 'while (${printExpr(econd)}) ${printExpr(e1)}'; + case EWhile(econd, e1, false): 'do ${printExpr(e1)} while (${printExpr(econd)})'; + case ESwitch(e1, cl, edef): + var old = tabs; + tabs += tabString; + var s = 'switch ${printExpr(e1)} {\n$tabs' + + cl.map(function(c) + return 'case ${printExprs(c.values, ", ")}' + + (c.guard != null ? ' if (${printExpr(c.guard)}):' : ":") + + (c.expr != null ? (opt(c.expr, printExpr)) + ";" : "")) + .join('\n$tabs'); + if (edef != null) + s += '\n${tabs}default:' + (edef.expr == null ? "" : printExpr(edef) + ";"); + 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(""); + case EReturn(eo): "return" + opt(eo, printExpr, " "); + case EBreak: "break"; + case EContinue: "continue"; + case EUntyped(e1): "untyped " +printExpr(e1); + case EThrow(e1): "throw " +printExpr(e1); + case ECast(e1, cto) if (cto != null): 'cast(${printExpr(e1)}, ${printComplexType(cto)})'; + case ECast(e1, _): "cast " +printExpr(e1); + case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})'; + 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(meta, e1): printMetadata(meta) + " " +printExpr(e1); + } + + public function printExprs(el:Array, sep:String) { + return el.map(printExpr).join(sep); + } + + function printExtension(tpl:Array, fields: Array) { + return '{\n$tabs>' + tpl.map(printTypePath).join(',\n$tabs>') + "," + + (fields.length > 0 ? ('\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}") : ("\n}")); + } + + function printStructure(fields:Array) { + return fields.length == 0 ? "{ }" : + '{\n$tabs' + fields.map(printField).join(';\n$tabs') + ";\n}"; + } + + public function printTypeDefinition(t:TypeDefinition, printPackage = true):String { + var old = tabs; + tabs = tabString; + + var str = t == null ? "#NULL" : + (printPackage && t.pack.length > 0 && t.pack[0] != "" ? "package " + t.pack.join(".") + ";\n" : "") + + (t.meta != null && t.meta.length > 0 ? t.meta.map(printMetadata).join(" ") + " " : "") + (t.isExtern ? "extern " : "") + switch (t.kind) { + case TDEnum: + "enum " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "") + " {\n" + + [for (field in t.fields) + tabs + (field.doc != null && field.doc != "" ? "/**\n" + tabs + tabString + StringTools.replace(field.doc, "\n", "\n" + tabs + tabString) + "\n" + tabs + "**/\n" + tabs : "") + + (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join(" ") + " " : "") + + (switch(field.kind) { + case FVar(t, _): field.name + opt(t, printComplexType, ":"); + case FProp(_, _, _, _): throw "FProp is invalid for TDEnum."; + case FFun(func): field.name + printFunction(func); + }) + ";" + ].join("\n") + + "\n}"; + case TDStructure: + "typedef " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "") + " = {\n" + + [for (f in t.fields) { + tabs + printField(f) + ";"; + }].join("\n") + + "\n}"; + case TDClass(superClass, interfaces, isInterface): + (isInterface ? "interface " : "class ") + t.name + (t.params != null && t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "") + + (superClass != null ? " extends " + printTypePath(superClass) : "") + + (interfaces != null ? (isInterface ? [for (tp in interfaces) " extends " + printTypePath(tp)] : [for (tp in interfaces) " implements " + printTypePath(tp)]).join("") : "") + + " {\n" + + [for (f in t.fields) { + var fstr = printField(f); + tabs + fstr + switch(f.kind) { + case FVar(_, _), FProp(_, _, _, _): ";"; + case FFun({expr:null}): ";"; + case FFun({expr:{expr:EBlock(_)}}): ""; + case FFun(_): ";"; + case _: ""; + }; + }].join("\n") + + "\n}"; + case TDAlias(ct): + "typedef " + t.name + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "") + " = " + + (switch(ct) { + case TExtend(tpl, fields): printExtension(tpl, fields); + case TAnonymous(fields): printStructure(fields); + case _: printComplexType(ct); + }) + + ";"; + case TDAbstract(tthis, from, to): + "abstract " + t.name + + (t.params.length > 0 ? "<" + t.params.map(printTypeParamDecl).join(", ") + ">" : "") + + (tthis == null ? "" : "(" + printComplexType(tthis) + ")") + + (from == null ? "" : [for (f in from) " from " + printComplexType(f)].join("")) + + (to == null ? "" : [for (t in to) " to " + printComplexType(t)].join("")) + + " {\n" + + [for (f in t.fields) { + var fstr = printField(f); + tabs + fstr + switch(f.kind) { + case FVar(_, _), FProp(_, _, _, _): ";"; + case FFun(func) if (func.expr == null): ";"; + case _: ""; + }; + }].join("\n") + + "\n}"; + } + + tabs = old; + return str; + } + + function opt(v:T, f:T->String, prefix = "") return v == null ? "" : (prefix + f(v)); +} diff --git a/std/haxe/macro/Tools.hx b/std/haxe/macro/Tools.hx index 083093503cc90c4a2d8a38a95925bd4e5d4779d5..2c429687969943f282502ad1fde361111cc2297b 100644 --- a/std/haxe/macro/Tools.hx +++ b/std/haxe/macro/Tools.hx @@ -1,30 +1,33 @@ -/* - * Copyright (C)2005-2012 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.macro; - -/** - This class can be added via 'using haxe.macro.Tools' in order to enable - 'using' functionality on all macro tool classes listed below. -**/ -typedef TExprTools = ExprTools; -typedef TComplexTypeTools = ComplexTypeTools; -typedef TTypeTools = TypeTools; \ No newline at end of file +/* + * Copyright (C)2005-2012 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.macro; + +/** + This class can be added via 'using haxe.macro.Tools' in order to enable + 'using' functionality on all macro tool classes listed below. +**/ +typedef TExprTools = ExprTools; +typedef TComplexTypeTools = ComplexTypeTools; +typedef TTypeTools = TypeTools; +typedef TMacroStringTools = MacroStringTools; +typedef TTypedExprTools = TypedExprTools; +typedef TPositionTools = PositionTools; diff --git a/std/haxe/macro/Type.hx b/std/haxe/macro/Type.hx index d28c63a13469dfcd65ef19c53790d58e9d4365e4..366fafd0268d8f014a96b08069cd98963bc83a66 100644 --- a/std/haxe/macro/Type.hx +++ b/std/haxe/macro/Type.hx @@ -1,154 +1,349 @@ -/* - * Copyright (C)2005-2012 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.macro; - -typedef Ref = { - public function get() : T; - public function toString() : String; -} - -enum Type { - TMono( t : Ref> ); - TEnum( t : Ref, params : Array ); - TInst( t : Ref, params : Array ); - TType( t : Ref, params : Array ); - TFun( args : Array<{ name : String, opt : Bool, t : Type }>, ret : Type ); - TAnonymous( a : Ref ); - TDynamic( t : Null ); - TLazy( f : Void -> Type ); - TAbstract( t : Ref, params : Array ); -} - -typedef AnonType = { - var fields : Array; - //var status : AnonStatus; -} - -typedef BaseType = { - var pack : Array; - var name : String; - var module : String; - var pos : Expr.Position; - var isPrivate : Bool; - var isExtern : Bool; - var params : Array<{ name : String, t : Type }>; - var meta : MetaAccess; - var doc : Null; - function exclude() : Void; -} - -typedef ClassField = { - var name : String; - var type : Type; - var isPublic : Bool; - var params : Array<{ name : String, t : Type }>; - var meta : MetaAccess; - var kind : FieldKind; - function expr() : Null; - var pos : Expr.Position; - var doc : Null; -} - -enum ClassKind { - KNormal; - KTypeParameter(constraints:Array); - KExtension(cl:Ref, params:Array); - KExpr(expr:Expr); - KGeneric; - KGenericInstance(cl:Ref, params:Array); - KMacroType; - KAbstractImpl(a:Ref); -} - -typedef ClassType = {> BaseType, - var kind : ClassKind; - var isInterface : Bool; - var superClass : Null<{ t : Ref, params : Array }>; - var interfaces : Array<{ t : Ref, params : Array }>; - var fields : Ref>; - var statics : Ref>; - //var dynamic : Null; - //var arrayAccess : Null; - var constructor : Null>; - var init : Null; -} - -typedef EnumField = { - var name : String; - var type : Type; - var pos : Expr.Position; - var meta : MetaAccess; - var index : Int; - var doc : Null; - var params : Array<{ name : String, t : Type }>; -} - -typedef EnumType = {> BaseType, - var constructs : haxe.ds.StringMap; - var names : Array; -} - -typedef DefType = {> BaseType, - var type : Type; -} - - -typedef AbstractType = {>BaseType, - var type : Type; - var impl : Null>; - var binops : Array<{op:Expr.Binop, field:ClassField}>; - var unops : Array<{op:Expr.Unop, postFix:Bool, field:ClassField}>; - var from : Array<{t:Type, field:Null}>; - var to : Array<{t:Type, field:Null}>; - var array : Array; -} - -typedef MetaAccess = { - function get() : Expr.Metadata; - function add( name : String, params : Array, pos : Expr.Position ) : Void; - function remove( name : String ) : Void; - function has( name : String ) : Bool; -} - -enum FieldKind { - FVar( read : VarAccess, write : VarAccess ); - FMethod( k : MethodKind ); -} - -enum VarAccess { - AccNormal; - AccNo; - AccNever; - AccResolve; - AccCall; - AccInline; - AccRequire( r : String, ?msg : String ); -} - -enum MethodKind { - MethNormal; - MethInline; - MethDynamic; - MethMacro; -} - -extern enum TypedExpr {} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.macro; + +/* + Warning: Some of these types correspond to compiler-internal data structures + and might change in minor Haxe releases in order to adapt to internal changes. +*/ +typedef Ref = { + public function get() : T; + public function toString() : String; +} + +enum Type { + /** + Represents a monomorph. + + @see http://haxe.org/manual/types-monomorph.html + **/ + TMono( t : Ref> ); + + /** + Represents an enum instance. + + @see http://haxe.org/manual/types-enum-instance.html + **/ + TEnum( t : Ref, params : Array ); + + /** + Represents a class instance. + + @see http://haxe.org/manual/types-class-instance.html + **/ + TInst( t : Ref, params : Array ); + + /** + Represents a typedef. + + @see http://haxe.org/manual/type-system-typedef.html + **/ + TType( t : Ref, params : Array ); + + /** + Represents a function type. + + @see http://haxe.org/manual/types-function.html + **/ + TFun( args : Array<{ name : String, opt : Bool, t : Type }>, ret : Type ); + + /** + Represents an anonymous structure type. + + @see http://haxe.org/manual/types-anonymous-structure.html + **/ + TAnonymous( a : Ref ); + + /** + Represents Dynamic. + + @see http://haxe.org/manual/types-dynamic.html + **/ + TDynamic( t : Null ); + + /** + Used internally by the compiler to delay some typing. + **/ + TLazy( f : Void -> Type ); + + /** + Represents an abstract type. + + @see http://haxe.org/manual/types-abstract.html + **/ + TAbstract( t : Ref, params : Array ); +} + +typedef AnonType = { + var fields : Array; + var status : AnonStatus; +} + +enum AnonStatus { + AClosed; + AOpened; + AConst; + AExtend( tl:Ref> ); + AClassStatics( t : Ref ); + AEnumStatics( t : Ref ); + AAbstractStatics( t : Ref ); +} + +typedef TypeParameter = { + var name: String; + var t: Type; +} + +typedef BaseType = { + var pack : Array; + var name : String; + var module : String; + var pos : Expr.Position; + var isPrivate : Bool; + var isExtern : Bool; + var params : Array; + var meta : MetaAccess; + var doc : Null; + function exclude() : Void; +} + +typedef ClassField = { + var name : String; + var type : Type; + var isPublic : Bool; + var params : Array; + var meta : MetaAccess; + var kind : FieldKind; + function expr() : Null; + var pos : Expr.Position; + var doc : Null; +} + +enum ClassKind { + KNormal; + KTypeParameter(constraints:Array); + KExtension(cl:Ref, params:Array); + KExpr(expr:Expr); + KGeneric; + KGenericInstance(cl:Ref, params:Array); + KMacroType; + KAbstractImpl(a:Ref); + KGenericBuild; +} + +typedef ClassType = {> BaseType, + var kind : ClassKind; + var isInterface : Bool; + var superClass : Null<{ t : Ref, params : Array }>; + var interfaces : Array<{ t : Ref, params : Array }>; + var fields : Ref>; + var statics : Ref>; + //var dynamic : Null; + //var arrayAccess : Null; + var constructor : Null>; + var init : Null; + var overrides : Array>; +} + +typedef EnumField = { + var name : String; + var type : Type; + var pos : Expr.Position; + var meta : MetaAccess; + var index : Int; + var doc : Null; + var params : Array; +} + +typedef EnumType = {> BaseType, + var constructs : Map; + var names : Array; +} + +typedef DefType = {> BaseType, + var type : Type; +} + +typedef AbstractType = {>BaseType, + var type : Type; + var impl : Null>; + var binops : Array<{op:Expr.Binop, field:ClassField}>; + var unops : Array<{op:Expr.Unop, postFix:Bool, field:ClassField}>; + var from : Array<{t:Type, field:Null}>; + var to : Array<{t:Type, field:Null}>; + var array : Array; +} + +/** + MetaAccess is a wrapper for the `Metadata` array. It can be used to add + metadata to and remove metadata from its origin. +**/ +typedef MetaAccess = { + /** + Return the wrapped `Metadata` array. + + Modifying this array has no effect on the origin of `this` MetaAccess. + The `add` and `remove` methods can be used for that. + **/ + function get() : Expr.Metadata; + + /** + Extract metadata entries by given `name`. + + If there's no metadata with such name, empty array is returned. + + If `name` is null, compilation fails with an error. + **/ + function extract( name : String ) : Array; + + /** + Adds the metadata specified by `name`, `params` and `pos` to the origin + of `this` MetaAccess. + + Metadata names are not unique during compilation, so this method never + overwrites a previous metadata. + + If a `Metadata` array is obtained through a call to `get`, a subsequent + call to `add` has no effect on that array. + + If any argument is null, compilation fails with an error. + **/ + function add( name : String, params : Array, pos : Expr.Position ) : Void; + + /** + Removes all `name` metadata entries from the origin of `this` + MetaAccess. + + This method might clear several metadata entries of the same name. + + If a `Metadata` array is obtained through a call to `get`, a subsequent + call to `remove` has no effect on that array. + + If `name` is null, compilation fails with an error. + **/ + function remove( name : String ) : Void; + + /** + Tells if the origin of `this` MetaAccess has a `name` metadata entry. + + If `name` is null, compilation fails with an error. + **/ + function has( name : String ) : Bool; +} + +enum FieldKind { + FVar( read : VarAccess, write : VarAccess ); + FMethod( k : MethodKind ); +} + +enum VarAccess { + AccNormal; + AccNo; + AccNever; + AccResolve; + AccCall; + AccInline; + AccRequire( r : String, ?msg : String ); +} + +enum MethodKind { + MethNormal; + MethInline; + MethDynamic; + MethMacro; +} + +enum TConstant { + TInt(i:Int); + TFloat(s:String); + TString(s:String); + TBool(b:Bool); + TNull; + TThis; + TSuper; +} + +typedef TVar = { + public var id(default, never):Int; + public var name(default, never):String; + public var t(default, never):Type; + public var capture(default, never):Bool; + public var extra(default,never):Null<{params: Array, expr: Null}>; +} + +enum ModuleType { + TClassDecl(c:Ref); + TEnumDecl(e:Ref); + TTypeDecl(t:Ref); + TAbstract(a:Ref); +} + +typedef TFunc = { + args: Array<{v:TVar, value:Null}>, + t: Type, + expr: TypedExpr +} + +enum FieldAccess { + FInstance(c:Ref, params:Array, cf:Ref); + FStatic(c:Ref, cf:Ref); + FAnon(cf:Ref); + FDynamic(s:String); + FClosure(c:Null<{c:Ref, params:Array}>, cf:Ref); + FEnum(e:Ref, ef:EnumField); +} + +enum TypedExprDef { + TConst(c:TConstant); + TLocal(v:TVar); + TArray(e1:TypedExpr, e2:TypedExpr); + TBinop(op:Expr.Binop, e1:TypedExpr, e2:TypedExpr); + TField(e:TypedExpr, fa:FieldAccess); + TTypeExpr(m:ModuleType); + TParenthesis(e:TypedExpr); + TObjectDecl(fields:Array<{name:String, expr:TypedExpr}>); + TArrayDecl(el:Array); + TCall(e:TypedExpr, el:Array); + TNew(c:Ref, params: Array, el:Array); + TUnop(op:Expr.Unop, postFix:Bool, e:TypedExpr); + TFunction(tfunc:TFunc); + TVar(v:TVar, expr:Null); + TBlock(el:Array); + TFor(v:TVar, e1:TypedExpr, e2:TypedExpr); + TIf(econd:TypedExpr, eif:TypedExpr, eelse:Null); + TWhile(econd:TypedExpr, e:TypedExpr, normalWhile:Bool); + TSwitch(e:TypedExpr, cases:Array<{values:Array, expr:TypedExpr}>, edef:Null); + TTry(e:TypedExpr, catches:Array<{v:TVar, expr:TypedExpr}>); + TReturn(e:Null); + TBreak; + TContinue; + TThrow(e:TypedExpr); + TCast(e:TypedExpr, m:Null); + TMeta(m:Expr.MetadataEntry, e1:TypedExpr); + TEnumParameter(e1:TypedExpr, ef:EnumField, index:Int); +} + +typedef TypedExpr = { + expr: TypedExprDef, + pos: Expr.Position, + t: Type +} diff --git a/std/haxe/macro/TypeTools.hx b/std/haxe/macro/TypeTools.hx index 40663a11ca2a907866d32c1c0ecf78ff0fdf69f8..3bb179a3b7f8a134b1bff7dddebd13e9b7f81db2 100644 --- a/std/haxe/macro/TypeTools.hx +++ b/std/haxe/macro/TypeTools.hx @@ -1,106 +1,336 @@ -/* - * Copyright (C)2005-2013 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.macro; - -import haxe.macro.Context; -import haxe.macro.Expr; -import haxe.macro.Type; - -using Lambda; - -/** - This class provides some utility methods to work with types. It is - best used through 'using haxe.macro.TypeTools' syntax and then provides - additional methods on haxe.macro.Type instances. -**/ -class TypeTools { - #if macro - - /** - Follows all typedefs of [t] to reach the actual type. - - If [once] is true, this function does not call itself recursively, - otherwise it does. This can be useful in cases where intermediate - typedefs might be of interest. - - Affected types are monomorphs (TMono) and typedefs (TType(t,pl)). - - If [t] is null, an internal exception is thrown. - - Usage example: - var t = Context.typeof(macro null); // TMono() - var ts = Context.typeof(macro "foo"); //TInst(String,[]) - Context.unify(t, ts); - trace(t); // TMono() - trace(t.follow()); //TInst(String,[]) - **/ - static public inline function follow( t : Type, ?once : Bool ) : Type - return Context.follow(t, once); - - /** - Returns a syntax-level type corresponding to Type [t]. - - This function is mostly inverse to ComplexTypeTools.toType(), but may - lose some information on types that do not have a corresponding syntax - version, such as monomorphs. In these cases, the result is null. - - If [t] is null, an internal exception is thrown. - **/ - static public inline function toComplexType( t : Type ) : ComplexType - return Context.toComplexType(t); - - /** - Tries to extract the class instance stored inside [t]. - - If [t] is a class instance TInst(c,pl), c is returned. - - If [t] is of a different type, an exception of type String is thrown. - - If [t] is null, the result is null. - **/ - static public function getClass( t : Type ) return t == null ? null : switch(follow(t)) { - case TInst(c, _): c.get(); - case _: throw "Class instance expected"; - } - - /** - Tries to extract the enum instance stored inside [t]. - - If [t] is an enum instance TEnum(e,pl), e is returned. - - If [t] is of a different type, an exception of type String is thrown. - - If [t] is null, the result is null. - **/ - static public function getEnum( t : Type ) return t == null ? null : switch(follow(t)) { - case TEnum(e, _): e.get(); - case _: throw "Enum instance expected"; - } - - /** - Converts type [t] to a human-readable String representation. - **/ - static public function toString( t : Type ) : String return new String(Context.load("s_type", 1)(t)); - #end - -} \ No newline at end of file +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.macro.Type; + +using Lambda; + +/** + This class provides some utility methods to work with types. It is + best used through 'using haxe.macro.TypeTools' syntax and then provides + additional methods on haxe.macro.Type instances. +**/ +class TypeTools { + + static function nullable(complexType : ComplexType) : ComplexType return macro : Null<$complexType>; + + static function toField(cf : ClassField) : Field return { + function varAccessToString(va : VarAccess, getOrSet : String) : String return { + switch (va) { + case AccNormal: "default"; + case AccNo: "null"; + case AccNever: "never"; + case AccResolve: throw "Invalid TAnonymous"; + case AccCall: getOrSet; + case AccInline: "default"; + case AccRequire(_, _): "default"; + } + } + if (cf.params.length == 0) { + name: cf.name, + doc: cf.doc, + access: cf.isPublic ? [ APublic ] : [ APrivate ], + kind: switch([ cf.kind, cf.type ]) { + case [ FVar(read, write), ret ]: + FProp( + varAccessToString(read, "get"), + varAccessToString(write, "set"), + toComplexType(ret), + null); + case [ FMethod(_), TFun(args, ret) ]: + FFun({ + args: [ + for (a in args) { + name: a.name, + opt: a.opt, + type: toComplexType(a.t), + } + ], + ret: toComplexType(ret), + expr: null, + }); + default: + throw "Invalid TAnonymous"; + }, + pos: cf.pos, + meta: cf.meta.get(), + } else { + throw "Invalid TAnonymous"; + } + } + + + /** + Returns a syntax-level type corresponding to Type `t`. + + This function is mostly inverse to `ComplexTypeTools.toType`, but may + lose some information on types that do not have a corresponding syntax + version, such as monomorphs. In these cases, the result is null. + + If `t` is null, an internal exception is thrown. + **/ + public static function toComplexType(type : Null) : Null return + { + #if macro + Context.toComplexType(type); + #else + switch (type) { + case null: + null; + case TMono(_.get() => t): + t == null ? null : toComplexType(t); + case TEnum(_.get() => baseType, params): + TPath(toTypePath(baseType, params)); + case TInst(_.get() => classType, params): + switch (classType.kind) { + case KTypeParameter(_): + TPath({ + name: classType.name, + pack: [], + }); + default: + TPath(toTypePath(classType, params)); + } + case TType(_.get() => baseType, params): + TPath(toTypePath(baseType, params)); + case TFun(args, ret): + TFunction( + [ for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t) ], + toComplexType(ret)); + case TAnonymous(_.get() => { fields: fields }): + TAnonymous([ for (cf in fields) toField(cf) ]); + case TDynamic(t): + if (t == null) { + macro : Dynamic; + } else { + var ct = toComplexType(t); + macro : Dynamic<$ct>; + } + case TLazy(f): + toComplexType(f()); + case TAbstract(_.get() => baseType, params): + TPath(toTypePath(baseType, params)); + default: + throw "Invalid type"; + } + #end + } + + static function toTypePath(baseType : BaseType, params : Array) : TypePath return { + var module = baseType.module; + { + pack: baseType.pack, + name: module.substring(module.lastIndexOf(".") + 1), + sub: baseType.name, + params: [ for (t in params) TPType(toComplexType(t)) ], + } + } + + + #if macro + + /** + Follows all typedefs of `t` to reach the actual type. + + If `once` is true, this function does not call itself recursively, + otherwise it does. This can be useful in cases where intermediate + typedefs might be of interest. + + Affected types are monomorphs `TMono` and typedefs `TType(t,pl)`. + + If `t` is null, an internal exception is thrown. + + Usage example: + var t = Context.typeof(macro null); // TMono() + var ts = Context.typeof(macro "foo"); //TInst(String,[]) + Context.unify(t, ts); + trace(t); // TMono() + trace(t.follow()); //TInst(String,[]) + **/ + static public inline function follow( t : Type, ?once : Bool ) : Type + return Context.follow(t, once); + + /** + Returns true if `t1` and `t2` unify, false otherwise. + **/ + static public inline function unify( t1 : Type, t2:Type ) : Bool + return Context.unify(t1, t2); + + /** + Tries to extract the class instance stored inside `t`. + + If `t` is a class instance `TInst(c,pl)`, c is returned. + + If `t` is of a different type, an exception of type String is thrown. + + If `t` is null, the result is null. + **/ + static public function getClass( t : Type ) return t == null ? null : switch(follow(t)) { + case TInst(c, _): c.get(); + case _: throw "Class instance expected"; + } + + /** + Tries to extract the enum instance stored inside `t`. + + If `t` is an enum instance `TEnum(e,pl)`, e is returned. + + If `t` is of a different type, an exception of type String is thrown. + + If `t` is null, the result is null. + **/ + static public function getEnum( t : Type ) return t == null ? null : switch(follow(t)) { + case TEnum(e, _): e.get(); + case _: throw "Enum instance expected"; + } + + /** + Applies the type parameters `typeParameters` to type `t` with the given + types `concreteTypes`. + + This function replaces occurences of type parameters in `t` if they are + part of `typeParameters`. The array index of such a type parameter is + then used to lookup the concrete type in `concreteTypes`. + + If `typeParameters.length` is not equal to `concreteTypes.length`, an + exception of type `String` is thrown. + + If `typeParameters.length` is 0, `t` is returned unchanged. + + If either argument is `null`, the result is unspecified. + **/ + static public function applyTypeParameters(t:Type, typeParameters:Array, concreteTypes:Array):Type { + if (typeParameters.length != concreteTypes.length) + throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types'; + else if (typeParameters.length == 0) + return t; + return Context.load("apply_params", 3)(typeParameters.map(function(tp) return {name:untyped tp.name.__s, t:tp.t}), concreteTypes, t); + } + + /** + Transforms `t` by calling `f` on each of its subtypes. + + If `t` is a compound type, `f` is called on each of its components. + + Otherwise `t` is returned unchanged. + + The following types are considered compound: + - TInst, TEnum, TType and TAbstract with type parameters + - TFun + - TAnonymous + + If `t` or `f` are null, the result is unspecified. + **/ + static public function map(t:Type, f:Type -> Type):Type { + return switch(t) { + case TMono(tm): + switch(tm.get()) { + case null: t; + case t: f(t); + } + case TEnum(_, []) | TInst(_, []) | TType(_, []): + t; + case TEnum(en, tl): + TEnum(en, tl.map(f)); + case TInst(cl, tl): + TInst(cl, tl.map(f)); + case TType(t2, tl): + TType(t2, tl.map(f)); + case TAbstract(a, tl): + TAbstract(a, tl.map(f)); + case TFun(args, ret): + TFun(args.map(function(arg) return { + name: arg.name, + opt: arg.opt, + t: f(arg.t) + }), f(ret)); + case TAnonymous(an): + t; // TODO: Ref? + case TDynamic(t2): + t == t2 ? t : TDynamic(f(t2)); + case TLazy(ft): + var ft = ft(); + var ft2 = f(ft); + ft == ft2 ? t : ft2; + } + } + + /** + Calls function `f` on each component of type `t`. + + If `t` is not a compound type, this operation has no effect. + + The following types are considered compound: + - TInst, TEnum, TType and TAbstract with type parameters + - TFun + - TAnonymous + + If `t` or `f` are null, the result is unspecified. + **/ + static public function iter(t:Type, f:Type -> Void):Void { + switch (t) { + case TMono(tm): + var t = tm.get(); + if (t != null) f(t); + case TEnum(_, tl) | TInst(_, tl) | TType(_, tl) | TAbstract(_, tl): + for (t in tl) f(t); + case TDynamic(t2): + if (t != t2) f(t2); + case TLazy(ft): + f(ft()); + case TAnonymous(an): + for (field in an.get().fields) f(field.type); + case TFun(args, ret): + for (arg in args) f(arg.t); + f(ret); + } + } + + /** + Converts type `t` to a human-readable String representation. + **/ + static public function toString( t : Type ) : String return new String(Context.load("s_type", 1)(t)); + #end + + /** + Resolves the field named `name` on class `c`. + + If `isStatic` is true, the classes' static fields are checked. Otherwise + the classes' member fields are checked. + + If the field is found, it is returned. Otherwise if `c` has a super + class, `findField` recursively checks that super class. Otherwise null + is returned. + + If any argument is null, the result is unspecified. + **/ + static public function findField(c:ClassType, name:String, isStatic:Bool = false):Null { + var field = (isStatic ? c.statics : c.fields).get().find(function(field) return field.name == name); + return if(field != null) field; + else if (c.superClass != null) findField(c.superClass.t.get(), name, isStatic); + else null; + } +} diff --git a/std/haxe/macro/TypedExprTools.hx b/std/haxe/macro/TypedExprTools.hx new file mode 100644 index 0000000000000000000000000000000000000000..0a0177c2f28ac1d1b2ad6864920acce83341aca6 --- /dev/null +++ b/std/haxe/macro/TypedExprTools.hx @@ -0,0 +1,157 @@ +/* + * Copyright (C)2005-2013 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.macro; + +import haxe.macro.Type; + +class TypedExprTools { + static function with(e:TypedExpr, ?edef:TypedExprDef, ?t:Type) { + return { + expr: edef == null ? e.expr : edef, + pos: e.pos, + t: t == null ? e.t : t + } + } + + /** + Transforms the sub-expressions of [e] by calling [f] on each of them. + + See `haxe.macro.ExprTools.map` for details on expression mapping in + general. This function works the same way, but with a different data + structure. + **/ + static public function map(e:TypedExpr, f:TypedExpr -> TypedExpr):TypedExpr { + return switch(e.expr) { + case TConst(_) | TLocal(_) | TBreak | TContinue | TTypeExpr(_): e; + case TArray(e1, e2): with(e, TArray(f(e1), f(e2))); + case TBinop(op, e1, e2): with(e, TBinop(op, f(e1), f(e2))); + case TFor(v, e1, e2): with(e, TFor(v, f(e1), f(e2))); + case TWhile(e1, e2, flag): with(e, TWhile(f(e1), f(e2), flag)); + case TThrow(e1): with(e, TThrow(f(e1))); + case TEnumParameter(e1, ef, i): with(e, TEnumParameter(f(e1), ef, i)); + case TField(e1, fa): with(e, TField(f(e1), fa)); + case TParenthesis(e1): with(e, TParenthesis(f(e1))); + case TUnop(op, pre, e1): with(e, TUnop(op, pre, f(e1))); + case TArrayDecl(el): with(e, TArrayDecl(el.map(f))); + case TNew(t, pl, el): with(e, TNew(t, pl, el.map(f))); + case TBlock(el): with(e, TBlock(el.map(f))); + case TObjectDecl(fl): with(e, TObjectDecl(fl.map(function(field) return { name: field.name, expr: f(field.expr) }))); + case TCall(e1, el): with(e, TCall(f(e1), el.map(f))); + case TVar(v,eo): with(e, TVar(v, eo == null ? null : f(eo))); + case TFunction(fu): with(e, TFunction({ t: fu.t, args: fu.args, expr: f(fu.expr)})); + case TIf(e1, e2, e3): with(e, TIf(f(e1), f(e2), e3 == null ? null : f(e3))); + case TSwitch(e1, cases, e2): with(e, TSwitch(f(e1), cases.map(function(c) return { values: c.values.map(f), expr: f(c.expr) }), e2 == null ? null : f(e2))); + case TTry(e1, catches): with(e, TTry(f(e1), catches.map(function(c) return { v:c.v, expr: f(c.expr) }))); + case TReturn(e1): with(e, TReturn(e1 == null ? null : f(e1))); + case TCast(e1, mt): with(e, TCast(f(e1), mt)); + case TMeta(m, e1): with(e, TMeta(m, f(e1))); + } + } + + /** + Calls function [f] on each sub-expression of [e]. + + See `haxe.macro.ExprTools.iter` for details on iterating expressions in + general. This function works the same way, but with a different data + structure. + **/ + static public function iter(e:TypedExpr, f:TypedExpr -> Void):Void { + switch(e.expr) { + case TConst(_) | TLocal(_) | TBreak | TContinue | TTypeExpr(_): + case TArray(e1, e2) | TBinop(_, e1, e2) | TFor(_, e1, e2) | TWhile(e1, e2, _): + f(e1); + f(e2); + case TThrow(e1) | TEnumParameter(e1, _, _) | TField(e1, _) | TParenthesis(e1) | TUnop(_, _, e1) | TCast(e1, _) | TMeta(_, e1): + f(e1); + case TArrayDecl(el) | TNew(_, _, el) | TBlock(el): + for (e in el) f(e); + case TObjectDecl(fl): + for (field in fl) f(field.expr); + case TCall(e1, el): + f(e1); + for (e in el) f(e); + case TVar(_, e1) | TReturn(e1): + if (e1 != null) f(e1); + case TFunction(fu): + f(fu.expr); + case TIf(e1, e2, e3): + f(e1); + f(e2); + if (e3 != null) f(e3); + case TSwitch(e1, cases, e2): + f(e1); + for (c in cases) { + for (v in c.values) f(v); + f(c.expr); + } + if (e2 != null) f(e2); + case TTry(e1, catches): + f(e1); + for (c in catches) f(c.expr); + } + } + + /** + Transforms the sub-expressions of [e] by calling [f] on each of them. + Additionally, types are mapped using `ft` and variables are mapped using + `fv`. + + See `haxe.macro.ExprTools.map` for details on expression mapping in + general. This function works the same way, but with a different data + structure. + **/ + static public function mapWithType(e:TypedExpr, f:TypedExpr -> TypedExpr, ft:Type -> Type, fv:TVar -> TVar):TypedExpr { + return switch(e.expr) { + case TConst(_) | TBreak | TContinue | TTypeExpr(_): with(e, ft(e.t)); + case TLocal(v): with(e, TLocal(fv(v)), ft(e.t)); + case TArray(e1, e2): with(e, TArray(f(e1), f(e2)), ft(e.t)); + case TBinop(op, e1, e2): with(e, TBinop(op, f(e1), f(e2)), ft(e.t)); + case TFor(v, e1, e2): with(e, TFor(fv(v), f(e1), f(e2)), ft(e.t)); + case TWhile(e1, e2, flag): with(e, TWhile(f(e1), f(e2), flag), ft(e.t)); + case TThrow(e1): with(e, TThrow(f(e1)), ft(e.t)); + case TEnumParameter(e1, ef, i): with(e, TEnumParameter(f(e1), ef, i), ft(e.t)); + case TField(e1, fa): with(e, TField(f(e1), fa), ft(e.t)); + case TParenthesis(e1): with(e, TParenthesis(e1), ft(e.t)); + case TUnop(op, pre, e1): with(e, TUnop(op, pre, f(e1)), ft(e.t)); + case TArrayDecl(el): with(e, TArrayDecl(el.map(f)), ft(e.t)); + case TNew(t, pl, el): with(e, TNew(t, pl, el.map(f)), ft(e.t)); + case TBlock(el): with(e, TBlock(el.map(f)), ft(e.t)); + case TObjectDecl(fl): with(e, TObjectDecl(fl.map(function(field) return { name: field.name, expr: f(field.expr) })), ft(e.t)); + case TCall(e1, el): with(e, TCall(f(e1), el.map(f)), ft(e.t)); + case TVar(v,eo): with(e, TVar(fv(v), eo == null ? null : f(eo)), ft(e.t)); + case TFunction(fu): with(e, TFunction({ t: ft(fu.t), args: fu.args.map(function(arg) return { v: fv(arg.v), value: arg.value }), expr: f(fu.expr)}), ft(e.t)); + case TIf(e1, e2, e3): with(e, TIf(f(e1), f(e2), e3 == null ? null : f(e3)), ft(e.t)); + case TSwitch(e1, cases, e2): with(e, TSwitch(f(e1), cases.map(function(c) return { values: c.values.map(f), expr: f(c.expr) }), e2 == null ? null : f(e2)), ft(e.t)); + case TTry(e1, catches): with(e, TTry(f(e1), catches.map(function(c) return { v:fv(c.v), expr: f(c.expr) })), ft(e.t)); + case TReturn(e1): with(e, TReturn(e1 == null ? null : f(e1)), ft(e.t)); + case TCast(e1, mt): with(e, TCast(f(e1), mt), ft(e.t)); + case TMeta(m, e1): with(e, TMeta(m, f(e1)), ft(e.t)); + } + } + + #if macro + static public function toString(t:TypedExpr, ?pretty = false):String { + return new String(haxe.macro.Context.load("s_expr", 2)(t, pretty)); + } + #end +} diff --git a/std/haxe/remoting/AMFConnection.hx b/std/haxe/remoting/AMFConnection.hx index 95a0b9ff0fcb3b165db950a2670be4a855c70927..fe0a2920547b60c94843fea6e5b814fecfb4e4c1 100644 --- a/std/haxe/remoting/AMFConnection.hx +++ b/std/haxe/remoting/AMFConnection.hx @@ -25,10 +25,8 @@ class AMFConnection implements AsyncConnection implements Dynamic Void, - #if flash9 + #if flash cnx : flash.net.NetConnection, - #elseif flash - cnx : flash.NetConnection, #else cnx : Dynamic, #end @@ -57,7 +55,7 @@ class AMFConnection implements AsyncConnection implements Dynamic, ?onResult : Dynamic -> Void ) : Void { if( onResult == null ) onResult = function(e) {}; var p = params.copy(); - #if flash9 + #if flash p.unshift(new flash.net.Responder(onResult,__data.error)); #else p.unshift({ onStatus : __data.error, onResult : onResult }); @@ -68,7 +66,6 @@ class AMFConnection implements AsyncConnection implements Dynamic ) { untyped __global__[ "flash.net.registerClassAlias" ]( s, cl ); } #end - #end - } diff --git a/std/haxe/remoting/ExternalConnection.hx b/std/haxe/remoting/ExternalConnection.hx index f81d89e9ee80a1f0675170c3f9b667c4d449a855..57c98d61720ab2abd8ff08f88526665c4699c412 100644 --- a/std/haxe/remoting/ExternalConnection.hx +++ b/std/haxe/remoting/ExternalConnection.hx @@ -45,14 +45,10 @@ class ExternalConnection implements Connection implements Dynamic { connections.remove(__data.name); } - #if flash9 + #if flash static function escapeString( s : String ) { return s.split("\\").join("\\\\"); } - #elseif flash - static function escapeString( s : String ) { - return s.split("\\").join("\\\\").split("&").join("&"); - } #else static inline function escapeString(s) { return s; @@ -67,8 +63,8 @@ class ExternalConnection implements Connection implements Dynamic { #if flash data = flash.external.ExternalInterface.call("haxe.remoting.ExternalConnection.doCall",__data.name,__path.join("."),params); #elseif js - var fobj : Dynamic = untyped window.document[__data.flash]; - if( fobj == null ) fobj = untyped window.document.getElementById(__data.flash); + var fobj : Dynamic = (untyped js.Browser.document)[cast __data.flash]; // FIXME(bruno): Why is this necessary? + if( fobj == null ) fobj = js.Browser.document.getElementById(__data.flash); if( fobj == null ) throw "Could not find flash object '"+__data.flash+"'"; try data = fobj.externalRemotingCall(__data.name,__path.join("."),params) catch( e : Dynamic ) {}; #end @@ -78,7 +74,7 @@ class ExternalConnection implements Connection implements Dynamic { try { // check that swf in on the same domain domain = fobj.src.split("/")[2]; - pageDomain = js.Browser.window.location.host; + pageDomain = js.Browser.location.host; } catch( e : Dynamic ) { domain = null; pageDomain = null; @@ -123,11 +119,7 @@ class ExternalConnection implements Connection implements Dynamic { public static function jsConnect( name : String, ?ctx : Context ) { if( !flash.external.ExternalInterface.available ) throw "External Interface not available"; - #if flash9 try flash.external.ExternalInterface.addCallback("externalRemotingCall",doCall) catch( e : Dynamic ) {}; - #else - flash.external.ExternalInterface.addCallback("externalRemotingCall",null,doCall); - #end var cnx = new ExternalConnection({ name : name, ctx : ctx },[]); connections.set(name,cnx); return cnx; diff --git a/std/haxe/remoting/FlashJsConnection.hx b/std/haxe/remoting/FlashJsConnection.hx index 87b6fb6f21adc4155ac838f29dee08af1a205d97..11ba2b09cb988f5cb834fbd2a32f9666c74870d5 100644 --- a/std/haxe/remoting/FlashJsConnection.hx +++ b/std/haxe/remoting/FlashJsConnection.hx @@ -90,7 +90,7 @@ class FlashJsConnection #if flash implements AsyncConnection implements Dynamic< static var connections = new haxe.ds.StringMap(); static function escapeString( s : String ) { - #if flash9 + #if flash return s.split("\\").join("\\\\"); #else return s.split("\\").join("\\\\").split("&").join("&"); @@ -120,11 +120,7 @@ class FlashJsConnection #if flash implements AsyncConnection implements Dynamic< public static function connect( name : String, objId : String, ?ctx : Context ) { if( !flash.external.ExternalInterface.available ) throw "External Interface not available"; - #if flash9 try flash.external.ExternalInterface.addCallback("flashJsRemotingCall",doCall) catch( e : Dynamic ) {}; - #else - flash.external.ExternalInterface.addCallback("flashJsRemotingCall",null,doCall); - #end var cnx = new FlashJsConnection({ id : objId, name : name, @@ -141,8 +137,8 @@ class FlashJsConnection #if flash implements AsyncConnection implements Dynamic< static function flashCall( flashObj : String, name : String, path : String, params : String ) : String { try { - var fobj : Dynamic = untyped window.document[flashObj]; - if( fobj == null ) fobj = untyped window.document.getElementById[flashObj]; + var fobj : Dynamic = untyped (untyped js.Browser.document)[__data.flash]; // FIXME(bruno): Why is this necessary? + if( fobj == null ) fobj = js.Browser.document.getElementById(flashObj); if( fobj == null ) throw "Could not find flash object '"+flashObj+"'"; var data = null; try data = fobj.flashJsRemotingCall(name,path,params) catch( e : Dynamic ) {}; diff --git a/std/haxe/remoting/LocalConnection.hx b/std/haxe/remoting/LocalConnection.hx index d33f2c00909f2eb3ff9fcc34fa384037ae734f07..033e25f004f7fb09c67837e0b4f8c31d09e58a6a 100644 --- a/std/haxe/remoting/LocalConnection.hx +++ b/std/haxe/remoting/LocalConnection.hx @@ -31,10 +31,8 @@ class LocalConnection implements AsyncConnection implements Dynamic Void, result : Dynamic -> Void }>, error : Dynamic -> Void, target : String, - #if flash9 + #if flash cnx : flash.net.LocalConnection, - #elseif flash - cnx : flash.LocalConnection, #else cnx : Dynamic, #end @@ -58,7 +56,7 @@ class LocalConnection implements AsyncConnection implements Dynamic, ?onResult : Dynamic -> Void ) : Void { try { var id = ID++; - #if flash9 + #if flash __data.cnx.send(__data.target,"remotingCall",id,__path.join("."),haxe.Serializer.run(params)); #else if( !__data.cnx.send(__data.target,"remotingCall",id,__path.join("."),haxe.Serializer.run(params)) ) @@ -107,11 +105,7 @@ class LocalConnection implements AsyncConnection implements Dynamic ) { - #if flash9 - var l = new flash.net.LocalConnection(); - #else - var l = new flash.LocalConnection(); - #end + var l = new flash.net.LocalConnection(); var recv = name + "_recv"; var c = new LocalConnection({ ctx : ctx, @@ -120,44 +114,23 @@ class LocalConnection implements AsyncConnection implements Dynamic Void, onError : Dynamic -> Void }>, log : Array -> Array -> Dynamic -> Void, error : Dynamic -> Void, - #if !flash9 - #if (flash || js) + #if js queue : Array Void>, timer : haxe.Timer, #end - #end }; function new(data,path) { @@ -110,8 +108,6 @@ class SocketConnection implements AsyncConnection implements Dynamic +typedef FunctionArgument = { name : String, opt : Bool, t : CType, ?value:String } + enum CType { CUnknown; CEnum( name : Path, params : List ); CClass( name : Path, params : List ); CTypedef( name : Path, params : List ); - CFunction( args : List<{ name : String, opt : Bool, t : CType }>, ret : CType ); + CFunction( args : List, ret : CType ); CAnonymous( fields : List ); CDynamic( ?t : CType ); CAbstract( name : Path, params : List ); @@ -59,13 +61,15 @@ typedef ClassField = { var type : CType; var isPublic : Bool; var isOverride : Bool; - var doc : String; + var doc : Null; var get : Rights; var set : Rights; var params : TypeParams; var platforms : Platforms; var meta : MetaData; var line : Null; + var overloads : Null>; + var expr : Null; } typedef TypeInfos = { @@ -73,7 +77,7 @@ typedef TypeInfos = { var module : Path; var file : Null; var params : TypeParams; - var doc : String; + var doc : Null; var isPrivate : Bool; var platforms : Platforms; var meta : MetaData; @@ -82,7 +86,7 @@ typedef TypeInfos = { typedef Classdef = {> TypeInfos, var isExtern : Bool; var isInterface : Bool; - var superClass : PathParams; + var superClass : Null; var interfaces : List; var fields : List; var statics : List; @@ -104,12 +108,14 @@ typedef Enumdef = {> TypeInfos, typedef Typedef = {> TypeInfos, var type : CType; - var types : haxe.ds.StringMap; // by platform + var types : Map; // by platform } typedef Abstractdef = {> TypeInfos, - var subs : Array; - var supers : Array; + var to : Array<{t:CType, field:Null}>; + var from : Array<{t:CType, field:Null}>; + var impl : Classdef; + var athis : CType; } enum TypeTree { @@ -202,7 +208,7 @@ class TypeApi { case CFunction(args,ret): switch( t2 ) { case CFunction(args2,ret2): - return leq(function(a,b) { + return leq(function(a:FunctionArgument,b:FunctionArgument) { return a.name == b.name && a.opt == b.opt && typeEq(a.t,b.t); },args,args2) && typeEq(ret,ret2); default: @@ -258,3 +264,43 @@ class TypeApi { } } + +class CTypeTools { + static public function toString(t:CType):String { + return switch (t) { + case CUnknown: + "unknown"; + case CClass(name, params), CEnum(name, params), CTypedef(name, params), CAbstract(name, params): + nameWithParams(name, params); + case CFunction(args, ret): + if (args.length == 0) { + "Void -> " +toString(ret); + } else { + args.map(functionArgumentName).join(" -> "); + } + case CDynamic(d): + if (d == null) { + "Dynamic"; + } else { + "Dynamic<" + toString(d) + ">"; + } + case CAnonymous(fields): + "{ " + fields.map(classField).join(", "); + } + } + + static function nameWithParams(name:String, params:List) { + if (params.length == 0) { + return name; + } + return name + "<" + params.map(toString).join(", ") + ">"; + } + + static function functionArgumentName(arg:FunctionArgument) { + return (arg.opt ? "?" : "") + arg.name + ":" + toString(arg.t) + (arg.value == null ? "" : " = " +arg.value); + } + + static function classField(cf:ClassField) { + return cf.name + ":" +toString(cf.type); + } +} \ No newline at end of file diff --git a/std/haxe/rtti/Meta.hx b/std/haxe/rtti/Meta.hx index 28baf76c6f457c258747bf58e51badc921c77f22..eebfff5f291b7d49649e07ce253f94346525897c 100644 --- a/std/haxe/rtti/Meta.hx +++ b/std/haxe/rtti/Meta.hx @@ -1,65 +1,78 @@ -/* - * Copyright (C)2005-2012 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.rtti; - -/** - An api to access classes and enums metadata at runtime. -**/ -class Meta { - - /** - Returns the metadata that were declared for the given type (class or enum) - **/ - public static function getType( t : Dynamic ) : Dynamic> { - #if (java || cs) - var meta : Dynamic = Reflect.field(t, "__meta__"); - #else - var meta : Dynamic = untyped t.__meta__; - #end - return (meta == null || meta.obj == null) ? {} : meta.obj; - } - - /** - Returns the metadata that were declared for the given class static fields - **/ - public static function getStatics( t : Dynamic ) : Dynamic>> { - #if (java || cs) - var meta : Dynamic = Reflect.field(t, "__meta__"); - #else - var meta : Dynamic = untyped t.__meta__; - #end - return (meta == null || meta.statics == null) ? {} : meta.statics; - } - - /** - Returns the metadata that were declared for the given class fields or enum constructors - **/ - public static function getFields( t : Dynamic ) : Dynamic>> { - #if (java || cs) - var meta : Dynamic = Reflect.field(t, "__meta__"); - #else - var meta : Dynamic = untyped t.__meta__; - #end - return (meta == null || meta.fields == null) ? {} : meta.fields; - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.rtti; + +/** + An api to access classes and enums metadata at runtime. +**/ +class Meta { + + /** + Returns the metadata that were declared for the given type (class or enum) + **/ + public static function getType( t : Dynamic ) : Dynamic> { + var meta = getMeta(t); + return (meta == null || meta.obj == null) ? {} : meta.obj; + } + + private static function getMeta(t:Dynamic):Dynamic + { +#if (java || cs) + var ret = Reflect.field(t, "__meta__"); + if (ret == null && Std.is(t,Class)) + { +#if java + var interf = java.Lib.toNativeType(t).isInterface(); +#elseif cs + var interf = cs.Lib.toNativeType(t).IsInterface; +#end + if (interf) + { + var name = Type.getClassName(t), + cls = Type.resolveClass(name + '_HxMeta'); + if (cls != null) + return Reflect.field(cls, "__meta__"); + } + } + return ret; +#else + return untyped t.__meta__; +#end + } + + /** + Returns the metadata that were declared for the given class static fields + **/ + public static function getStatics( t : Dynamic ) : Dynamic>> { + var meta = getMeta(t); + return (meta == null || meta.statics == null) ? {} : meta.statics; + } + + /** + Returns the metadata that were declared for the given class fields or enum constructors + **/ + public static function getFields( t : Dynamic ) : Dynamic>> { + var meta = getMeta(t); + return (meta == null || meta.fields == null) ? {} : meta.fields; + } + +} diff --git a/std/js/html/Entity.hx b/std/haxe/rtti/Rtti.hx similarity index 51% rename from std/js/html/Entity.hx rename to std/haxe/rtti/Rtti.hx index 52fdbc56f191c82ec83e0c562cd109075ade45c4..a6d7ea2ad25f0c71c8f38ae6acab801af7e9c469 100644 --- a/std/js/html/Entity.hx +++ b/std/haxe/rtti/Rtti.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2014 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,19 +20,41 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html; +package haxe.rtti; +import haxe.rtti.CType; -/**

NOTE: This is not implemented in Mozilla

-

Read-only reference to a DTD entity. Also inherits the methods and properties of Node.



-Documentation for this class was provided by MDN. */ -@:native("Entity") -extern class Entity extends Node -{ - var notationName(default,null) : String; +/** + Rtti is a helper class which supplements the `@:rtti` metadata. +**/ +class Rtti { - var publicId(default,null) : String; + /** + Returns the `haxe.rtti.CType.Classdef` corresponding to class `c`. - var systemId(default,null) : String; + If `c` has no runtime type information, e.g. because no `@:rtti@` was + added, `null` is returned. -} + If `c` is null, the result is unspecified. + **/ + static public function getRtti(c:Class):Classdef { + var rtti = Reflect.field(c, "__rtti"); + if (rtti == null) { + throw 'Class ${Type.getClassName(c)} has no RTTI information, consider adding @:rtti'; + } + var x = Xml.parse(rtti).firstElement(); + var infos = new haxe.rtti.XmlParser().processElement(x); + switch (infos) { + case TClassdecl(c): return c; + case t: throw 'Enum mismatch: expected TClassDecl but found $t'; + } + } + + /** + Tells if `c` has runtime type information. + + If `c` is null, the result is unspecified. + **/ + static public function hasRtti(c:Class):Bool { + return Lambda.has(Type.getClassFields(c), "__rtti"); + } +} \ No newline at end of file diff --git a/std/haxe/rtti/XmlParser.hx b/std/haxe/rtti/XmlParser.hx index dad3b906ddda45d798b2b3dc27c94cd92d543b47..d445664af7a17bfdd5b4e431166d27b355bf1a65 100644 --- a/std/haxe/rtti/XmlParser.hx +++ b/std/haxe/rtti/XmlParser.hx @@ -91,12 +91,12 @@ class XmlParser { f1.set = RMethod; return true; } - return false; + return Type.enumEq(f1.get, f2.get) && Type.enumEq(f1.set, f2.set); } function mergeDoc( f1 : ClassField, f2 : ClassField ) { if( f1.doc == null ) - f2.doc = f2.doc; + f1.doc = f2.doc; else if( f2.doc == null ) f2.doc = f1.doc; return true; @@ -178,14 +178,15 @@ class XmlParser { function mergeAbstracts( a : Abstractdef, a2 : Abstractdef ) { if( curplatform == null ) return false; - if( a.subs.length != a2.subs.length || a.supers.length != a2.supers.length ) + if( a.to.length != a2.to.length || a.from.length != a2.from.length ) return false; - for( i in 0...a.subs.length ) - if( !TypeApi.typeEq(a.subs[i],a2.subs[i]) ) + for( i in 0...a.to.length ) + if( !TypeApi.typeEq(a.to[i].t,a2.to[i].t) ) return false; - for( i in 0...a.supers.length ) - if( !TypeApi.typeEq(a.supers[i],a2.supers[i]) ) + for( i in 0...a.from.length ) + if( !TypeApi.typeEq(a.from[i].t,a2.from[i].t) ) return false; + if (a2.impl != null) mergeClasses(a.impl, a2.impl); a.platforms.add(curplatform); return true; } @@ -231,6 +232,7 @@ class XmlParser { else tinf.doc = inf.doc; } + if (tinf.path == "haxe._Int64.NativeInt64") continue; if( tinf.module == inf.module && tinf.doc == inf.doc && tinf.isPrivate == inf.isPrivate ) switch( ct ) { case TClassdecl(c): @@ -332,6 +334,14 @@ class XmlParser { return ml; } + function xoverloads( x : Fast ) : List { + var l = new List(); + for ( m in x.elements ) { + l.add(xclassfield(m)); + } + return l; + } + function xpath( x : Fast ) : PathParams { var path = mkPath(x.att.path); var params = new List(); @@ -383,15 +393,17 @@ class XmlParser { }; } - function xclassfield( x : Fast, ?defPublic ) : ClassField { + function xclassfield( x : Fast, ?defPublic = false ) : ClassField { var e = x.elements; var t = xtype(e.next()); var doc = null; var meta = []; + var overloads = null; for( c in e ) switch( c.name ) { case "haxe_doc": doc = c.innerData; case "meta": meta = xmeta(c); + case "overloads": overloads = xoverloads(c); default: xerror(c); } return { @@ -403,9 +415,11 @@ class XmlParser { doc : doc, get : if( x.has.get ) mkRights(x.att.get) else RNormal, set : if( x.has.set ) mkRights(x.att.set) else RNormal, - params : if( x.has.params ) mkTypeParams(x.att.params) else null, + params : if( x.has.params ) mkTypeParams(x.att.params) else [], platforms : defplat(), meta : meta, + overloads: overloads, + expr : if( x.has.expr ) x.att.expr else null }; } @@ -465,8 +479,8 @@ class XmlParser { } function xabstract( x : Fast ) : Abstractdef { - var doc = null; - var meta = [], subs = [], supers = []; + var doc = null, impl = null, athis = null; + var meta = [], to = [], from = []; for( c in x.elements ) switch( c.name ) { case "haxe_doc": @@ -475,10 +489,14 @@ class XmlParser { meta = xmeta(c); case "to": for( t in c.elements ) - subs.push(xtype(t)); + to.push({t: xtype(new Fast(t.x.firstElement())), field: t.has.field ? t.att.field : null}); case "from": for( t in c.elements ) - supers.push(xtype(t)); + from.push({t: xtype(new Fast(t.x.firstElement())), field: t.has.field ? t.att.field : null}); + case "impl": + impl = xclass(c.node.resolve("class")); + case "this": + athis = xtype(new Fast(c.x.firstElement())); default: xerror(c); } @@ -491,8 +509,10 @@ class XmlParser { params : mkTypeParams(x.att.params), platforms : defplat(), meta : meta, - subs : subs, - supers : supers, + athis : athis, + to : to, + from : from, + impl: impl }; } @@ -541,6 +561,7 @@ class XmlParser { var args = new List(); var aname = x.att.a.split(":"); var eargs = aname.iterator(); + var evalues = x.has.v ? x.att.v.split(":").iterator() : null; for( e in x.elements ) { var opt = false; var a = eargs.next(); @@ -550,10 +571,12 @@ class XmlParser { opt = true; a = a.substr(1); } + var v = evalues == null ? null : evalues.next(); args.add({ name : a, opt : opt, t : xtype(e), + value : v == "" ? null : v }); } var ret = args.last(); diff --git a/std/haxe/unit/TestCase.hx b/std/haxe/unit/TestCase.hx index e1830fa18809f83ae95ad8b770b27afcb8db1bbe..8c90e9b82b26b143357be8334185e1c4b2da5de6 100644 --- a/std/haxe/unit/TestCase.hx +++ b/std/haxe/unit/TestCase.hx @@ -24,7 +24,7 @@ import haxe.PosInfos; @:keepSub @:publicFields -class TestCase #if mt_build implements mt.Protect #end { +class TestCase { public var currentTest : TestStatus; public function new( ) { @@ -42,7 +42,7 @@ class TestCase #if mt_build implements mt.Protect #end { function assertTrue( b:Bool, ?c : PosInfos ) : Void { currentTest.done = true; - if (b == false){ + if (b != true){ currentTest.success = false; currentTest.error = "expected true but was false"; currentTest.posInfos = c; diff --git a/std/haxe/unit/TestRunner.hx b/std/haxe/unit/TestRunner.hx index 8d191a166c343678e3ce03996feaae26c7a1c1ed..5937f41599d53b4e49861a7b331bfdf0d6af26fc 100644 --- a/std/haxe/unit/TestRunner.hx +++ b/std/haxe/unit/TestRunner.hx @@ -26,14 +26,12 @@ class TestRunner { public var result(default, null) : TestResult; var cases : List; -#if flash9 +#if flash static var tf : flash.text.TextField = null; -#elseif flash - static var tf : flash.TextField = null; #end public static dynamic function print( v : Dynamic ) untyped { - #if flash9 + #if flash if( tf == null ) { tf = new flash.text.TextField(); tf.selectable = false; @@ -42,21 +40,6 @@ class TestRunner { flash.Lib.current.addChild(tf); } tf.appendText(v); - #elseif flash - var root = flash.Lib.current; - if( tf == null ) { - root.createTextField("__tf",1048500,0,0,flash.Stage.width,flash.Stage.height+30); - tf = root.__tf; - tf.selectable = false; - tf.wordWrap = true; - } - var s = flash.Boot.__string_rec(v,""); - tf.text += s; - while( tf.textHeight > flash.Stage.height ) { - var lines = tf.text.split("\r"); - lines.shift(); - tf.text = lines.join("\n"); - } #elseif neko __dollar__print(v); #elseif php @@ -64,18 +47,28 @@ class TestRunner { #elseif cpp cpp.Lib.print(v); #elseif js - var msg = StringTools.htmlEscape(js.Boot.__string_rec(v,"")).split("\n").join("
"); - var d = document.getElementById("haxe:trace"); - if( d == null ) - alert("haxe:trace element not found") - else - d.innerHTML += msg; + var msg = js.Boot.__string_rec(v,""); + var d; + if( __js__("typeof")(document) != "undefined" + && (d = document.getElementById("haxe:trace")) != null ) { + msg = StringTools.htmlEscape(msg).split("\n").join("
"); + d.innerHTML += msg+"
"; + } + else if ( __js__("typeof process") != "undefined" + && __js__("process").stdout != null + && __js__("process").stdout.write != null) + __js__("process").stdout.write(msg); // node + else if ( __js__("typeof console") != "undefined" + && __js__("console").log != null ) + __js__("console").log(msg); // document-less js (which may include a line break) + #elseif cs - var str:String = v; - untyped __cs__("System.Console.Write(str)"); + cs.system.Console.Write(v); #elseif java var str:String = v; untyped __java__("java.lang.System.out.print(str)"); + #elseif python + python.Lib.print(v); #end } diff --git a/std/haxe/web/Dispatch.hx b/std/haxe/web/Dispatch.hx index 7723344afc6234c103f61b2873949cadbaa9d555..0fe0dfc6843cd7324ca186509658fbf86ba96755 100644 --- a/std/haxe/web/Dispatch.hx +++ b/std/haxe/web/Dispatch.hx @@ -1,453 +1,480 @@ -/* - * Copyright (C)2005-2012 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.web; - -#if macro -import haxe.macro.Expr; -import haxe.macro.Type.ClassField; -import haxe.macro.Context; -#end - -typedef DispatchConfig = { - var obj : Dynamic; - var rules : Dynamic; -} - -typedef Lock = T; - -enum MatchRule { - MRInt; - MRBool; - MRFloat; - MRString; - MRDispatch; - MRSpod( c : String, lock : Bool ); - MROpt( r : MatchRule ); -} - -enum DispatchRule { - DRMatch( r : MatchRule ); - DRMult( r : Array ); - DRArgs( r : DispatchRule, args : Array<{ name : String, rule : MatchRule, opt : Bool }>, opt : Bool ); - DRMeta( r : DispatchRule ); -} - -enum DispatchError { - DENotFound( part : String ); - DEInvalidValue; - DEMissing; - DEMissingParam( p : String ); - DETooManyValues; -} - -private class Redirect { - public function new() { - } -} - -class Dispatch { - - public var parts : Array; - public var params : haxe.ds.StringMap; - public var name : String; - public var cfg : DispatchConfig; - var subDispatch : Bool; - - public function new(url:String, params) { - parts = url.split("/"); - if( parts[0] == "" ) parts.shift(); - this.params = params; - } - - public macro function dispatch( ethis : Expr, obj : ExprOf<{}> ) : ExprOf { - var p = Context.currentPos(); - var cfg = makeConfig(obj); - return { expr : ECall({ expr : EField(ethis, "runtimeDispatch"), pos : p }, [cfg]), pos : p }; - } - - public macro function getParams( ethis : Expr ) : Expr { - var p = Context.currentPos(); - if( PARAMS == null ) { - PARAMS = new Array(); - Context.onGenerate(buildParams); - } - var index = PARAMS.length; - var t = Context.typeof({ expr : EConst(CIdent("null")), pos : p }); - PARAMS.push( { p : p, t : t } ); - var call = { expr : ECall( { expr : EField(ethis, "runtimeGetParams"), pos : p }, [ { expr : EConst(CInt(Std.string(index))), pos : p } ]), pos : p }; - var rt = TPath( { pack : ["haxe", "macro"], name : "MacroType", params : [TPExpr(Context.parse("haxe.web.Dispatch.getRunParam("+index+")",p))], sub : null } ); - return { expr : EBlock([ { expr : EVars([ { name : "tmp", type : rt, expr : call } ]), pos : p }, { expr : EConst(CIdent("tmp")), pos : p } ]), pos : p }; - } - - public dynamic function onMeta( v : String, args : Null> ) { - } - - function resolveName( name : String ) { - return name; - } - - public function runtimeDispatch( cfg : DispatchConfig ) { - name = parts.shift(); - if( name == null ) - name = "default"; - name = resolveName(name); - this.cfg = cfg; - var r : DispatchRule = Reflect.field(cfg.rules, name); - if( r == null ) { - r = Reflect.field(cfg.rules, "default"); - if( r == null ) - throw DENotFound(name); - parts.unshift(name); - name = "default"; - } - name = "do" + name.charAt(0).toUpperCase() + name.substr(1); - var args = []; - subDispatch = false; - loop(args, r); - if( parts.length > 0 && !subDispatch ) { - if( parts.length == 1 && parts[parts.length - 1] == "" ) parts.pop() else throw DETooManyValues; - } - try { - Reflect.callMethod(cfg.obj, Reflect.field(cfg.obj, name), args); - } catch( e : Redirect ) { - runtimeDispatch(cfg); - } - } - - public function redirect( url : String, ?params : haxe.ds.StringMap ) { - parts = url.split("/"); - if( parts[0] == "" ) parts.shift(); - if( params != null ) this.params = params; - throw new Redirect(); - } - - static var GET_RULES; - public function runtimeGetParams( cfgIndex : Int ) : Dynamic { - if( GET_RULES == null ) - GET_RULES = haxe.Unserializer.run(haxe.rtti.Meta.getType(Dispatch).getParams[0]); - return checkParams(GET_RULES[cfgIndex], true); - } - - function match( v : String, r : MatchRule, opt : Bool ) : Dynamic { - switch( r ) { - case MRInt: - if( v == null ) throw DEMissing; - if( opt && v == "" ) return null; - var v = Std.parseInt(v); - if( v == null ) throw DEInvalidValue; - return v; - case MRFloat: - if( v == null ) throw DEMissing; - if( opt && v == "" ) return null; - var v = Std.parseFloat(v); - if( Math.isNaN(v) ) throw DEInvalidValue; - return v; - case MRString: - if( v == null ) throw DEMissing; - return v; - case MRBool: - return v != null && v != "0" && v != "false" && v != "null"; - case MRDispatch: - if( v != null ) - parts.unshift(v); - subDispatch = true; - return this; - case MRSpod(c, lock): - if( v == null ) throw DEMissing; - var v = Std.parseInt(v); - if( v == null ) throw DEInvalidValue; - var cl : Dynamic = Type.resolveClass(c); - if( cl == null ) throw "assert"; - var o : Dynamic; - #if !old_spod - o = cl.manager.unsafeGet(v, lock); - #else - o = cl.manager.get(v, lock); - #end - if( o == null ) throw DEInvalidValue; - return o; - case MROpt(r) : - if( v == null ) - return null; - return match(v, r, true); - } - } - - function checkParams( params : Array<{ name : String, opt : Bool, rule : MatchRule }>, opt ) { - var po = { }; - for( p in params ) { - var v = this.params.get(p.name); - if( v == null ) { - if( p.opt ) continue; - if( opt ) return null; - throw DEMissingParam(p.name); - } - Reflect.setField(po, p.name, match(v, p.rule,p.opt)); - } - return po; - } - - function loop( args : Array, r ) { - switch( r ) { - case DRArgs(r, params, opt): - loop(args, r); - args.push( checkParams(params, opt) ); - case DRMatch(r): - args.push(match(parts.shift(), r, false)); - case DRMult(rl): - for( r in rl ) - args.push(match(parts.shift(), r, false)); - case DRMeta(r): - loop(args, r); - var c = Type.getClass(cfg.obj); - var m; - do { - if( c == null ) throw "assert"; - m = Reflect.field(haxe.rtti.Meta.getFields(c), name); - c = Type.getSuperClass(c); - } while( m == null ); - for( mv in Reflect.fields(m) ) - onMeta(mv, Reflect.field(m, mv)); - } - } - - #if macro - - static inline var PREFIX = "haxe.web.Dispatch.DispatchRule."; - - static function getType(t,p) { - switch( Context.follow(t) ) { - case TInst(i,_): - switch( i.toString() ) { - case "Int": - return MRInt; - case "Float": - return MRFloat; - case "String": - return MRString; - case "haxe.web.Dispatch": - return MRDispatch; - default: - var c = i.get(); - var csup = c.superClass; - while( csup != null ) { - var name = csup.t.toString(); - if( name == "neko.db.Object" || name == "sys.db.Object" ) { - var lock = switch( t ) { - case TType(t, _): t.get().name == "Lock"; - default: false; - } - return MRSpod(i.toString(), lock); - } - csup = csup.t.get().superClass; - } - Context.error("Unsupported dispatch type '"+i.toString()+"'",p); - } - case TEnum(e, _): - switch( e.toString() ) { - case "Bool": - return MRBool; - default: - Context.error("Unsupported dispatch type "+e.toString(),p); - } - case TAbstract(a,_): - switch( a.toString() ) { - case "Int": - return MRInt; - case "Float": - return MRFloat; - case "Bool": - return MRBool; - default: - Context.error("Unsupported dispatch type "+a.toString(),p); - } - default: - Context.error("Unsupported dispatch type "+Std.string(t),p); - } - return null; - } - - static function makeArgs( t : haxe.macro.Type, p ) { - var args = []; - switch( Context.follow(t) ) { - case TAnonymous(a): - for( f in a.get().fields ) { - var r = getType(f.type, f.pos); - var opt = false; - switch( f.type ) { - case TType(t, _): - if( t.get().name == "Null" ) opt = true; - default: - } - if( r == MRBool ) opt = true; - args.push( { name : f.name, rule : r, opt : opt } ); - } - default: - Context.error("Arguments should be an anonymous object", p); - } - return args; - } - - static function makeRule( f : ClassField ) : DispatchRule { - switch( Context.follow(f.type) ) { - case TFun(pl, _): - var params = []; - var rules = []; - var args = null, argsOpt = false; - for( p in pl ) { - if( p.name == "args" ) { - if( args != null ) - Context.error("Duplicate arguments", f.pos); - argsOpt = p.opt; - args = makeArgs(p.t,f.pos); - continue; - } - if( args != null ) Context.error("Arguments should be last parameter", f.pos); - var r = getType(p.t, f.pos); - if( p.opt ) r = MROpt(r); - rules.push(r); - } - var rule = if( rules.length == 1 ) - DRMatch(rules[0]); - else - DRMult(rules); - if( args != null ) - rule = DRArgs(rule, args, argsOpt); - return rule; - default: - Context.error("Configuration entry should be a function", f.pos); - } - return null; - } - - static function makeConfig( obj : Expr ) { - var p = obj.pos; - if( Context.defined("display") ) - return { expr : EObjectDecl([ { field : "obj", expr : obj }, { field : "rules", expr : { expr : EObjectDecl([]), pos : p } } ]), pos : p }; - var t = Context.typeof(obj); - switch( Context.follow(t) ) { - case TAnonymous(fl): - var fields = []; - for( f in fl.get().fields ) { - if( f.name.substr(0, 2) != "do" ) - continue; - if (!f.meta.has(':keep')) - f.meta.add(':keep', [], f.pos); - var r = makeRule(f); - fields.push( { field : f.name.charAt(2).toLowerCase() + f.name.substr(3), expr : Context.makeExpr(r,p) } ); - } - if( fields.length == 0 ) - Context.error("No dispatch method found", p); - var rules = { expr : EObjectDecl(fields), pos : p }; - return { expr : EObjectDecl([ { field : "obj", expr : obj }, { field : "rules", expr : rules } ]), pos : p }; - case TInst(i, _): - var i = i.get(); - // store the config inside the class metadata (only once) - if( !i.meta.has("dispatchConfig") ) { - var fields = {}; - var tmp = i; - while( true ) { - for( f in tmp.fields.get() ) { - if( f.name.substr(0, 2) != "do" ) - continue; - if (!f.meta.has(':keep')) - f.meta.add(':keep', [], f.pos); - var r = makeRule(f); - for( m in f.meta.get() ) - if( m.name.charAt(0) != ":" ) { - checkMeta(f); - r = DRMeta(r); - break; - } - Reflect.setField(fields, f.name.charAt(2).toLowerCase() + f.name.substr(3), r); - } - if( tmp.superClass == null ) - break; - tmp = tmp.superClass.t.get(); - } - if( Reflect.fields(fields).length == 0 ) - Context.error("No dispatch method found", p); - var str = serialize(fields); - i.meta.add("dispatchConfig", [ { expr : EConst(CString(str)), pos : p } ], p); - } - return { expr : EUntyped ({ expr : ECall({ expr : EField(Context.makeExpr(Dispatch,p),"extractConfig"), pos : p },[obj]), pos : p }), pos : p }; - default: - Context.error("Configuration should be an anonymous object",p); - } - return null; - } - - static var PARAMS = null; - - static function buildParams(_) { - var rules = []; - for( p in PARAMS ) - rules.push(makeArgs(p.t, p.p)); - var str = serialize(rules); - switch( Context.getType("haxe.web.Dispatch") ) { - case TInst(c, _): - var c = c.get(); - c.meta.remove("getParams"); - c.meta.add("getParams",[{ expr : EConst(CString(str)), pos : c.pos }],c.pos); - default: - } - } - - static function serialize( v : Dynamic ) { - var s = new haxe.Serializer(); - s.useEnumIndex = true; - s.serialize(v); - return s.toString(); - } - - public static function getRunParam(i:Int) { - return PARAMS[i].t; - } - - public dynamic static function checkMeta( f : ClassField ) { - } - - #end - - public static macro function make( obj : ExprOf<{}> ) : ExprOf { - return makeConfig(obj); - } - - public static macro function run( url : ExprOf, params : ExprOf>, obj : ExprOf<{}> ) : ExprOf { - var p = Context.currentPos(); - var cfg = makeConfig(obj); - return { expr : ECall({ expr : EField({ expr : ENew({ name : "Dispatch", pack : ["haxe","web"], params : [], sub : null },[url,params]), pos : p },"runtimeDispatch"), pos : p },[cfg]), pos : p }; - } - - static function extractConfig( obj : Dynamic ) : DispatchConfig { - // extract the config from the class metadata (cache result) - var c = Type.getClass(obj); - var dc = haxe.rtti.Meta.getType(c); - var m : Dynamic = dc.dispatchConfig[0]; - if( Std.is(m,String) ) { - m = haxe.Unserializer.run(m); - dc.dispatchConfig[0] = m; - } - return { obj : obj, rules : m }; - } - -} +/* + * Copyright (C)2005-2012 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.web; + +#if macro +import haxe.macro.Expr; +import haxe.macro.Type.ClassField; +import haxe.macro.Context; +#end + +typedef DispatchConfig = { + var obj : Dynamic; + var rules : Dynamic; +} + +typedef Lock = T; + +enum MatchRule { + MRInt; + MRBool; + MRFloat; + MRString; + MRDate; + MREnum( e : String ); + MRDispatch; + MRSpod( c : String, lock : Bool ); + MROpt( r : MatchRule ); +} + +enum DispatchRule { + DRMatch( r : MatchRule ); + DRMult( r : Array ); + DRArgs( r : DispatchRule, args : Array<{ name : String, rule : MatchRule, opt : Bool }>, opt : Bool ); + DRMeta( r : DispatchRule ); +} + +enum DispatchError { + DENotFound( part : String ); + DEInvalidValue; + DEMissing; + DEMissingParam( p : String ); + DETooManyValues; +} + +class Redirect { + public function new() { + } +} + +class Dispatch { + + public var parts : Array; + public var params : Map; + public var name : String; + public var cfg : DispatchConfig; + var subDispatch : Bool; + + public function new(url:String, params) { + parts = url.split("/"); + if( parts[0] == "" ) parts.shift(); + this.params = params; + } + + public macro function dispatch( ethis : Expr, obj : ExprOf<{}> ) : ExprOf { + var p = Context.currentPos(); + var cfg = makeConfig(obj); + return { expr : ECall({ expr : EField(ethis, "runtimeDispatch"), pos : p }, [cfg]), pos : p }; + } + + public macro function getParams( ethis : Expr ) : Expr { + var p = Context.currentPos(); + if( PARAMS == null ) { + PARAMS = new Array(); + Context.onGenerate(buildParams); + } + var index = PARAMS.length; + var t = Context.typeof({ expr : EConst(CIdent("null")), pos : p }); + PARAMS.push( { p : p, t : t } ); + var call = { expr : ECall( { expr : EField(ethis, "runtimeGetParams"), pos : p }, [ { expr : EConst(CInt(Std.string(index))), pos : p } ]), pos : p }; + var rt = TPath( { pack : ["haxe", "macro"], name : "MacroType", params : [TPExpr(Context.parse("haxe.web.Dispatch.getRunParam("+index+")",p))], sub : null } ); + return { expr : EBlock([ { expr : EVars([ { name : "tmp", type : rt, expr : call } ]), pos : p }, { expr : EConst(CIdent("tmp")), pos : p } ]), pos : p }; + } + + public dynamic function onMeta( v : String, args : Null> ) { + } + + function resolveName( name : String ) { + return name; + } + + public function runtimeDispatch( cfg : DispatchConfig ) { + name = parts.shift(); + if( name == null ) + name = "default"; + name = resolveName(name); + this.cfg = cfg; + var r : DispatchRule = Reflect.field(cfg.rules, name); + if( r == null ) { + r = Reflect.field(cfg.rules, "default"); + if( r == null ) + throw DENotFound(name); + parts.unshift(name); + name = "default"; + } + name = "do" + name.charAt(0).toUpperCase() + name.substr(1); + var args = []; + subDispatch = false; + loop(args, r); + if( parts.length > 0 && !subDispatch ) { + if( parts.length == 1 && parts[parts.length - 1] == "" ) parts.pop() else throw DETooManyValues; + } + try { + Reflect.callMethod(cfg.obj, Reflect.field(cfg.obj, name), args); + } catch( e : Redirect ) { + runtimeDispatch(cfg); + } + } + + public function redirect( url : String, ?params : Map ) { + parts = url.split("/"); + if( parts[0] == "" ) parts.shift(); + if( params != null ) this.params = params; + throw new Redirect(); + } + + static var GET_RULES; + public function runtimeGetParams( cfgIndex : Int ) : Dynamic { + if( GET_RULES == null ) + GET_RULES = haxe.Unserializer.run(haxe.rtti.Meta.getType(Dispatch).getParams[0]); + return checkParams(GET_RULES[cfgIndex], true); + } + + function match( v : String, r : MatchRule, opt : Bool ) : Dynamic { + switch( r ) { + case MRInt: + if( v == null ) throw DEMissing; + if( opt && v == "" ) return null; + var v = Std.parseInt(v); + if( v == null ) throw DEInvalidValue; + return v; + case MRFloat: + if( v == null ) throw DEMissing; + if( opt && v == "" ) return null; + var v = Std.parseFloat(v); + if( Math.isNaN(v) ) throw DEInvalidValue; + return v; + case MRString: + if( v == null ) throw DEMissing; + return v; + case MRBool: + return v != null && v != "0" && v != "false" && v != "null"; + case MRDate: + if( v == null ) throw DEMissing; + try{ + return Date.fromString(v); + } catch (e:Dynamic) { + throw DEInvalidValue; + } + case MREnum(e): + if( v == null ) throw DEMissing; + if( opt && v == "" ) return null; + if( v == "" ) throw DEMissing; + var en : Dynamic = Type.resolveEnum(e); + if( en == null ) throw "assert"; + var ev:Dynamic; + if (v.charCodeAt(0) >= '0'.code && v.charCodeAt(0) <= '9'.code) { + ev = Type.createEnumIndex(en, Std.parseInt(v)); + } else { + ev = Type.createEnum(en, v); + } + return ev; + case MRDispatch: + if( v != null ) + parts.unshift(v); + subDispatch = true; + return this; + case MRSpod(c, lock): + if( v == null ) throw DEMissing; + var v = Std.parseInt(v); + if( v == null ) throw DEInvalidValue; + var cl : Dynamic = Type.resolveClass(c); + if( cl == null ) throw "assert"; + var o : Dynamic; + #if !old_spod + o = cl.manager.unsafeGet(v, lock); + #else + o = cl.manager.get(v, lock); + #end + if( o == null ) throw DEInvalidValue; + return o; + case MROpt(r) : + if( v == null ) + return null; + return match(v, r, true); + } + } + + function checkParams( params : Array<{ name : String, opt : Bool, rule : MatchRule }>, opt ) { + var po = { }; + for( p in params ) { + var v = this.params.get(p.name); + if( v == null ) { + if( p.opt ) continue; + if( opt ) return null; + throw DEMissingParam(p.name); + } + Reflect.setField(po, p.name, match(v, p.rule,p.opt)); + } + return po; + } + + function loop( args : Array, r ) { + switch( r ) { + case DRArgs(r, params, opt): + loop(args, r); + args.push( checkParams(params, opt) ); + case DRMatch(r): + args.push(match(parts.shift(), r, false)); + case DRMult(rl): + for( r in rl ) + args.push(match(parts.shift(), r, false)); + case DRMeta(r): + loop(args, r); + var c = Type.getClass(cfg.obj); + var m; + do { + if( c == null ) throw "assert"; + m = Reflect.field(haxe.rtti.Meta.getFields(c), name); + c = Type.getSuperClass(c); + } while( m == null ); + for( mv in Reflect.fields(m) ) + onMeta(mv, Reflect.field(m, mv)); + } + } + + #if macro + + static inline var PREFIX = "haxe.web.Dispatch.DispatchRule."; + + static function getType(t,p) { + switch( Context.follow(t) ) { + case TInst(i,_): + switch( i.toString() ) { + case "Int": + return MRInt; + case "Float": + return MRFloat; + case "String": + return MRString; + case "Date": + return MRDate; + case "haxe.web.Dispatch": + return MRDispatch; + default: + var c = i.get(); + var csup = c.superClass; + while( csup != null ) { + var name = csup.t.toString(); + if( name == "neko.db.Object" || name == "sys.db.Object" ) { + var lock = switch( t ) { + case TType(t, _): t.get().name == "Lock"; + default: false; + } + return MRSpod(i.toString(), lock); + } + else if ( name == "haxe.web.Dispatch" ) { + return MRDispatch; + } + csup = csup.t.get().superClass; + } + Context.error("Unsupported dispatch type '"+i.toString()+"'",p); + } + case TEnum(e, _): + switch( e.toString() ) { + case "Bool": + return MRBool; + default: + return MREnum(e.toString()); + } + case TAbstract(a,_): + switch( a.toString() ) { + case "Int": + return MRInt; + case "Float": + return MRFloat; + case "Bool": + return MRBool; + default: + Context.error("Unsupported dispatch type "+a.toString(),p); + } + default: + Context.error("Unsupported dispatch type "+Std.string(t),p); + } + return null; + } + + static function makeArgs( t : haxe.macro.Type, p ) { + var args = []; + switch( Context.follow(t) ) { + case TAnonymous(a): + for( f in a.get().fields ) { + var r = getType(f.type, f.pos); + var opt = f.meta.has(":optional"); + switch( f.type ) { + case TType(t, _): + if( t.get().name == "Null" ) opt = true; + default: + } + if( r == MRBool ) opt = true; + args.push( { name : f.name, rule : r, opt : opt } ); + } + default: + Context.error("Arguments should be an anonymous object", p); + } + return args; + } + + static function makeRule( f : ClassField ) : DispatchRule { + switch( Context.follow(f.type) ) { + case TFun(pl, _): + var params = []; + var rules = []; + var args = null, argsOpt = false; + for( p in pl ) { + if( p.name == "args" ) { + if( args != null ) + Context.error("Duplicate arguments", f.pos); + argsOpt = p.opt; + args = makeArgs(p.t,f.pos); + continue; + } + if( args != null ) Context.error("Arguments should be last parameter", f.pos); + var r = getType(p.t, f.pos); + if( p.opt ) r = MROpt(r); + rules.push(r); + } + var rule = if( rules.length == 1 ) + DRMatch(rules[0]); + else + DRMult(rules); + if( args != null ) + rule = DRArgs(rule, args, argsOpt); + return rule; + default: + Context.error("Configuration entry should be a function", f.pos); + } + return null; + } + + static function makeConfig( obj : Expr ) { + var p = obj.pos; + if( Context.defined("display") ) + return { expr : EObjectDecl([ { field : "obj", expr : obj }, { field : "rules", expr : { expr : EObjectDecl([]), pos : p } } ]), pos : p }; + var t = Context.typeof(obj); + switch( Context.follow(t) ) { + case TAnonymous(fl): + var fields = []; + for( f in fl.get().fields ) { + if( f.name.substr(0, 2) != "do" ) + continue; + if (!f.meta.has(':keep')) + f.meta.add(':keep', [], f.pos); + var r = makeRule(f); + fields.push( { field : f.name.charAt(2).toLowerCase() + f.name.substr(3), expr : Context.makeExpr(r,p) } ); + } + if( fields.length == 0 ) + Context.error("No dispatch method found", p); + var rules = { expr : EObjectDecl(fields), pos : p }; + return { expr : EObjectDecl([ { field : "obj", expr : obj }, { field : "rules", expr : rules } ]), pos : p }; + case TInst(i, _): + var i = i.get(); + // store the config inside the class metadata (only once) + if( !i.meta.has("dispatchConfig") ) { + var fields = {}; + var tmp = i; + while( true ) { + for( f in tmp.fields.get() ) { + if( f.name.substr(0, 2) != "do" ) + continue; + if (!f.meta.has(':keep')) + f.meta.add(':keep', [], f.pos); + var r = makeRule(f); + for( m in f.meta.get() ) + if( m.name.charAt(0) != ":" ) { + checkMeta(f); + r = DRMeta(r); + break; + } + Reflect.setField(fields, f.name.charAt(2).toLowerCase() + f.name.substr(3), r); + } + if( tmp.superClass == null ) + break; + tmp = tmp.superClass.t.get(); + } + if( Reflect.fields(fields).length == 0 ) + Context.error("No dispatch method found", p); + var str = serialize(fields); + i.meta.add("dispatchConfig", [ { expr : EConst(CString(str)), pos : p } ], p); + } + return { expr : EUntyped ({ expr : ECall({ expr : EField(Context.makeExpr(Dispatch,p),"extractConfig"), pos : p },[obj]), pos : p }), pos : p }; + default: + Context.error("Configuration should be an anonymous object",p); + } + return null; + } + + static var PARAMS:Array = null; + + static function buildParams(_) { + var rules = []; + for( p in PARAMS ) + rules.push(makeArgs(p.t, p.p)); + var str = serialize(rules); + switch( Context.getType("haxe.web.Dispatch") ) { + case TInst(c, _): + var c = c.get(); + c.meta.remove("getParams"); + c.meta.add("getParams",[{ expr : EConst(CString(str)), pos : c.pos }],c.pos); + default: + } + } + + static function serialize( v : Dynamic ) { + var s = new haxe.Serializer(); + s.useEnumIndex = true; + s.serialize(v); + return s.toString(); + } + + public static function getRunParam(i:Int) { + return PARAMS[i].t; + } + + public dynamic static function checkMeta( f : ClassField ) { + } + + #end + + public static macro function make( obj : ExprOf<{}> ) : ExprOf { + return makeConfig(obj); + } + + public static macro function run( url : ExprOf, params : ExprOf>, obj : ExprOf<{}> ) : ExprOf { + var p = Context.currentPos(); + var cfg = makeConfig(obj); + return { expr : ECall({ expr : EField({ expr : ENew({ name : "Dispatch", pack : ["haxe","web"], params : [], sub : null },[url,params]), pos : p },"runtimeDispatch"), pos : p },[cfg]), pos : p }; + } + + static function extractConfig( obj : Dynamic ) : DispatchConfig { + // extract the config from the class metadata (cache result) + var c = Type.getClass(obj); + var dc = haxe.rtti.Meta.getType(c); + var m : Dynamic = dc.dispatchConfig[0]; + if( Std.is(m,String) ) { + m = haxe.Unserializer.run(m); + dc.dispatchConfig[0] = m; + } + return { obj : obj, rules : m }; + } + +} diff --git a/std/haxe/web/Request.hx b/std/haxe/web/Request.hx index 31701076a1a4eeec96be7b930074e9ae6a4d045c..c5de4d100fd98502c90ef53f23b4877c27db4c4e 100644 --- a/std/haxe/web/Request.hx +++ b/std/haxe/web/Request.hx @@ -1,73 +1,73 @@ -/* - * Copyright (C)2005-2012 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.web; - -class Request { - - /** - Returns the current page GET and POST parameters (only GET parameters for Javascript) - **/ - public static function getParams() : haxe.ds.StringMap { - #if neko - return neko.Web.getParams(); - #elseif php - return php.Web.getParams(); - #elseif js - var get : String = untyped window.location.search.substr(1); - var params = new haxe.ds.StringMap(); - for( p in ~/[&;]/g.split(get) ) { - var pl = p.split("="); - if( pl.length < 2 ) continue; - var name = pl.shift(); - params.set(StringTools.urlDecode(name), StringTools.urlDecode(pl.join("="))); - } - return params; - #end - } - - /** - Returns the local server host name - **/ - public static function getHostName() : String { - #if neko - return neko.Web.getHostName(); - #elseif php - return php.Web.getHostName(); - #elseif js - return untyped window.location.host; // includes port - #end - } - - /** - Returns the original request URL (before any server internal redirections) - **/ - public static function getURI() : String { - #if neko - return neko.Web.getURI(); - #elseif php - return php.Web.getURI(); - #elseif js - return untyped window.location.pathname; - #end - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.web; + +class Request { + + /** + Returns the current page GET and POST parameters (only GET parameters for Javascript) + **/ + public static function getParams() : Map { + #if neko + return neko.Web.getParams(); + #elseif php + return php.Web.getParams(); + #elseif js + var get : String = js.Browser.location.search.substr(1); + var params = new haxe.ds.StringMap(); + for( p in ~/[&;]/g.split(get) ) { + var pl = p.split("="); + if( pl.length < 2 ) continue; + var name = pl.shift(); + params.set(StringTools.urlDecode(name), StringTools.urlDecode(pl.join("="))); + } + return params; + #end + } + + /** + Returns the local server host name + **/ + public static function getHostName() : String { + #if neko + return neko.Web.getHostName(); + #elseif php + return php.Web.getHostName(); + #elseif js + return js.Browser.location.host; // includes port + #end + } + + /** + Returns the original request URL (before any server internal redirections) + **/ + public static function getURI() : String { + #if neko + return neko.Web.getURI(); + #elseif php + return php.Web.getURI(); + #elseif js + return js.Browser.location.pathname; + #end + } + +} diff --git a/std/haxe/xml/Parser.hx b/std/haxe/xml/Parser.hx index 7335200857262556cf5d220114efb22b9626ea37..94607477a18672dd00becee449630b9715b5d8b0 100644 --- a/std/haxe/xml/Parser.hx +++ b/std/haxe/xml/Parser.hx @@ -1,346 +1,396 @@ -/* - * Copyright (C)2005-2012 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.xml; - -using StringTools; - -/* poor'man enum : reduce code size + a bit faster since inlined */ -extern private class S { - public static inline var IGNORE_SPACES = 0; - public static inline var BEGIN = 1; - public static inline var BEGIN_NODE = 2; - public static inline var TAG_NAME = 3; - public static inline var BODY = 4; - public static inline var ATTRIB_NAME = 5; - public static inline var EQUALS = 6; - public static inline var ATTVAL_BEGIN = 7; - public static inline var ATTRIB_VAL = 8; - public static inline var CHILDS = 9; - public static inline var CLOSE = 10; - public static inline var WAIT_END = 11; - public static inline var WAIT_END_RET = 12; - public static inline var PCDATA = 13; - public static inline var HEADER = 14; - public static inline var COMMENT = 15; - public static inline var DOCTYPE = 16; - public static inline var CDATA = 17; - public static inline var ESCAPE = 18; -} - -class Parser -{ - static var escapes = { - var h = new haxe.ds.StringMap(); - h.set("lt", "<"); - h.set("gt", ">"); - h.set("amp", "&"); - h.set("quot", '"'); - h.set("apos", "'"); - h.set("nbsp", String.fromCharCode(160)); - h; - } - - static public function parse(str:String) - { - var doc = Xml.createDocument(); - doParse(str, 0, doc); - return doc; - } - - static function doParse(str:String, p:Int = 0, ?parent:Xml):Int - { - var xml:Xml = null; - var state = S.BEGIN; - var next = S.BEGIN; - var aname = null; - var start = 0; - var nsubs = 0; - var nbrackets = 0; - var c = str.fastCodeAt(p); - var buf = new StringBuf(); - while (!StringTools.isEof(c)) - { - switch(state) - { - case S.IGNORE_SPACES: - switch(c) - { - case - '\n'.code, - '\r'.code, - '\t'.code, - ' '.code: - default: - state = next; - continue; - } - case S.BEGIN: - switch(c) - { - case '<'.code: - state = S.IGNORE_SPACES; - next = S.BEGIN_NODE; - default: - start = p; - state = S.PCDATA; - continue; - } - case S.PCDATA: - if (c == '<'.code) - { - #if php - var child = Xml.createPCDataFromCustomParser(buf.toString() + str.substr(start, p - start)); - #else - var child = Xml.createPCData(buf.toString() + str.substr(start, p - start)); - #end - buf = new StringBuf(); - parent.addChild(child); - nsubs++; - state = S.IGNORE_SPACES; - next = S.BEGIN_NODE; - } - #if !flash9 - else if (c == '&'.code) { - buf.addSub(str, start, p - start); - state = S.ESCAPE; - next = S.PCDATA; - start = p + 1; - } - #end - case S.CDATA: - if (c == ']'.code && str.fastCodeAt(p + 1) == ']'.code && str.fastCodeAt(p + 2) == '>'.code) - { - var child = Xml.createCData(str.substr(start, p - start)); - parent.addChild(child); - nsubs++; - p += 2; - state = S.BEGIN; - } - case S.BEGIN_NODE: - switch(c) - { - case '!'.code: - if (str.fastCodeAt(p + 1) == '['.code) - { - p += 2; - if (str.substr(p, 6).toUpperCase() != "CDATA[") - throw("Expected '.code: - state = S.CHILDS; - nsubs++; - default: - state = S.ATTRIB_NAME; - start = p; - continue; - } - case S.ATTRIB_NAME: - if (!isValidChar(c)) - { - var tmp; - if( start == p ) - throw("Expected attribute name"); - tmp = str.substr(start,p-start); - aname = tmp; - if( xml.exists(aname) ) - throw("Duplicate attribute"); - state = S.IGNORE_SPACES; - next = S.EQUALS; - continue; - } - case S.EQUALS: - switch(c) - { - case '='.code: - state = S.IGNORE_SPACES; - next = S.ATTVAL_BEGIN; - default: - throw("Expected ="); - } - case S.ATTVAL_BEGIN: - switch(c) - { - case '"'.code, '\''.code: - state = S.ATTRIB_VAL; - start = p; - default: - throw("Expected \""); - } - case S.ATTRIB_VAL: - if (c == str.fastCodeAt(start)) - { - var val = str.substr(start+1,p-start-1); - xml.set(aname, val); - state = S.IGNORE_SPACES; - next = S.BODY; - } - case S.CHILDS: - p = doParse(str, p, xml); - start = p; - state = S.BEGIN; - case S.WAIT_END: - switch(c) - { - case '>'.code: - state = S.BEGIN; - default : - throw("Expected >"); - } - case S.WAIT_END_RET: - switch(c) - { - case '>'.code: - if( nsubs == 0 ) - parent.addChild(Xml.createPCData("")); - return p; - default : - throw("Expected >"); - } - case S.CLOSE: - if (!isValidChar(c)) - { - if( start == p ) - throw("Expected node name"); - - var v = str.substr(start,p - start); - if (v != parent.nodeName) - throw "Expected "; - - state = S.IGNORE_SPACES; - next = S.WAIT_END_RET; - continue; - } - case S.COMMENT: - if (c == '-'.code && str.fastCodeAt(p +1) == '-'.code && str.fastCodeAt(p + 2) == '>'.code) - { - parent.addChild(Xml.createComment(str.substr(start, p - start))); - p += 2; - state = S.BEGIN; - } - case S.DOCTYPE: - if(c == '['.code) - nbrackets++; - else if(c == ']'.code) - nbrackets--; - else if (c == '>'.code && nbrackets == 0) - { - parent.addChild(Xml.createDocType(str.substr(start, p - start))); - state = S.BEGIN; - } - case S.HEADER: - if (c == '?'.code && str.fastCodeAt(p + 1) == '>'.code) - { - p++; - var str = str.substr(start + 1, p - start - 2); - parent.addChild(Xml.createProcessingInstruction(str)); - state = S.BEGIN; - } - case S.ESCAPE: - if (c == ';'.code) - { - var s = str.substr(start, p - start); - if (s.fastCodeAt(0) == '#'.code) { - var i = s.fastCodeAt(1) == 'x'.code - ? Std.parseInt("0" +s.substr(1, s.length - 1)) - : Std.parseInt(s.substr(1, s.length - 1)); - buf.add(String.fromCharCode(i)); - } else if (!escapes.exists(s)) - buf.add('&$s;'); - else - buf.add(escapes.get(s)); - start = p + 1; - state = next; - } - } - c = str.fastCodeAt(++p); - } - - if (state == S.BEGIN) - { - start = p; - state = S.PCDATA; - } - - if (state == S.PCDATA) - { - if (p != start || nsubs == 0) - parent.addChild(Xml.createPCData(buf.toString() + str.substr(start, p - start))); - return p; - } - - throw "Unexpected end"; - } - - static inline function isValidChar(c) { - return (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == ':'.code || c == '.'.code || c == '_'.code || c == '-'.code; - } +/* + * Copyright (C)2005-2012 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.xml; + +using StringTools; + +/* poor'man enum : reduce code size + a bit faster since inlined */ +extern private class S { + public static inline var IGNORE_SPACES = 0; + public static inline var BEGIN = 1; + public static inline var BEGIN_NODE = 2; + public static inline var TAG_NAME = 3; + public static inline var BODY = 4; + public static inline var ATTRIB_NAME = 5; + public static inline var EQUALS = 6; + public static inline var ATTVAL_BEGIN = 7; + public static inline var ATTRIB_VAL = 8; + public static inline var CHILDS = 9; + public static inline var CLOSE = 10; + public static inline var WAIT_END = 11; + public static inline var WAIT_END_RET = 12; + public static inline var PCDATA = 13; + public static inline var HEADER = 14; + public static inline var COMMENT = 15; + public static inline var DOCTYPE = 16; + public static inline var CDATA = 17; + public static inline var ESCAPE = 18; +} + +class Parser +{ + static var escapes = { + var h = new haxe.ds.StringMap(); + h.set("lt", "<"); + h.set("gt", ">"); + h.set("amp", "&"); + h.set("quot", '"'); + h.set("apos", "'"); + h; + } + + /** + Parses the String into an XML Document. Set strict parsing to true in order to enable a strict check of XML attributes and entities. + **/ + static public function parse(str:String, strict = false) + { + var doc = Xml.createDocument(); + doParse(str, strict, 0, doc); + return doc; + } + + static function doParse(str:String, strict:Bool, p:Int = 0, ?parent:Xml):Int + { + var xml:Xml = null; + var state = S.BEGIN; + var next = S.BEGIN; + var aname = null; + var start = 0; + var nsubs = 0; + var nbrackets = 0; + var c = str.fastCodeAt(p); + var buf = new StringBuf(); + // need extra state because next is in use + var escapeNext = S.BEGIN; + var attrValQuote = -1; + inline function addChild(xml:Xml) { + parent.addChild(xml); + nsubs++; + } + while (!StringTools.isEof(c)) + { + switch(state) + { + case S.IGNORE_SPACES: + switch(c) + { + case + '\n'.code, + '\r'.code, + '\t'.code, + ' '.code: + default: + state = next; + continue; + } + case S.BEGIN: + switch(c) + { + case '<'.code: + state = S.IGNORE_SPACES; + next = S.BEGIN_NODE; + default: + start = p; + state = S.PCDATA; + continue; + } + case S.PCDATA: + if (c == '<'.code) + { + buf.addSub(str, start, p - start); + var child = Xml.createPCData(buf.toString()); + buf = new StringBuf(); + addChild(child); + state = S.IGNORE_SPACES; + next = S.BEGIN_NODE; + } else if (c == '&'.code) { + buf.addSub(str, start, p - start); + state = S.ESCAPE; + escapeNext = S.PCDATA; + start = p + 1; + } + case S.CDATA: + if (c == ']'.code && str.fastCodeAt(p + 1) == ']'.code && str.fastCodeAt(p + 2) == '>'.code) + { + var child = Xml.createCData(str.substr(start, p - start)); + addChild(child); + p += 2; + state = S.BEGIN; + } + case S.BEGIN_NODE: + switch(c) + { + case '!'.code: + if (str.fastCodeAt(p + 1) == '['.code) + { + p += 2; + if (str.substr(p, 6).toUpperCase() != "CDATA[") + throw("Expected '.code: + state = S.CHILDS; + default: + state = S.ATTRIB_NAME; + start = p; + continue; + } + case S.ATTRIB_NAME: + if (!isValidChar(c)) + { + var tmp; + if( start == p ) + throw("Expected attribute name"); + tmp = str.substr(start,p-start); + aname = tmp; + if( xml.exists(aname) ) + throw("Duplicate attribute"); + state = S.IGNORE_SPACES; + next = S.EQUALS; + continue; + } + case S.EQUALS: + switch(c) + { + case '='.code: + state = S.IGNORE_SPACES; + next = S.ATTVAL_BEGIN; + default: + throw("Expected ="); + } + case S.ATTVAL_BEGIN: + switch(c) + { + case '"'.code | '\''.code: + buf = new StringBuf(); + state = S.ATTRIB_VAL; + start = p + 1; + attrValQuote = c; + default: + throw("Expected \""); + } + case S.ATTRIB_VAL: + switch (c) { + case '&'.code: + buf.addSub(str, start, p - start); + state = S.ESCAPE; + escapeNext = S.ATTRIB_VAL; + start = p + 1; + case '>'.code | '<'.code if( strict ): + // HTML allows these in attributes values + throw "Invalid unescaped " + String.fromCharCode(c) + " in attribute value"; + case _ if (c == attrValQuote): + buf.addSub(str, start, p - start); + var val = buf.toString(); + buf = new StringBuf(); + xml.set(aname, val); + state = S.IGNORE_SPACES; + next = S.BODY; + } + case S.CHILDS: + p = doParse(str, strict, p, xml); + start = p; + state = S.BEGIN; + case S.WAIT_END: + switch(c) + { + case '>'.code: + state = S.BEGIN; + default : + throw("Expected >"); + } + case S.WAIT_END_RET: + switch(c) + { + case '>'.code: + if( nsubs == 0 ) + parent.addChild(Xml.createPCData("")); + return p; + default : + throw("Expected >"); + } + case S.CLOSE: + if (!isValidChar(c)) + { + if( start == p ) + throw("Expected node name"); + + var v = str.substr(start,p - start); + if (v != parent.nodeName) + throw "Expected "; + + state = S.IGNORE_SPACES; + next = S.WAIT_END_RET; + continue; + } + case S.COMMENT: + if (c == '-'.code && str.fastCodeAt(p +1) == '-'.code && str.fastCodeAt(p + 2) == '>'.code) + { + addChild(Xml.createComment(str.substr(start, p - start))); + p += 2; + state = S.BEGIN; + } + case S.DOCTYPE: + if(c == '['.code) + nbrackets++; + else if(c == ']'.code) + nbrackets--; + else if (c == '>'.code && nbrackets == 0) + { + addChild(Xml.createDocType(str.substr(start, p - start))); + state = S.BEGIN; + } + case S.HEADER: + if (c == '?'.code && str.fastCodeAt(p + 1) == '>'.code) + { + p++; + var str = str.substr(start + 1, p - start - 2); + addChild(Xml.createProcessingInstruction(str)); + state = S.BEGIN; + } + case S.ESCAPE: + if (c == ';'.code) + { + var s = str.substr(start, p - start); + if (s.fastCodeAt(0) == '#'.code) { + var c = s.fastCodeAt(1) == 'x'.code + ? Std.parseInt("0" +s.substr(1, s.length - 1)) + : Std.parseInt(s.substr(1, s.length - 1)); + #if (neko || cpp || php) + if( c >= 128 ) { + // UTF8-encode it + if( c <= 0x7FF ) { + buf.addChar(0xC0 | (c >> 6)); + buf.addChar(0x80 | (c & 63)); + } else if( c <= 0xFFFF ) { + buf.addChar(0xE0 | (c >> 12)); + buf.addChar(0x80 | ((c >> 6) & 63)); + buf.addChar(0x80 | (c & 63)); + } else if( c <= 0x10FFFF ) { + buf.addChar(0xF0 | (c >> 18)); + buf.addChar(0x80 | ((c >> 12) & 63)); + buf.addChar(0x80 | ((c >> 6) & 63)); + buf.addChar(0x80 | (c & 63)); + } else + throw "Cannot encode UTF8-char " + c; + } else + #end + buf.addChar(c); + } else if (!escapes.exists(s)) { + if( strict ) + throw 'Undefined entity: $s'; + buf.add('&$s;'); + } else { + buf.add(escapes.get(s)); + } + start = p + 1; + state = escapeNext; + } else if (!isValidChar(c) && c != "#".code) { + if( strict ) + throw 'Invalid character in entity: ' + String.fromCharCode(c); + buf.addChar("&".code); + buf.addSub(str, start, p - start); + p--; + start = p + 1; + state = escapeNext; + } + } + c = str.fastCodeAt(++p); + } + + if (state == S.BEGIN) + { + start = p; + state = S.PCDATA; + } + + if (state == S.PCDATA) + { + if (p != start || nsubs == 0) { + buf.addSub(str, start, p-start); + addChild(Xml.createPCData(buf.toString())); + } + return p; + } + + if( !strict && state == S.ESCAPE && escapeNext == S.PCDATA ) { + buf.addChar("&".code); + buf.addSub(str, start, p - start); + addChild(Xml.createPCData(buf.toString())); + return p; + } + + throw "Unexpected end"; + } + + static inline function isValidChar(c) { + return (c >= 'a'.code && c <= 'z'.code) || (c >= 'A'.code && c <= 'Z'.code) || (c >= '0'.code && c <= '9'.code) || c == ':'.code || c == '.'.code || c == '_'.code || c == '-'.code; + } } \ No newline at end of file diff --git a/std/haxe/xml/Printer.hx b/std/haxe/xml/Printer.hx new file mode 100644 index 0000000000000000000000000000000000000000..aa5bd6c971561dce393d38435611477e8656c58c --- /dev/null +++ b/std/haxe/xml/Printer.hx @@ -0,0 +1,124 @@ +/* + * Copyright (c)2005-2013, Haxe Foundation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the Haxe Foundation nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package haxe.xml; + +class Printer { + + static public function print(xml:Xml, ?pretty = false) { + var printer = new Printer(pretty); + printer.writeNode(xml, ""); + return printer.output.toString(); + } + + var output:StringBuf; + var pretty:Bool; + + function new(pretty) { + output = new StringBuf(); + this.pretty = pretty; + } + + function writeNode(value:Xml, tabs:String) { + switch (value.nodeType) { + case CData: + write(tabs + ""); + newline(); + case Comment: + var commentContent:String = value.nodeValue; + commentContent = ~/[\n\r\t]+/g.replace(commentContent, ""); + commentContent = ""; + write(tabs); + write(StringTools.trim(commentContent)); + newline(); + case Document: + for (child in value) { + writeNode(child, tabs); + } + case Element: + write(tabs + "<"); + write(value.nodeName); + for (attribute in value.attributes()) { + write(" " + attribute + "=\""); + write(StringTools.htmlEscape(value.get(attribute), true)); + write("\""); + } + if (hasChildren(value)) { + write(">"); + newline(); + for (child in value) { + writeNode(child, pretty ? tabs + "\t" : tabs); + } + write(tabs + ""); + newline(); + } else { + write("/>"); + newline(); + } + case PCData: + var nodeValue:String = value.nodeValue; + if (nodeValue.length != 0) { + write(tabs + StringTools.htmlEscape(nodeValue)); + newline(); + } + case ProcessingInstruction: + write(""); + case DocType: + write(""); + } + } + + inline function write(input:String) { + output.add(input); + } + + inline function newline() { + if (pretty) { + output.add(""); + } + } + + function hasChildren(value:Xml):Bool { + for (child in value) { + switch (child.nodeType) { + case Xml.Element, Xml.PCData: + return true; + case Xml.CData, Xml.Comment: + if (StringTools.ltrim(child.nodeValue).length != 0) { + return true; + } + case _: + } + } + return false; + } +} \ No newline at end of file diff --git a/std/haxe/zip/Compress.hx b/std/haxe/zip/Compress.hx new file mode 100644 index 0000000000000000000000000000000000000000..308159c309d1de005c14586a53bc5e4c3a1d4526 --- /dev/null +++ b/std/haxe/zip/Compress.hx @@ -0,0 +1,45 @@ +/* + * Copyright (C)2005-2012 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.zip; + +class Compress { + + public function new( level : Int ) { + throw "Not implemented for this platform"; + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return null; + } + + public function setFlushMode( f : FlushMode ) { + } + + public function close() { + } + + public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes { + throw "Not implemented for this platform"; + return null; + } + +} diff --git a/std/haxe/zip/Entry.hx b/std/haxe/zip/Entry.hx index 33bd1b3437f33623b7bd0dadfc1600d5433b3d08..e63b02714dd79bb241789d08ba793b45a96860e2 100644 --- a/std/haxe/zip/Entry.hx +++ b/std/haxe/zip/Entry.hx @@ -1,40 +1,40 @@ -/* - * Copyright (C)2005-2012 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.zip; - -enum ExtraField { - FUnknown( tag : Int, bytes : haxe.io.Bytes ); - FInfoZipUnicodePath( name : String, crc : Int ); - FUtf8; -} - -typedef Entry = { - var fileName : String; - var fileSize : Int; - var fileTime : Date; - var compressed : Bool; - var dataSize : Int; - var data : Null; - var crc32 : Null; - @:optional var extraFields : Null>; -} - +/* + * Copyright (C)2005-2012 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.zip; + +enum ExtraField { + FUnknown( tag : Int, bytes : haxe.io.Bytes ); + FInfoZipUnicodePath( name : String, crc : Int ); + FUtf8; +} + +typedef Entry = { + var fileName : String; + var fileSize : Int; + var fileTime : Date; + var compressed : Bool; + var dataSize : Int; + var data : Null; + var crc32 : Null; + @:optional var extraFields : Null>; +} + diff --git a/std/cs/system/IFormatProvider.hx b/std/haxe/zip/FlushMode.hx similarity index 90% rename from std/cs/system/IFormatProvider.hx rename to std/haxe/zip/FlushMode.hx index 4b0b8cc4d804a0a5f262b2a14d82cce16ab58fd7..071e9ebd838e6c6199700d95d0d0d84d2da18b4d 100644 --- a/std/cs/system/IFormatProvider.hx +++ b/std/haxe/zip/FlushMode.hx @@ -1,27 +1,30 @@ -/* - * Copyright (C)2005-2012 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 cs.system; - -@:native("System.IFormatProvider") extern interface IFormatProvider -{ - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.zip; + +enum FlushMode { + NO; + SYNC; + FULL; + FINISH; + BLOCK; +} diff --git a/std/haxe/zip/Huffman.hx b/std/haxe/zip/Huffman.hx index b84ef6183e73c05ccef07a647b52105938b0b375..d9696a0b20372781fbc1e1361d2e5c0815d9c6c1 100644 --- a/std/haxe/zip/Huffman.hx +++ b/std/haxe/zip/Huffman.hx @@ -1,115 +1,115 @@ -/* - * Copyright (C)2005-2012 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.zip; - -enum Huffman { - Found( i : Int ); - NeedBit( left : Huffman, right : Huffman ); - NeedBits( n : Int, table : Array ); -} - -class HuffTools { - - public function new() { - } - - function treeDepth(t) { - return switch(t) { - case Found(_): 0; - case NeedBits(_,_): throw "assert"; - case NeedBit(a,b): - var da = treeDepth(a); - var db = treeDepth(b); - 1 + ((da < db) ? da : db); - } - } - - function treeCompress(t) { - var d = treeDepth(t); - if( d == 0 ) - return t; - if( d == 1 ) - return switch( t ) { - case NeedBit(a,b): NeedBit(treeCompress(a),treeCompress(b)); - default: throw "assert"; - } - var size = 1 << d; - var table = new Array(); - for( i in 0...size ) - table.push(Found(-1)); - treeWalk(table,0,0,d,t); - return NeedBits(d,table); - } - - function treeWalk(table,p,cd,d,t) { - switch( t ) { - case NeedBit(a,b): - if( d > 0 ) { - treeWalk(table,p,cd+1,d-1,a); - treeWalk(table,p|(1<, maxbits : Int, v : Int, len : Int ) { - if( len > maxbits ) throw "Invalid huffman"; - var idx = (v << 5) | len; - if( bits.exists(idx) ) - return Found(bits.get(idx)); - v <<= 1; - len += 1; - return NeedBit(treeMake(bits,maxbits,v,len),treeMake(bits,maxbits,v|1,len)); - } - - public function make(lengths,pos,nlengths,maxbits) { - var counts = new Array(); - var tmp = new Array(); - if( maxbits > 32 ) throw "Invalid huffman"; - for( i in 0...maxbits ) { - counts.push(0); - tmp.push(0); - } - for( i in 0...nlengths ) { - var p = lengths[i+pos]; - if( p >= maxbits ) throw "Invalid huffman"; - counts[p]++; - } - var code = 0; - for( i in 1...maxbits-1 ) { - code = (code + counts[i]) << 1; - tmp[i] = code; - } - var bits = new haxe.ds.IntMap(); - for( i in 0...nlengths ) { - var l = lengths[i + pos]; - if( l != 0 ) { - var n = tmp[l-1]; - tmp[l-1] = n + 1; - bits.set((n << 5) | l,i); - } - } - return treeCompress(NeedBit(treeMake(bits,maxbits,0,1),treeMake(bits,maxbits,1,1))); - } -} +/* + * Copyright (C)2005-2012 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.zip; + +enum Huffman { + Found( i : Int ); + NeedBit( left : Huffman, right : Huffman ); + NeedBits( n : Int, table : Array ); +} + +class HuffTools { + + public function new() { + } + + function treeDepth(t) { + return switch(t) { + case Found(_): 0; + case NeedBits(_,_): throw "assert"; + case NeedBit(a,b): + var da = treeDepth(a); + var db = treeDepth(b); + 1 + ((da < db) ? da : db); + } + } + + function treeCompress(t) { + var d = treeDepth(t); + if( d == 0 ) + return t; + if( d == 1 ) + return switch( t ) { + case NeedBit(a,b): NeedBit(treeCompress(a),treeCompress(b)); + default: throw "assert"; + } + var size = 1 << d; + var table = new Array(); + for( i in 0...size ) + table.push(Found(-1)); + treeWalk(table,0,0,d,t); + return NeedBits(d,table); + } + + function treeWalk(table,p,cd,d,t) { + switch( t ) { + case NeedBit(a,b): + if( d > 0 ) { + treeWalk(table,p,cd+1,d-1,a); + treeWalk(table,p|(1<, maxbits : Int, v : Int, len : Int ) { + if( len > maxbits ) throw "Invalid huffman"; + var idx = (v << 5) | len; + if( bits.exists(idx) ) + return Found(bits.get(idx)); + v <<= 1; + len += 1; + return NeedBit(treeMake(bits,maxbits,v,len),treeMake(bits,maxbits,v|1,len)); + } + + public function make(lengths,pos,nlengths,maxbits) { + var counts = new Array(); + var tmp = new Array(); + if( maxbits > 32 ) throw "Invalid huffman"; + for( i in 0...maxbits ) { + counts.push(0); + tmp.push(0); + } + for( i in 0...nlengths ) { + var p = lengths[i+pos]; + if( p >= maxbits ) throw "Invalid huffman"; + counts[p]++; + } + var code = 0; + for( i in 1...maxbits-1 ) { + code = (code + counts[i]) << 1; + tmp[i] = code; + } + var bits = new haxe.ds.IntMap(); + for( i in 0...nlengths ) { + var l = lengths[i + pos]; + if( l != 0 ) { + var n = tmp[l-1]; + tmp[l-1] = n + 1; + bits.set((n << 5) | l,i); + } + } + return treeCompress(NeedBit(treeMake(bits,maxbits,0,1),treeMake(bits,maxbits,1,1))); + } +} diff --git a/std/haxe/zip/InflateImpl.hx b/std/haxe/zip/InflateImpl.hx index b3095a793ba38d9e8e8dfc0d9ff6e4241eeb8d85..6f7a79301a056e2fb3a2dfc08efaec555bc6af70 100644 --- a/std/haxe/zip/InflateImpl.hx +++ b/std/haxe/zip/InflateImpl.hx @@ -1,376 +1,376 @@ -/* - * Copyright (C)2005-2012 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.zip; -import haxe.zip.Huffman; -import haxe.crypto.Adler32; - -private class Window { - - public static inline var SIZE = 1 << 15; - public static inline var BUFSIZE = 1 << 16; - - public var buffer : haxe.io.Bytes; - public var pos : Int; - var crc : Adler32; - - public function new(hasCrc) { - buffer = haxe.io.Bytes.alloc(BUFSIZE); - pos = 0; - if( hasCrc ) crc = new Adler32(); - } - - public function slide() { - if( crc != null ) crc.update(buffer,0,SIZE); - var b = haxe.io.Bytes.alloc(BUFSIZE); - pos -= SIZE; - b.blit(0,buffer,SIZE,pos); - buffer = b; - } - - public function addBytes(b,p,len) { - if( pos + len > BUFSIZE ) slide(); - buffer.blit(pos,b,p,len); - pos += len; - } - - public function addByte(c) { - if( pos == BUFSIZE ) slide(); - buffer.set(pos,c); - pos++; - } - - public function getLastChar() { - return buffer.get(pos - 1); - } - - public function available() { - return pos; - } - - public function checksum() { - if( crc != null ) crc.update(buffer,0,pos); - return crc; - } - -} - -private enum State { - Head; - Block; - CData; - Flat; - Crc; - Dist; - DistOne; - Done; -} - -/** - A pure Haxe implementation of the ZLIB Inflate algorithm which allows reading compressed data without any platform-specific support. -**/ -class InflateImpl { - - static var LEN_EXTRA_BITS_TBL = [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,-1,-1]; - static var LEN_BASE_VAL_TBL = [3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258]; - static var DIST_EXTRA_BITS_TBL = [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,-1,-1]; - static var DIST_BASE_VAL_TBL = [1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577]; - static var CODE_LENGTHS_POS = [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; - - var nbits : Int; - var bits : Int; - var state : State; - var final : Bool; - var huffman : Huffman; - var huffdist : Null; - var htools : HuffTools; - var len : Int; - var dist : Int; - var needed : Int; - var output : haxe.io.Bytes; - var outpos : Int; - var input : haxe.io.Input; - var lengths : Array; - var window : Window; - - static var FIXED_HUFFMAN = null; - - public function new( i, ?header = true, ?crc = true ) { - final = false; - htools = new HuffTools(); - huffman = buildFixedHuffman(); - huffdist = null; - len = 0; - dist = 0; - state = header ? Head : Block; - input = i; - bits = 0; - nbits = 0; - needed = 0; - output = null; - outpos = 0; - lengths = new Array(); - for( i in 0...19 ) - lengths.push(-1); - window = new Window(crc); - } - - function buildFixedHuffman() { - if( FIXED_HUFFMAN != null ) - return FIXED_HUFFMAN; - var a = new Array(); - for( n in 0...288 ) - a.push(if( n <= 143 ) 8 else if( n <= 255 ) 9 else if( n <= 279 ) 7 else 8); - FIXED_HUFFMAN = htools.make(a,0,288,10); - return FIXED_HUFFMAN; - } - - public function readBytes(b,pos,len) { - needed = len; - outpos = pos; - output = b; - if( len > 0 ) - while( inflateLoop() ) { - } - return len - needed; - } - - function getBits(n) { - while( nbits < n ) { - bits |= input.readByte() << nbits; - nbits += 8; - } - var b = bits & ((1 << n) - 1); - nbits -= n; - bits >>= n; - return b; - } - - function getBit() { - if( nbits == 0 ) { - nbits = 8; - bits = input.readByte(); - } - var b = bits & 1 == 1; - nbits--; - bits >>= 1; - return b; - } - - function getRevBits(n) { - return if( n == 0 ) - 0 - else if( getBit() ) - (1 << (n - 1)) | getRevBits(n-1) - else - getRevBits(n-1); - } - - function resetBits() { - bits = 0; - nbits = 0; - } - - function addBytes(b,p,len) { - window.addBytes(b,p,len); - output.blit(outpos,b,p,len); - needed -= len; - outpos += len; - } - - function addByte(b) { - window.addByte(b); - output.set(outpos,b); - needed--; - outpos++; - } - - function addDistOne(n) { - var c = window.getLastChar(); - for( i in 0...n ) - addByte(c); - } - - function addDist(d,len) { - addBytes(window.buffer,window.pos - d,len); - } - - function applyHuffman(h) { - return switch(h) { - case Found(n): n; - case NeedBit(a,b): applyHuffman(getBit()?b:a); - case NeedBits(n,tbl): applyHuffman(tbl[getBits(n)]); - } - } - - function inflateLengths(a,max) { - var i = 0; - var prev = 0; - while( i < max ) { - var n = applyHuffman(huffman); - switch( n ) { - case 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15: - prev = n; - a[i] = n; - i++; - case 16: - var end = i + 3 + getBits(2); - if( end > max ) throw "Invalid data"; - while( i < end ) { - a[i] = prev; - i++; - } - case 17: - i += 3 + getBits(3); - if( i > max ) throw "Invalid data"; - case 18: - i += 11 + getBits(7); - if( i > max ) throw "Invalid data"; - default: - throw "Invalid data"; - } - } - } - - function inflateLoop() { - switch( state ) { - case Head: - var cmf = input.readByte(); - var cm = cmf & 15; - var cinfo = cmf >> 4; - if( cm != 8 || cinfo != 7 ) throw "Invalid data"; - var flg = input.readByte(); - //var fcheck = flg & 31; - var fdict = flg & 32 != 0; - //var flevel = flg >> 6; - if( ((cmf << 8) + flg) % 31 != 0 ) throw "Invalid data"; - if( fdict ) throw "Unsupported dictionary"; - state = Block; - return true; - case Crc: - var calc = window.checksum(); - if( calc == null ) { - state = Done; - return true; - } - var crc = Adler32.read(input); - if( !calc.equals(crc) ) throw "Invalid CRC"; - state = Done; - return true; - case Done: - // nothing - return false; - case Block: - final = getBit(); - switch( getBits(2) ) { - case 0: // no compression - len = input.readUInt16(); - var nlen = input.readUInt16(); - if( nlen != 0xFFFF - len ) throw "Invalid data"; - state = Flat; - var r = inflateLoop(); - resetBits(); - return r; - case 1: // fixed Huffman - huffman = buildFixedHuffman(); - huffdist = null; - state = CData; - return true; - case 2: // dynamic Huffman - var hlit = getBits(5) + 257; - var hdist = getBits(5) + 1; - var hclen = getBits(4) + 4; - for( i in 0...hclen ) - lengths[CODE_LENGTHS_POS[i]] = getBits(3); - for( i in hclen...19 ) - lengths[CODE_LENGTHS_POS[i]] = 0; - huffman = htools.make(lengths,0,19,8); - var lengths = new Array(); - for( i in 0...hlit + hdist ) - lengths.push(0); - inflateLengths(lengths,hlit + hdist); - huffdist = htools.make(lengths,hlit,hdist,16); - huffman = htools.make(lengths,0,hlit,16); - state = CData; - return true; - default: - throw "Invalid data"; - } - case Flat: - var rlen = (len < needed) ? len : needed; - var bytes = input.read(rlen); - len -= rlen; - addBytes(bytes,0,rlen); - if( len == 0 ) state = final ? Crc : Block; - return needed > 0; - case DistOne: - var rlen = (len < needed) ? len : needed; - addDistOne(rlen); - len -= rlen; - if( len == 0 ) state = CData; - return needed > 0; - case Dist: - while( len > 0 && needed > 0 ) { - var rdist = (len < dist) ? len : dist; - var rlen = (needed < rdist) ? needed : rdist; - addDist(dist,rlen); - len -= rlen; - } - if( len == 0 ) state = CData; - return needed > 0; - case CData: - var n = applyHuffman(huffman); - if( n < 256 ) { - addByte(n); - return needed > 0; - } else if( n == 256 ) { - state = final ? Crc : Block; - return true; - } else { - n -= 257; - var extra_bits = LEN_EXTRA_BITS_TBL[n]; - if( extra_bits == -1 ) throw "Invalid data"; - len = LEN_BASE_VAL_TBL[n] + getBits(extra_bits); - var dist_code = if( huffdist == null ) getRevBits(5) else applyHuffman(huffdist); - extra_bits = DIST_EXTRA_BITS_TBL[dist_code]; - if( extra_bits == -1 ) throw "Invalid data"; - dist = DIST_BASE_VAL_TBL[dist_code] + getBits(extra_bits); - if( dist > window.available() ) throw "Invalid data"; - state = (dist == 1) ? DistOne : Dist; - return true; - } - } - } - - public static function run( i : haxe.io.Input, ?bufsize = 65536 ) { - var buf = haxe.io.Bytes.alloc(bufsize); - var output = new haxe.io.BytesBuffer(); - var inflate = new InflateImpl(i); - while( true ) { - var len = inflate.readBytes(buf,0,bufsize); - output.addBytes(buf,0,len); - if( len < bufsize ) - break; - } - return output.getBytes(); - } - -} +/* + * Copyright (C)2005-2012 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.zip; +import haxe.zip.Huffman; +import haxe.crypto.Adler32; + +private class Window { + + public static inline var SIZE = 1 << 15; + public static inline var BUFSIZE = 1 << 16; + + public var buffer : haxe.io.Bytes; + public var pos : Int; + var crc : Adler32; + + public function new(hasCrc) { + buffer = haxe.io.Bytes.alloc(BUFSIZE); + pos = 0; + if( hasCrc ) crc = new Adler32(); + } + + public function slide() { + if( crc != null ) crc.update(buffer,0,SIZE); + var b = haxe.io.Bytes.alloc(BUFSIZE); + pos -= SIZE; + b.blit(0,buffer,SIZE,pos); + buffer = b; + } + + public function addBytes(b,p,len) { + if( pos + len > BUFSIZE ) slide(); + buffer.blit(pos,b,p,len); + pos += len; + } + + public function addByte(c) { + if( pos == BUFSIZE ) slide(); + buffer.set(pos,c); + pos++; + } + + public function getLastChar() { + return buffer.get(pos - 1); + } + + public function available() { + return pos; + } + + public function checksum() { + if( crc != null ) crc.update(buffer,0,pos); + return crc; + } + +} + +private enum State { + Head; + Block; + CData; + Flat; + Crc; + Dist; + DistOne; + Done; +} + +/** + A pure Haxe implementation of the ZLIB Inflate algorithm which allows reading compressed data without any platform-specific support. +**/ +class InflateImpl { + + static var LEN_EXTRA_BITS_TBL = [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,-1,-1]; + static var LEN_BASE_VAL_TBL = [3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258]; + static var DIST_EXTRA_BITS_TBL = [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,-1,-1]; + static var DIST_BASE_VAL_TBL = [1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577]; + static var CODE_LENGTHS_POS = [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; + + var nbits : Int; + var bits : Int; + var state : State; + var final : Bool; + var huffman : Huffman; + var huffdist : Null; + var htools : HuffTools; + var len : Int; + var dist : Int; + var needed : Int; + var output : haxe.io.Bytes; + var outpos : Int; + var input : haxe.io.Input; + var lengths : Array; + var window : Window; + + static var FIXED_HUFFMAN = null; + + public function new( i, ?header = true, ?crc = true ) { + final = false; + htools = new HuffTools(); + huffman = buildFixedHuffman(); + huffdist = null; + len = 0; + dist = 0; + state = header ? Head : Block; + input = i; + bits = 0; + nbits = 0; + needed = 0; + output = null; + outpos = 0; + lengths = new Array(); + for( i in 0...19 ) + lengths.push(-1); + window = new Window(crc); + } + + function buildFixedHuffman() { + if( FIXED_HUFFMAN != null ) + return FIXED_HUFFMAN; + var a = new Array(); + for( n in 0...288 ) + a.push(if( n <= 143 ) 8 else if( n <= 255 ) 9 else if( n <= 279 ) 7 else 8); + FIXED_HUFFMAN = htools.make(a,0,288,10); + return FIXED_HUFFMAN; + } + + public function readBytes(b,pos,len) { + needed = len; + outpos = pos; + output = b; + if( len > 0 ) + while( inflateLoop() ) { + } + return len - needed; + } + + function getBits(n) { + while( nbits < n ) { + bits |= input.readByte() << nbits; + nbits += 8; + } + var b = bits & ((1 << n) - 1); + nbits -= n; + bits >>= n; + return b; + } + + function getBit() { + if( nbits == 0 ) { + nbits = 8; + bits = input.readByte(); + } + var b = bits & 1 == 1; + nbits--; + bits >>= 1; + return b; + } + + function getRevBits(n) { + return if( n == 0 ) + 0 + else if( getBit() ) + (1 << (n - 1)) | getRevBits(n-1) + else + getRevBits(n-1); + } + + function resetBits() { + bits = 0; + nbits = 0; + } + + function addBytes(b,p,len) { + window.addBytes(b,p,len); + output.blit(outpos,b,p,len); + needed -= len; + outpos += len; + } + + function addByte(b) { + window.addByte(b); + output.set(outpos,b); + needed--; + outpos++; + } + + function addDistOne(n) { + var c = window.getLastChar(); + for( i in 0...n ) + addByte(c); + } + + function addDist(d,len) { + addBytes(window.buffer,window.pos - d,len); + } + + function applyHuffman(h) { + return switch(h) { + case Found(n): n; + case NeedBit(a,b): applyHuffman(getBit()?b:a); + case NeedBits(n,tbl): applyHuffman(tbl[getBits(n)]); + } + } + + function inflateLengths(a,max) { + var i = 0; + var prev = 0; + while( i < max ) { + var n = applyHuffman(huffman); + switch( n ) { + case 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15: + prev = n; + a[i] = n; + i++; + case 16: + var end = i + 3 + getBits(2); + if( end > max ) throw "Invalid data"; + while( i < end ) { + a[i] = prev; + i++; + } + case 17: + i += 3 + getBits(3); + if( i > max ) throw "Invalid data"; + case 18: + i += 11 + getBits(7); + if( i > max ) throw "Invalid data"; + default: + throw "Invalid data"; + } + } + } + + function inflateLoop() { + switch( state ) { + case Head: + var cmf = input.readByte(); + var cm = cmf & 15; + var cinfo = cmf >> 4; + if( cm != 8 ) throw "Invalid data"; + var flg = input.readByte(); + //var fcheck = flg & 31; + var fdict = flg & 32 != 0; + //var flevel = flg >> 6; + if( ((cmf << 8) + flg) % 31 != 0 ) throw "Invalid data"; + if( fdict ) throw "Unsupported dictionary"; + state = Block; + return true; + case Crc: + var calc = window.checksum(); + if( calc == null ) { + state = Done; + return true; + } + var crc = Adler32.read(input); + if( !calc.equals(crc) ) throw "Invalid CRC"; + state = Done; + return true; + case Done: + // nothing + return false; + case Block: + final = getBit(); + switch( getBits(2) ) { + case 0: // no compression + len = input.readUInt16(); + var nlen = input.readUInt16(); + if( nlen != 0xFFFF - len ) throw "Invalid data"; + state = Flat; + var r = inflateLoop(); + resetBits(); + return r; + case 1: // fixed Huffman + huffman = buildFixedHuffman(); + huffdist = null; + state = CData; + return true; + case 2: // dynamic Huffman + var hlit = getBits(5) + 257; + var hdist = getBits(5) + 1; + var hclen = getBits(4) + 4; + for( i in 0...hclen ) + lengths[CODE_LENGTHS_POS[i]] = getBits(3); + for( i in hclen...19 ) + lengths[CODE_LENGTHS_POS[i]] = 0; + huffman = htools.make(lengths,0,19,8); + var lengths = new Array(); + for( i in 0...hlit + hdist ) + lengths.push(0); + inflateLengths(lengths,hlit + hdist); + huffdist = htools.make(lengths,hlit,hdist,16); + huffman = htools.make(lengths,0,hlit,16); + state = CData; + return true; + default: + throw "Invalid data"; + } + case Flat: + var rlen = (len < needed) ? len : needed; + var bytes = input.read(rlen); + len -= rlen; + addBytes(bytes,0,rlen); + if( len == 0 ) state = final ? Crc : Block; + return needed > 0; + case DistOne: + var rlen = (len < needed) ? len : needed; + addDistOne(rlen); + len -= rlen; + if( len == 0 ) state = CData; + return needed > 0; + case Dist: + while( len > 0 && needed > 0 ) { + var rdist = (len < dist) ? len : dist; + var rlen = (needed < rdist) ? needed : rdist; + addDist(dist,rlen); + len -= rlen; + } + if( len == 0 ) state = CData; + return needed > 0; + case CData: + var n = applyHuffman(huffman); + if( n < 256 ) { + addByte(n); + return needed > 0; + } else if( n == 256 ) { + state = final ? Crc : Block; + return true; + } else { + n -= 257; + var extra_bits = LEN_EXTRA_BITS_TBL[n]; + if( extra_bits == -1 ) throw "Invalid data"; + len = LEN_BASE_VAL_TBL[n] + getBits(extra_bits); + var dist_code = if( huffdist == null ) getRevBits(5) else applyHuffman(huffdist); + extra_bits = DIST_EXTRA_BITS_TBL[dist_code]; + if( extra_bits == -1 ) throw "Invalid data"; + dist = DIST_BASE_VAL_TBL[dist_code] + getBits(extra_bits); + if( dist > window.available() ) throw "Invalid data"; + state = (dist == 1) ? DistOne : Dist; + return true; + } + } + } + + public static function run( i : haxe.io.Input, ?bufsize = 65536 ) { + var buf = haxe.io.Bytes.alloc(bufsize); + var output = new haxe.io.BytesBuffer(); + var inflate = new InflateImpl(i); + while( true ) { + var len = inflate.readBytes(buf,0,bufsize); + output.addBytes(buf,0,len); + if( len < bufsize ) + break; + } + return output.getBytes(); + } + +} diff --git a/std/haxe/zip/Reader.hx b/std/haxe/zip/Reader.hx index 192f6883ed018701a85f6dbbfeae015457332f70..e5ccffb1cde8c9e3d0f1a59936708875cb98b117 100644 --- a/std/haxe/zip/Reader.hx +++ b/std/haxe/zip/Reader.hx @@ -1,208 +1,210 @@ -/* - * Copyright (C)2005-2012 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.zip; -import haxe.zip.Entry; - -// see http://www.pkware.com/documents/casestudies/APPNOTE.TXT - -class Reader { - - var i : haxe.io.Input; - - public function new(i) { - this.i = i; - } - - function readZipDate() { - var t = i.readUInt16(); - var hour = (t >> 11) & 31; - var min = (t >> 5) & 63; - var sec = t & 31; - var d = i.readUInt16(); - var year = d >> 9; - var month = (d >> 5) & 15; - var day = d & 31; - return new Date(year + 1980, month-1, day, hour, min, sec << 1); - } - - function readExtraFields(length) { - var fields = new List(); - while( length > 0 ) { - if( length < 4 ) throw "Invalid extra fields data"; - var tag = i.readUInt16(); - var len = i.readUInt16(); - if( length < len ) throw "Invalid extra fields data"; - switch( tag ) { - case 0x7075: - var version = i.readByte(); - if( version != 1 ) { - var data = new haxe.io.BytesBuffer(); - data.addByte(version); - data.add(i.read(len-1)); - fields.add(FUnknown(tag,data.getBytes())); - } else { - var crc = i.readInt32(); - var name = i.read(len - 5).toString(); - fields.add(FInfoZipUnicodePath(name,crc)); - } - default: - fields.add(FUnknown(tag,i.read(len))); - } - length -= 4 + len; - } - return fields; - } - - public function readEntryHeader() : Entry { - var i = this.i; - var h = i.readInt32(); - if( h == 0x02014B50 || h == 0x06054B50 ) - return null; - if( h != 0x04034B50 ) - throw "Invalid Zip Data"; - var version = i.readUInt16(); - var flags = i.readUInt16(); - var utf8 = flags & 0x800 != 0; - if( (flags & 0xF7F7) != 0 ) - throw "Unsupported flags "+flags; - var compression = i.readUInt16(); - var compressed = (compression != 0); - if( compressed && compression != 8 ) - throw "Unsupported compression "+compression; - var mtime = readZipDate(); - var crc32 = i.readInt32(); - var csize = i.readInt32(); - var usize = i.readInt32(); - var fnamelen = i.readInt16(); - var elen = i.readInt16(); - var fname = i.readString(fnamelen); - var fields = readExtraFields(elen); - if( utf8 ) - fields.push(FUtf8); - var data = null; - if( (flags & 8) != 0 ) - csize = -1; - return { - fileName : fname, - fileSize : usize, - fileTime : mtime, - compressed : compressed, - dataSize : csize, - data : data, - crc32 : crc32, - extraFields : fields, - }; - } - - public function read() : List { - var l = new List(); - var buf = null; - var tmp = null; - while( true ) { - var e = readEntryHeader(); - if( e == null ) - break; - if( e.dataSize < 0 ) { - #if neko - // enter progressive mode : we use a different input which has - // a temporary buffer, this is necessary since we have to uncompress - // progressively, and after that we might have pending readed data - // that needs to be processed - var bufSize = 65536; - if( buf == null ) { - buf = new haxe.io.BufferInput(i, haxe.io.Bytes.alloc(bufSize)); - tmp = haxe.io.Bytes.alloc(bufSize); - i = buf; - } - var out = new haxe.io.BytesBuffer(); - var z = new neko.zip.Uncompress(-15); - z.setFlushMode(neko.zip.Flush.SYNC); - while( true ) { - if( buf.available == 0 ) - buf.refill(); - var p = bufSize - buf.available; - if( p != buf.pos ) { - // because of lack of "srcLen" in zip api, we need to always be stuck to the buffer end - buf.buf.blit(p, buf.buf, buf.pos, buf.available); - buf.pos = p; - } - var r = z.execute(buf.buf, buf.pos, tmp, 0); - out.addBytes(tmp, 0, r.write); - buf.pos += r.read; - buf.available -= r.read; - if( r.done ) break; - } - e.data = out.getBytes(); - #else - var bufSize = 65536; - if( tmp == null ) - tmp = haxe.io.Bytes.alloc(bufSize); - var out = new haxe.io.BytesBuffer(); - var z = new InflateImpl(i, false, false); - while( true ) { - var n = z.readBytes(tmp, 0, bufSize); - out.addBytes(tmp, 0, n); - if( n < bufSize ) - break; - } - e.data = out.getBytes(); - #end - e.crc32 = i.readInt32(); - if( e.crc32 == 0x08074b50 ) - e.crc32 = i.readInt32(); - e.dataSize = i.readInt32(); - e.fileSize = i.readInt32(); - // set data to uncompressed - e.dataSize = e.fileSize; - e.compressed = false; - } else - e.data = i.read(e.dataSize); - l.add(e); - } - return l; - } - - public static function readZip( i : haxe.io.Input ) { - var r = new Reader(i); - return r.read(); - } - - public static function unzip( f : Entry ) { - if( !f.compressed ) - return f.data; - #if neko - var c = new neko.zip.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; - #else - throw "No uncompress support"; - #end - return f.data; - } - -} +/* + * Copyright (C)2005-2012 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.zip; +import haxe.zip.Entry; + +// see http://www.pkware.com/documents/casestudies/APPNOTE.TXT + +class Reader { + + var i : haxe.io.Input; + + public function new(i) { + this.i = i; + } + + function readZipDate() { + var t = i.readUInt16(); + var hour = (t >> 11) & 31; + var min = (t >> 5) & 63; + var sec = t & 31; + var d = i.readUInt16(); + var year = d >> 9; + var month = (d >> 5) & 15; + var day = d & 31; + return new Date(year + 1980, month-1, day, hour, min, sec << 1); + } + + function readExtraFields(length) { + var fields = new List(); + while( length > 0 ) { + if( length < 4 ) throw "Invalid extra fields data"; + var tag = i.readUInt16(); + var len = i.readUInt16(); + if( length < len ) throw "Invalid extra fields data"; + switch( tag ) { + case 0x7075: + var version = i.readByte(); + if( version != 1 ) { + var data = new haxe.io.BytesBuffer(); + data.addByte(version); + data.add(i.read(len-1)); + fields.add(FUnknown(tag,data.getBytes())); + } else { + var crc = i.readInt32(); + var name = i.read(len - 5).toString(); + fields.add(FInfoZipUnicodePath(name,crc)); + } + default: + fields.add(FUnknown(tag,i.read(len))); + } + length -= 4 + len; + } + return fields; + } + + public function readEntryHeader() : Entry { + var i = this.i; + var h = i.readInt32(); + if( h == 0x02014B50 || h == 0x06054B50 ) + return null; + if( h != 0x04034B50 ) + throw "Invalid Zip Data"; + var version = i.readUInt16(); + var flags = i.readUInt16(); + var utf8 = flags & 0x800 != 0; + if( (flags & 0xF7F1) != 0 ) + throw "Unsupported flags "+flags; + var compression = i.readUInt16(); + var compressed = (compression != 0); + if( compressed && compression != 8 ) + throw "Unsupported compression "+compression; + var mtime = readZipDate(); + var crc32 : Null = i.readInt32(); + var csize = i.readInt32(); + var usize = i.readInt32(); + var fnamelen = i.readInt16(); + var elen = i.readInt16(); + var fname = i.readString(fnamelen); + var fields = readExtraFields(elen); + if( utf8 ) + fields.push(FUtf8); + var data = null; + // we have a data descriptor that store the real crc/sizes + // after the compressed data, let's wait for it + if( (flags & 8) != 0 ) + crc32 = null; + return { + fileName : fname, + fileSize : usize, + fileTime : mtime, + compressed : compressed, + dataSize : csize, + data : data, + crc32 : crc32, + extraFields : fields, + }; + } + + public function read() : List { + var l = new List(); + var buf = null; + var tmp = null; + while( true ) { + var e = readEntryHeader(); + if( e == null ) + break; + // do we have a data descriptor? (see readEntryHeader) + if( e.crc32 == null ) { + if( e.compressed ) { + #if neko + // enter progressive mode : we use a different input which has + // a temporary buffer, this is necessary since we have to uncompress + // progressively, and after that we might have pending readed data + // that needs to be processed + var bufSize = 65536; + if( buf == null ) { + buf = new haxe.io.BufferInput(i, haxe.io.Bytes.alloc(bufSize)); + tmp = haxe.io.Bytes.alloc(bufSize); + i = buf; + } + var out = new haxe.io.BytesBuffer(); + var z = new neko.zip.Uncompress(-15); + z.setFlushMode(neko.zip.Flush.SYNC); + while( true ) { + if( buf.available == 0 ) + buf.refill(); + var p = bufSize - buf.available; + if( p != buf.pos ) { + // because of lack of "srcLen" in zip api, we need to always be stuck to the buffer end + buf.buf.blit(p, buf.buf, buf.pos, buf.available); + buf.pos = p; + } + var r = z.execute(buf.buf, buf.pos, tmp, 0); + out.addBytes(tmp, 0, r.write); + buf.pos += r.read; + buf.available -= r.read; + if( r.done ) break; + } + e.data = out.getBytes(); + #else + var bufSize = 65536; + if( tmp == null ) + tmp = haxe.io.Bytes.alloc(bufSize); + var out = new haxe.io.BytesBuffer(); + var z = new InflateImpl(i, false, false); + while( true ) { + var n = z.readBytes(tmp, 0, bufSize); + out.addBytes(tmp, 0, n); + if( n < bufSize ) + break; + } + e.data = out.getBytes(); + #end + } else + e.data = i.read(e.dataSize); + e.crc32 = i.readInt32(); + if( e.crc32 == 0x08074b50 ) + e.crc32 = i.readInt32(); + e.dataSize = i.readInt32(); + e.fileSize = i.readInt32(); + // set data to uncompressed + e.dataSize = e.fileSize; + e.compressed = false; + } else + e.data = i.read(e.dataSize); + l.add(e); + } + return l; + } + + public static function readZip( i : haxe.io.Input ) { + var r = new Reader(i); + return r.read(); + } + + public static function unzip( f : Entry ) { + if( !f.compressed ) + return f.data; + var c = new haxe.zip.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; + return f.data; + } + +} diff --git a/std/haxe/zip/Tools.hx b/std/haxe/zip/Tools.hx index 7c850ad6879584523d7ac9a7b09c5a75c49d35dc..64299148c66de4fcabb74fc30d58fe2d88911207 100644 --- a/std/haxe/zip/Tools.hx +++ b/std/haxe/zip/Tools.hx @@ -1,42 +1,38 @@ -/* - * Copyright (C)2005-2012 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.zip; - -class Tools { - - public static function compress( f : Entry, level : Int ) { - if( f.compressed ) - return; - #if neko - // this should be optimized with a temp buffer - // that would discard the first two bytes - // (in order to prevent 2x mem usage for large files) - var data = neko.zip.Compress.run( f.data, level ); - f.compressed = true; - f.data = data.sub(2,data.length-6); - f.dataSize = f.data.length; - #else - throw "No compress support"; - #end - } - -} +/* + * Copyright (C)2005-2012 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.zip; + +class Tools { + + public static function compress( f : Entry, level : Int ) { + if( f.compressed ) + return; + // this should be optimized with a temp buffer + // that would discard the first two bytes + // (in order to prevent 2x mem usage for large files) + var data = haxe.zip.Compress.run( f.data, level ); + f.compressed = true; + f.data = data.sub(2,data.length-6); + f.dataSize = f.data.length; + } + +} diff --git a/std/haxe/zip/Uncompress.hx b/std/haxe/zip/Uncompress.hx new file mode 100644 index 0000000000000000000000000000000000000000..53a28d34b72bd26bcae1c63162f65c58142f80d4 --- /dev/null +++ b/std/haxe/zip/Uncompress.hx @@ -0,0 +1,44 @@ +/* + * Copyright (C)2005-2012 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.zip; + +class Uncompress { + + public function new( ?windowBits : Int ) { + throw "Not implemented for this platform"; + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return null; + } + + public function setFlushMode( f : FlushMode ) { + } + + public function close() { + } + + public static function run( src : haxe.io.Bytes, ?bufsize : Int ) : haxe.io.Bytes { + return InflateImpl.run(new haxe.io.BytesInput(src),bufsize); + } + +} diff --git a/std/haxe/zip/Writer.hx b/std/haxe/zip/Writer.hx index d4839d321279b761a1c7f40a975b6febecea39be..55a94b02dd641c2dd16a62359304943764ffc51b 100644 --- a/std/haxe/zip/Writer.hx +++ b/std/haxe/zip/Writer.hx @@ -1,174 +1,174 @@ -/* - * Copyright (C)2005-2012 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.zip; - -class Writer { - - /* - * The next constant is required for computing the Central - * Directory Record(CDR) size. CDR consists of some fields - * of constant size and a filename. Constant represents - * total length of all fields with constant size for each - * file in archive - */ - inline static var CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE = 46; - - /* - * The following constant is the total size of all fields - * of Local File Header. It's required for calculating - * offset of start of central directory record - */ - inline static var LOCAL_FILE_HEADER_FIELDS_SIZE = 30; - - var o : haxe.io.Output; - var files : List<{ name : String, compressed : Bool, clen : Int, size : Int, crc : Int, date : Date, fields : haxe.io.Bytes }>; - - public function new( o : haxe.io.Output ) { - this.o = o; - files = new List(); - } - - function writeZipDate( date : Date ) { - var hour = date.getHours(); - var min = date.getMinutes(); - var sec = date.getSeconds() >> 1; - o.writeUInt16( (hour << 11) | (min << 5) | sec ); - var year = date.getFullYear() - 1980; - var month = date.getMonth() + 1; - var day = date.getDate(); - o.writeUInt16( (year << 9) | (month << 5) | day ); - } - - public function writeEntryHeader( f : Entry ) { - var o = this.o; - var flags = 0; - if (f.extraFields != null) { - for( e in f.extraFields ) - switch( e ) { - case FUtf8: flags |= 0x800; - default: - } - } - o.writeInt32(0x04034B50); - o.writeUInt16(0x0014); // version - o.writeUInt16(flags); // flags - if( f.data == null ) { - f.fileSize = 0; - f.dataSize = 0; - f.crc32 = 0; - f.compressed = false; - f.data = haxe.io.Bytes.alloc(0); - } else { - if( f.crc32 == null ) { - if( f.compressed ) throw "CRC32 must be processed before compression"; - f.crc32 = haxe.crypto.Crc32.make(f.data); - } - if( !f.compressed ) - f.fileSize = f.data.length; - f.dataSize = f.data.length; - } - o.writeUInt16(f.compressed?8:0); - writeZipDate(f.fileTime); - o.writeInt32(f.crc32); - o.writeInt32(f.dataSize); - o.writeInt32(f.fileSize); - o.writeUInt16(f.fileName.length); - var e = new haxe.io.BytesOutput(); - if (f.extraFields != null) { - for( f in f.extraFields ) - switch( f ) { - case FInfoZipUnicodePath(name,crc): - var namebytes = haxe.io.Bytes.ofString(name); - e.writeUInt16(0x7075); - e.writeUInt16(namebytes.length + 5); - e.writeByte(1); // version - e.writeInt32(crc); - e.write(namebytes); - case FUnknown(tag,bytes): - e.writeUInt16(tag); - e.writeUInt16(bytes.length); - e.write(bytes); - case FUtf8: - // nothing - } - } - var ebytes = e.getBytes(); - o.writeUInt16(ebytes.length); - o.writeString(f.fileName); - o.write(ebytes); - files.add({ name : f.fileName, compressed : f.compressed, clen : f.data.length, size : f.fileSize, crc : f.crc32, date : f.fileTime, fields : ebytes }); - } - - public function write( files : List ) { - for( f in files ) { - writeEntryHeader(f); - o.writeFullBytes(f.data,0,f.data.length); - } - writeCDR(); - } - - public function writeCDR() { - var cdr_size = 0; - var cdr_offset = 0; - for ( f in files ) { - var namelen = f.name.length; - var extraFieldsLength = f.fields.length; - o.writeInt32(0x02014B50); // header - o.writeUInt16(0x0014); // version made-by - o.writeUInt16(0x0014); // version - o.writeUInt16(0); // flags - o.writeUInt16(f.compressed?8:0); - writeZipDate(f.date); - o.writeInt32(f.crc); - o.writeInt32(f.clen); - o.writeInt32(f.size); - o.writeUInt16(namelen); - o.writeUInt16(extraFieldsLength); - o.writeUInt16(0); //comment length always 0 - o.writeUInt16(0); //disk number start - o.writeUInt16(0); //internal file attributes - o.writeInt32(0); //external file attributes - o.writeInt32(cdr_offset); //relative offset of local header - o.writeString(f.name); - o.write(f.fields); - cdr_size += CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE + namelen + extraFieldsLength; - cdr_offset += LOCAL_FILE_HEADER_FIELDS_SIZE + namelen + extraFieldsLength + f.clen; - } - //end of central dir signature - o.writeInt32(0x06054B50); - //number of this disk - o.writeUInt16(0); - //number of the disk with the start of the central directory - o.writeUInt16(0); - //total number of entries in the central directory on this disk - o.writeUInt16(files.length); - //total number of entries in the central directory - o.writeUInt16(files.length); - //size of the central directory record - o.writeInt32(cdr_size); - //offset of start of central directory with respect to the starting disk number - o.writeInt32(cdr_offset); - // .ZIP file comment length - o.writeUInt16(0); - } - -} +/* + * Copyright (C)2005-2012 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.zip; + +class Writer { + + /* + * The next constant is required for computing the Central + * Directory Record(CDR) size. CDR consists of some fields + * of constant size and a filename. Constant represents + * total length of all fields with constant size for each + * file in archive + */ + inline static var CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE = 46; + + /* + * The following constant is the total size of all fields + * of Local File Header. It's required for calculating + * offset of start of central directory record + */ + inline static var LOCAL_FILE_HEADER_FIELDS_SIZE = 30; + + var o : haxe.io.Output; + var files : List<{ name : String, compressed : Bool, clen : Int, size : Int, crc : Int, date : Date, fields : haxe.io.Bytes }>; + + public function new( o : haxe.io.Output ) { + this.o = o; + files = new List(); + } + + function writeZipDate( date : Date ) { + var hour = date.getHours(); + var min = date.getMinutes(); + var sec = date.getSeconds() >> 1; + o.writeUInt16( (hour << 11) | (min << 5) | sec ); + var year = date.getFullYear() - 1980; + var month = date.getMonth() + 1; + var day = date.getDate(); + o.writeUInt16( (year << 9) | (month << 5) | day ); + } + + public function writeEntryHeader( f : Entry ) { + var o = this.o; + var flags = 0; + if (f.extraFields != null) { + for( e in f.extraFields ) + switch( e ) { + case FUtf8: flags |= 0x800; + default: + } + } + o.writeInt32(0x04034B50); + o.writeUInt16(0x0014); // version + o.writeUInt16(flags); // flags + if( f.data == null ) { + f.fileSize = 0; + f.dataSize = 0; + f.crc32 = 0; + f.compressed = false; + f.data = haxe.io.Bytes.alloc(0); + } else { + if( f.crc32 == null ) { + if( f.compressed ) throw "CRC32 must be processed before compression"; + f.crc32 = haxe.crypto.Crc32.make(f.data); + } + if( !f.compressed ) + f.fileSize = f.data.length; + f.dataSize = f.data.length; + } + o.writeUInt16(f.compressed?8:0); + writeZipDate(f.fileTime); + o.writeInt32(f.crc32); + o.writeInt32(f.dataSize); + o.writeInt32(f.fileSize); + o.writeUInt16(f.fileName.length); + var e = new haxe.io.BytesOutput(); + if (f.extraFields != null) { + for( f in f.extraFields ) + switch( f ) { + case FInfoZipUnicodePath(name,crc): + var namebytes = haxe.io.Bytes.ofString(name); + e.writeUInt16(0x7075); + e.writeUInt16(namebytes.length + 5); + e.writeByte(1); // version + e.writeInt32(crc); + e.write(namebytes); + case FUnknown(tag,bytes): + e.writeUInt16(tag); + e.writeUInt16(bytes.length); + e.write(bytes); + case FUtf8: + // nothing + } + } + var ebytes = e.getBytes(); + o.writeUInt16(ebytes.length); + o.writeString(f.fileName); + o.write(ebytes); + files.add({ name : f.fileName, compressed : f.compressed, clen : f.data.length, size : f.fileSize, crc : f.crc32, date : f.fileTime, fields : ebytes }); + } + + public function write( files : List ) { + for( f in files ) { + writeEntryHeader(f); + o.writeFullBytes(f.data,0,f.data.length); + } + writeCDR(); + } + + public function writeCDR() { + var cdr_size = 0; + var cdr_offset = 0; + for ( f in files ) { + var namelen = f.name.length; + var extraFieldsLength = f.fields.length; + o.writeInt32(0x02014B50); // header + o.writeUInt16(0x0014); // version made-by + o.writeUInt16(0x0014); // version + o.writeUInt16(0); // flags + o.writeUInt16(f.compressed?8:0); + writeZipDate(f.date); + o.writeInt32(f.crc); + o.writeInt32(f.clen); + o.writeInt32(f.size); + o.writeUInt16(namelen); + o.writeUInt16(extraFieldsLength); + o.writeUInt16(0); //comment length always 0 + o.writeUInt16(0); //disk number start + o.writeUInt16(0); //internal file attributes + o.writeInt32(0); //external file attributes + o.writeInt32(cdr_offset); //relative offset of local header + o.writeString(f.name); + o.write(f.fields); + cdr_size += CENTRAL_DIRECTORY_RECORD_FIELDS_SIZE + namelen + extraFieldsLength; + cdr_offset += LOCAL_FILE_HEADER_FIELDS_SIZE + namelen + extraFieldsLength + f.clen; + } + //end of central dir signature + o.writeInt32(0x06054B50); + //number of this disk + o.writeUInt16(0); + //number of the disk with the start of the central directory + o.writeUInt16(0); + //total number of entries in the central directory on this disk + o.writeUInt16(files.length); + //total number of entries in the central directory + o.writeUInt16(files.length); + //size of the central directory record + o.writeInt32(cdr_size); + //offset of start of central directory with respect to the starting disk number + o.writeInt32(cdr_offset); + // .ZIP file comment length + o.writeUInt16(0); + } + +} diff --git a/std/java/Boot.hx b/std/java/Boot.hx index 8213f52d8ec4d6aab89cb1eaa4b4e9222632f063..24d4197ce5673400259a37117b3a248997b05c2f 100644 --- a/std/java/Boot.hx +++ b/std/java/Boot.hx @@ -1,53 +1,53 @@ -/* - * Copyright (C)2005-2012 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; -import java.internal.Exceptions; -import java.internal.Function; -import java.internal.HxObject; -import java.internal.Runtime; -import java.internal.Iterator; -import java.Lib; -//import java.internal.StringExt; -import java.StdTypes; -import Reflect; -import Map; -import haxe.ds.StringMap; -import java.lang.Boolean; -import java.lang.Character; -import java.lang.Class; -import java.lang.Number; -import java.lang.Byte; -import java.lang.Double; -import java.lang.Float; -import java.lang.Integer; -import java.lang.Long; -import java.lang.Short; -import java.lang.Throwable; -import java.internal.StringExt; -import java.internal.FieldLookup; - -extern class Boot -{ - - - -} +/* + * Copyright (C)2005-2012 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; +import java.internal.Exceptions; +import java.internal.Function; +import java.internal.HxObject; +import java.internal.Runtime; +import java.internal.Iterator; +import java.Lib; +//import java.internal.StringExt; +import java.StdTypes; +import Reflect; +import Map; +import haxe.ds.StringMap; +import java.lang.Boolean; +import java.lang.Character; +import java.lang.Class; +import java.lang.Number; +import java.lang.Byte; +import java.lang.Double; +import java.lang.Float; +import java.lang.Integer; +import java.lang.Long; +import java.lang.Short; +import java.lang.Throwable; +import java.internal.StringExt; +import java.internal.FieldLookup; + +extern class Boot +{ + + + +} diff --git a/std/java/Lib.hx b/std/java/Lib.hx index eb53c8dd5eca63cf8a41a5b1ab0c88059832696c..b7aa3a894b633c2e56e1a458db50686329d35836 100644 --- a/std/java/Lib.hx +++ b/std/java/Lib.hx @@ -1,90 +1,171 @@ -/* - * Copyright (C)2005-2012 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; - -/** - Platform-specific Java Library. Provides some platform-specific functions for the Java target, - such as conversion from haxe types to native types and vice-versa. -**/ -//we cannot use the java package for custom classes, so we're redefining it as "haxe.java.Lib" -@:native('haxe.java.Lib') class Lib -{ - - /** - Returns a native array from the supplied Array. This native array is unsafe to be written on, - as it may or may not be linked to the actual Array implementation. - - If equalLengthRequired is true, the result might be a copy of an array with the correct size. - **/ - public static function nativeArray(arr:Array, equalLengthRequired:Bool):NativeArray - { - var native:NativeArray = untyped arr.__a; - if (native.length == arr.length) - { - return native; - } else { - return null; - } - } - - /** - Gets the native System.Type from the supplied object. Will throw an exception in case of null being passed. - **/ - @:functionCode(' - return (java.lang.Class) obj.getClass(); - ') - public static function nativeType(obj:T):java.lang.Class - { - return null; - } - - /** - Returns a Haxe Array of a native Array. - It won't copy the contents of the native array, so unless any operation triggers an array resize, - all changes made to the Haxe array will affect the native array argument. - **/ - public static function array(native:java.NativeArray):Array - { - return untyped Array.ofNative(native); - } - - /** - Allocates a new Haxe Array with a predetermined size - **/ - public static function arrayAlloc(size:Int):Array - { - return untyped Array.alloc(size); - } - - /** - Ensures that one thread does not enter a critical section of code while another thread - is in the critical section. If another thread attempts to enter a locked code, it - will wait, block, until the object is released. - This is the equivalent to "synchronized" in java code. - - This method only exists at compile-time, so it can't be called via reflection. - **/ - @:extern public static inline function lock(obj:Dynamic, block:Dynamic):Void - { - untyped __lock__(obj, block); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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; + +/** + Platform-specific Java Library. Provides some platform-specific functions for the Java target, + such as conversion from haxe types to native types and vice-versa. +**/ +//we cannot use the java package for custom classes, so we're redefining it as "haxe.java.Lib" +@:native('haxe.java.Lib') class Lib +{ + + /** + Returns a native array from the supplied Array. This native array is unsafe to be written on, + as it may or may not be linked to the actual Array implementation. + + If equalLengthRequired is true, the result might be a copy of an array with the correct size. + **/ + inline public static function nativeArray(arr:Array, equalLengthRequired:Bool):NativeArray + { + var ret = new NativeArray(arr.length); + for (i in 0...arr.length) + { + ret[i] = arr[i]; + } + return ret; + } + + /** + Gets the native `java.lang.Class` from the supplied object. Will throw an exception in case of null being passed. + [deprecated] - use `getNativeType` instead + **/ + @:deprecated('The function `nativeType` is deprecated and will be removed in later versions. Please use `getNativeType` instead') + inline public static function nativeType(obj:T):java.lang.Class + { + return untyped obj.getClass(); + } + + /** + Gets the native `java.lang.Class` from the supplied object. Will throw an exception in case of null being passed. + [deprecated] - use `getNativeType` instead + **/ + inline public static function getNativeType(obj:T):java.lang.Class + { + return untyped obj.getClass(); + } + + /** + Returns a Class<> equivalent to the native java.lang.Class type. + **/ + public static inline function fromNativeType(t:java.lang.Class):Class + { + return untyped t; + } + + /** + Returns a java.lang.Class equivalent to the Haxe Class<> type. + **/ + public static inline function toNativeType(cl:Class):java.lang.Class + { + return untyped cl; + } + + /** + Returns a java.lang.Class equivalent to the Haxe Enum<> type. + **/ + public static inline function toNativeEnum(cl:Enum):java.lang.Class + { + return untyped cl; + } + + /** + Returns a Haxe Array of a native Array. + Unless `copy` is true, it won't copy the contents of the native array, + so unless any operation triggers an array resize, all changes made to the Haxe array will affect the native array argument. + **/ + @:generic public static function array(native:java.NativeArray):Array + { + return untyped Array.ofNative(native); + } + + @:extern inline private static function doArray(native:java.NativeArray):Array + { + var ret:NativeArray = new NativeArray(native.length); + for (i in 0...native.length) + { + ret[i] = native[i]; + } + return untyped Array.ofNative(ret); + } + + public static function array_Int(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_Float(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_Bool(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_java_Int8(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_java_Int16(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_java_Char16(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_Single(native:java.NativeArray):Array + { + return doArray(native); + } + + public static function array_haxe_Int64(native:java.NativeArray):Array + { + return doArray(native); + } + + /** + Allocates a new Haxe Array with a predetermined size + **/ + public static function arrayAlloc(size:Int):Array + { + return untyped Array.alloc(size); + } + + /** + Ensures that one thread does not enter a critical section of code while another thread + is in the critical section. If another thread attempts to enter a locked code, it + will wait, block, until the object is released. + This is the equivalent to "synchronized" in java code. + + This method only exists at compile-time, so it can't be called via reflection. + **/ + @:extern public static inline function lock(obj:Dynamic, block:T):Void + { + untyped __lock__(obj, block); + } +} diff --git a/std/java/NativeArray.hx b/std/java/NativeArray.hx index 5432b433e4f974e3a6e92f2d443cf30555477309..14b153acaf49d310ea7e80cb732407a38129e779 100644 --- a/std/java/NativeArray.hx +++ b/std/java/NativeArray.hx @@ -1,35 +1,50 @@ -/* - * Copyright (C)2005-2012 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; - -/** - * ... - * @author waneck - */ - -@:nativeGen extern class NativeArray implements ArrayAccess -{ - public var length(default, null):Int; - - public function new(len:Int):Void; - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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; + +import haxe.extern.Rest; + +/** + Represents a java fixed-size Array (`T[]`) +**/ +@:nativeGen extern class NativeArray implements ArrayAccess +{ + /** + Creates a new array with the specified elements. + + Usage: + ```haxe + var elements = NativeArray.make(1,2,3,4,5,6); + ``` + **/ + public static function make(elements:Rest):NativeArray; + + /** + The length of the array + **/ + public var length(default, null):Int; + + /** + Allocates a new array with size `len` + **/ + public function new(len:Int):Void; +} diff --git a/std/java/StdTypes.hx b/std/java/StdTypes.hx index 4f1d80e3ca4ef17ca6c3c4f5855084ff293ad018..b03e7e95bdd8cedc0f23515c2c8e6bf2301c4398 100644 --- a/std/java/StdTypes.hx +++ b/std/java/StdTypes.hx @@ -1,31 +1,64 @@ -/* - * Copyright (C)2005-2012 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; - -/** - * ... - * @author waneck - */ - -@:notNull @:runtimeValue @:coreType abstract Int8 from Int {} -@:notNull @:runtimeValue @:coreType abstract Int16 from Int {} -@:notNull @:runtimeValue @:coreType abstract Char16 from Int {} +/* + * Copyright (C)2005-2012 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; + +@:notNull @:runtimeValue @:coreType abstract Int8 from Int {} +@:notNull @:runtimeValue @:coreType abstract Int16 from Int {} +@:notNull @:runtimeValue @:coreType abstract Char16 from Int {} +@:notNull @:runtimeValue @:coreType abstract Int64 from Int from Float +{ + @:op(A+B) public static function addI(lhs:Int64, rhs:Int):Int64; + @:op(A+B) public static function add(lhs:Int64, rhs:Int64):Int64; + @:op(A*B) public static function mulI(lhs:Int64, rhs:Int):Int64; + @:op(A*B) public static function mul(lhs:Int64, rhs:Int64):Int64; + @:op(A%B) public static function modI(lhs:Int64, rhs:Int):Int64; + @:op(A%B) public static function mod(lhs:Int64, rhs:Int64):Int64; + @:op(A-B) public static function subI(lhs:Int64, rhs:Int):Int64; + @:op(A-B) public static function sub(lhs:Int64, rhs:Int64):Int64; + @:op(A/B) public static function divI(lhs:Int64, rhs:Int):Int64; + @:op(A/B) public static function div(lhs:Int64, rhs:Int64):Int64; + @:op(A|B) public static function orI(lhs:Int64, rhs:Int):Int64; + @:op(A|B) public static function or(lhs:Int64, rhs:Int64):Int64; + @:op(A^B) public static function xorI(lhs:Int64, rhs:Int):Int64; + @:op(A^B) public static function xor(lhs:Int64, rhs:Int64):Int64; + @:op(A&B) public static function andI(lhs:Int64, rhs:Int):Int64; + @:op(A&B) public static function and(lhs:Int64, rhs:Int64):Int64; + @:op(A<>B) public static function shrI(lhs:Int64, rhs:Int):Int64; + @:op(A>>B) public static function shr(lhs:Int64, rhs:Int64):Int64; + @:op(A>>>B) public static function ushrI(lhs:Int64, rhs:Int):Int64; + @:op(A>>>B) public static function ushr(lhs:Int64, rhs:Int64):Int64; + + @:op(A>B) public static function gt(lhs:Int64, rhs:Int64):Bool; + @:op(A>=B) public static function gte(lhs:Int64, rhs:Int64):Bool; + @:op(A implements ArrayAccess { - /** - The length of the Array - **/ public var length(default,null) : Int; private var __a:NativeArray; @@ -59,18 +51,12 @@ import java.NativeArray; return null; } - /** - Creates a new Array. - **/ public function new() : Void { this.length = 0; this.__a = new NativeArray(0); } - /** - Returns a new Array by appending [a] to [this]. - **/ public function concat( a : Array ) : Array { var length = length; @@ -101,9 +87,6 @@ import java.NativeArray; this.length = len; } - /** - Returns a representation of an array with [sep] for separating each element. - **/ public function join( sep : String ) : String { var buf = new StringBuf(); @@ -123,9 +106,6 @@ import java.NativeArray; return buf.toString(); } - /** - Removes the last element of the array and returns it. - **/ public function pop() : Null { var __a = __a; @@ -142,9 +122,6 @@ import java.NativeArray; } } - /** - Adds the element [x] at the end of the array. - **/ public function push(x : T) : Int { var length = length; @@ -161,9 +138,6 @@ import java.NativeArray; return ++this.length; } - /** - Reverse the order of elements of the Array. - **/ public function reverse() : Void { var i = 0; @@ -180,9 +154,6 @@ import java.NativeArray; } } - /** - Removes the first element and returns it. - **/ public function shift() : Null { var l = this.length; @@ -199,12 +170,6 @@ import java.NativeArray; return x; } - /** - Copies the range of the array starting at [pos] up to, - but not including, [end]. Both [pos] and [end] can be - negative to count from the end: -1 is the last item in - the array. - **/ public function slice( pos : Int, ?end : Int ) : Array { if( pos < 0 ){ @@ -227,11 +192,6 @@ import java.NativeArray; return ofNative(newarr); } - /** - Sort the Array according to the comparison public function [f]. - [f(x,y)] should return [0] if [x == y], [>0] if [x > y] - and [<0] if [x < y]. - **/ public function sort( f : T -> T -> Int ) : Void { if (length == 0) @@ -239,34 +199,27 @@ import java.NativeArray; quicksort(0, length - 1, f); } - /** - quicksort author: tong disktree - http://blog.disktree.net/2008/10/26/array-sort-performance.html - */ private function quicksort( lo : Int, hi : Int, f : T -> T -> Int ) : Void { - var buf = __a; + var buf = __a; var i = lo, j = hi; - var p = buf[(i + j) >> 1]; + var p = buf[(i + j) >> 1]; while ( i <= j ) { - while ( f(buf[i], p) < 0 ) i++; - while ( f(buf[j], p) > 0 ) j--; + while ( i < hi && f(buf[i], p) < 0 ) i++; + while ( j > lo && f(buf[j], p) > 0 ) j--; if ( i <= j ) { - var t = buf[i]; - buf[i++] = buf[j]; - buf[j--] = t; - } + var t = buf[i]; + buf[i++] = buf[j]; + buf[j--] = t; + } } if( lo < j ) quicksort( lo, j, f ); - if( i < hi ) quicksort( i, hi, f ); + if( i < hi ) quicksort( i, hi, f ); } - /** - Removes [len] elements starting from [pos] an returns them. - **/ public function splice( pos : Int, len : Int ) : Array { if( len < 0 ) return new Array(); @@ -318,9 +271,6 @@ import java.NativeArray; a[this.length + len] = null; } - /** - Returns a displayable representation of the Array content. - **/ public function toString() : String { var ret = new StringBuf(); @@ -340,9 +290,6 @@ import java.NativeArray; return ret.toString(); } - /** - Adds the element [x] at the start of the array. - **/ public function unshift( x : T ) : Void { var __a = __a; @@ -362,10 +309,6 @@ import java.NativeArray; ++this.length; } - /** - Inserts the element [x] at the position [pos]. - All elements after [pos] are moved one index ahead. - **/ public function insert( pos : Int, x : T ) : Void { var l = this.length; @@ -400,11 +343,6 @@ import java.NativeArray; } } - /** - Removes the first occurence of [x]. - Returns false if [x] was not present. - Elements are compared by using standard equality. - **/ public function remove( x : T ) : Bool { var __a = __a; @@ -424,10 +362,37 @@ import java.NativeArray; return false; } - /** - Returns a copy of the Array. The values are not - copied, only the Array structure. - **/ + public function indexOf(x : T, ?fromIndex:Int) : Int { + var len = length, a = __a, i:Int = (fromIndex == null) ? 0 : fromIndex; + if (i < 0) + { + i += len; + if (i < 0) i = 0; + } + while (i < len) + { + if (a[i] == x) + return i; + i++; + } + return -1; + } + + public function lastIndexOf(x : T, ?fromIndex:Int) : Int { + var len = length, a = __a, i:Int = (fromIndex == null) ? len - 1 : fromIndex; + if (i >= len) + i = len - 1; + else if (i < 0) + i += len; + while (i >= 0) + { + if (a[i] == x) + return i; + i--; + } + return -1; + } + public function copy() : Array { var len = length; @@ -437,18 +402,9 @@ import java.NativeArray; return ofNative(newarr); } - /** - Returns an iterator of the Array values. - **/ - public function iterator() : Iterator + public inline function iterator() : Iterator { - var i = 0; - var len = length; - return - { - hasNext:function() return i < len, - next:function() return __a[i++] - }; + return new ArrayIterator(this); } public function map( f : T -> S ) : Array { @@ -505,3 +461,21 @@ import java.NativeArray; return __a[idx] = val; } } + +@:final +private 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/java/_std/Date.hx b/std/java/_std/Date.hx index 569bb7f53c3468043ec1be03738be0ba351ab331..a16b55506c6671c31053056f7c87feac497e9186 100644 --- a/std/java/_std/Date.hx +++ b/std/java/_std/Date.hx @@ -1,172 +1,126 @@ -/* - * Copyright (C)2005-2012 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; -import haxe.Int64; - -@:SuppressWarnings("deprecation") -@:coreApi class Date -{ - private var date:java.util.Date; - - /** - Creates a new date object. - **/ - public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void - { - //issue #1769 - year = year != 0 ? year - 1900 : 0; - date = new java.util.Date(year, month, day, hour, min, sec); - } - - /** - Returns the timestamp of the date. It's the number of milliseconds - elapsed since 1st January 1970. It might only have a per-second precision - depending on the platforms. - **/ - public inline function getTime() : Float - { - return cast date.getTime(); - } - - /** - Returns the hours value of the date (0-23 range). - **/ - public inline function getHours() : Int - { - return date.getHours(); - } - - /** - Returns the minutes value of the date (0-59 range). - **/ - public inline function getMinutes() : Int - { - return date.getMinutes(); - } - - /** - Returns the seconds of the date (0-59 range). - **/ - public inline function getSeconds() : Int - { - return date.getSeconds(); - } - - /** - Returns the full year of the date. - **/ - public inline function getFullYear() : Int - { - return date.getYear() + 1900; - } - - /** - Returns the month of the date (0-11 range). - **/ - public inline function getMonth() : Int - { - return date.getMonth(); - } - - /** - Returns the day of the date (1-31 range). - **/ - public inline function getDate() : Int - { - return date.getDate(); - } - - /** - Returns the week day of the date (0-6 range). - **/ - public inline function getDay() : Int - { - return date.getDay(); - } - - /** - Returns a string representation for the Date, by using the - standard format [YYYY-MM-DD HH:MM:SS]. See [DateTools.format] for - other formating rules. - **/ - public function toString():String - { - var m = date.getMonth() + 1; - var d = date.getDate(); - var h = date.getHours(); - var mi = date.getMinutes(); - var s = date.getSeconds(); - return (date.getYear() + 1900) - +"-"+(if( m < 10 ) "0"+m else ""+m) - +"-"+(if( d < 10 ) "0"+d else ""+d) - +" "+(if( h < 10 ) "0"+h else ""+h) - +":"+(if( mi < 10 ) "0"+mi else ""+mi) - +":"+(if( s < 10 ) "0"+s else ""+s); - } - - /** - Returns a Date representing the current local time. - **/ - static public function now() : Date - { - var d = new Date(0, 0, 0, 0, 0, 0); - d.date = new java.util.Date(); - return d; - } - - /** - Returns a Date from a timestamp [t] which is the number of - milliseconds elapsed since 1st January 1970. - **/ - static public function fromTime( t : Float ) : Date - { - var d = new Date(0, 0, 0, 0, 0, 0); - d.date = new java.util.Date(cast(t, Int64)); - return d; - } - - /** - Returns a Date from a formated string of one of the following formats : - [YYYY-MM-DD hh:mm:ss] or [YYYY-MM-DD] or [hh:mm:ss]. The first two formats - are expressed in local time, the third in UTC Epoch. - **/ - static public function fromString( s : String ) : Date - { - switch( s.length ) - { - case 8: // hh:mm:ss - var k = s.split(":"); - var d : Date = new Date(0, 0, 0, Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2])); - return d; - case 10: // YYYY-MM-DD - var k = s.split("-"); - return new Date(Std.parseInt(k[0]),Std.parseInt(k[1]) - 1,Std.parseInt(k[2]),0,0,0); - case 19: // YYYY-MM-DD hh:mm:ss - var k = s.split(" "); - var y = k[0].split("-"); - var t = k[1].split(":"); - return new Date(Std.parseInt(y[0]),Std.parseInt(y[1]) - 1,Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2])); - default: - throw "Invalid date format : " + s; - } - } -} +/* + * Copyright (C)2005-2012 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; +import haxe.Int64; + +@:SuppressWarnings("deprecation") +@:coreApi class Date +{ + private var date:java.util.Date; + + public function new(year : Int, month : Int, day : Int, hour : Int, min : Int, sec : Int ) : Void + { + //issue #1769 + year = year != 0 ? year - 1900 : 0; + date = new java.util.Date(year, month, day, hour, min, sec); + } + + public inline function getTime() : Float + { + return cast date.getTime(); + } + + public inline function getHours() : Int + { + return date.getHours(); + } + + public inline function getMinutes() : Int + { + return date.getMinutes(); + } + + public inline function getSeconds() : Int + { + return date.getSeconds(); + } + + public inline function getFullYear() : Int + { + return date.getYear() + 1900; + } + + public inline function getMonth() : Int + { + return date.getMonth(); + } + + public inline function getDate() : Int + { + return date.getDate(); + } + + public inline function getDay() : Int + { + return date.getDay(); + } + + public function toString():String + { + var m = date.getMonth() + 1; + var d = date.getDate(); + var h = date.getHours(); + var mi = date.getMinutes(); + var s = date.getSeconds(); + return (date.getYear() + 1900) + +"-"+(if( m < 10 ) "0"+m else ""+m) + +"-"+(if( d < 10 ) "0"+d else ""+d) + +" "+(if( h < 10 ) "0"+h else ""+h) + +":"+(if( mi < 10 ) "0"+mi else ""+mi) + +":"+(if( s < 10 ) "0"+s else ""+s); + } + + static public function now() : Date + { + var d = new Date(0, 0, 0, 0, 0, 0); + d.date = new java.util.Date(); + return d; + } + + static public function fromTime( t : Float ) : Date + { + var d = new Date(0, 0, 0, 0, 0, 0); + d.date = new java.util.Date(cast(t, Int64)); + return d; + } + + static public function fromString( s : String ) : Date + { + switch( s.length ) + { + case 8: // hh:mm:ss + var k = s.split(":"); + var d : Date = new Date(0, 0, 0, Std.parseInt(k[0]), Std.parseInt(k[1]), Std.parseInt(k[2])); + return d; + case 10: // YYYY-MM-DD + var k = s.split("-"); + return new Date(Std.parseInt(k[0]),Std.parseInt(k[1]) - 1,Std.parseInt(k[2]),0,0,0); + case 19: // YYYY-MM-DD hh:mm:ss + var k = s.split(" "); + var y = k[0].split("-"); + var t = k[1].split(":"); + return new Date(Std.parseInt(y[0]),Std.parseInt(y[1]) - 1,Std.parseInt(y[2]),Std.parseInt(t[0]),Std.parseInt(t[1]),Std.parseInt(t[2])); + default: + throw "Invalid date format : " + s; + } + } +} diff --git a/std/java/_std/EReg.hx b/std/java/_std/EReg.hx index 19e10c70bb59fbe095db32e8e937f6b910511637..e8a0964d2886811864022649e364a9bf9ec79a65 100644 --- a/std/java/_std/EReg.hx +++ b/std/java/_std/EReg.hx @@ -1,180 +1,180 @@ -/* - * Copyright (C)2005-2012 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. - */ -import java.util.regex.*; - -@:coreType class EReg { - - private var pattern:String; - private var matcher:Matcher; - private var cur:String; - private var isGlobal:Bool; - - public function new( r : String, opt : String ) { - var flags = 0; - for (i in 0...opt.length) - { - switch(StringTools.fastCodeAt(opt, i)) - { - case 'i'.code: - flags |= Pattern.CASE_INSENSITIVE; - case 'm'.code: - flags |= Pattern.MULTILINE; - case 's'.code: - flags |= Pattern.DOTALL; - case 'g'.code: - isGlobal = true; - } - } - - matcher = Pattern._compile(convert(r), flags).matcher(""); - pattern = r; - } - - private static function convert(r:String):String - { - //some references of the implementation: - //http://stackoverflow.com/questions/809647/java-vs-javascript-regex-problem - //http://stackoverflow.com/questions/4788413/how-to-convert-javascript-regex-to-safe-java-regex - //Some necessary changes: - // - // \0 -> \x00 - // \v -> \x0b - // [^] -> [\s\S] - // unescaped ', " -> \', \" - /* FIXME - var pat = new StringBuf(); - var len = r.length; - var i = 0; - while (i < len) - { - var c = StringTools.fastCodeAt(r, i++); - switch(c) - { - case '\\'.code: //escape-sequence - - } - } - */ - return r; - } - - public function match( s : String ) : Bool { - cur = s; - matcher = matcher.reset(s); - return matcher.find(); - } - - public function matched( n : Int ) : String - { - if (n == 0) - return matcher.group(); - else - return matcher.group(n); - } - - public function matchedLeft() : String - { - return untyped cur.substring(0, matcher.start()); - } - - public function matchedRight() : String - { - return untyped cur.substring(matcher.end(), cur.length); - } - - public function matchedPos() : { pos : Int, len : Int } { - var start = matcher.start(); - return { pos : start, len : matcher.end() - start }; - } - - public function matchSub( s : String, pos : Int, len : Int = -1):Bool { - matcher = matcher.reset(len < 0 ? s : s.substr(0,pos + len)); - cur = s; - return matcher.find(pos); - } - - public function split( s : String ) : Array - { - if (isGlobal) - { - var ret = []; - while(this.match(s)) - { - ret.push(matchedLeft()); - s = matchedRight(); - } - ret.push(s); - return ret; - } else { - var m = matcher; - m.reset(s); - if (m.find()) - { - return untyped [s.substring(0, m.start()), s.substring(m.end(), s.length)]; - } else { - return [s]; - } - } - } - - inline function start(group:Int) - { - return matcher.start(group); - } - - inline function len(group:Int) - { - return matcher.end(group) - matcher.start(group); - } - - public function replace( s : String, by : String ) : String - { - matcher.reset(s); - by = by.split("$$").join("\\$"); - return isGlobal ? matcher.replaceAll(by) : matcher.replaceFirst(by); - } - - public function map( s : String, f : EReg -> String ) : String { - var offset = 0; - var buf = new StringBuf(); - do { - if (offset >= s.length) - break; - else if (!matchSub(s, offset)) { - buf.add(s.substr(offset)); - break; - } - var p = matchedPos(); - buf.add(s.substr(offset, p.pos - offset)); - buf.add(f(this)); - if (p.len == 0) { - buf.add(s.substr(p.pos, 1)); - offset = p.pos + 1; - } - else - offset = p.pos + p.len; - } while (isGlobal); - if (!isGlobal && offset > 0 && offset < s.length) - buf.add(s.substr(offset)); - return buf.toString(); - } -} +/* + * Copyright (C)2005-2012 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. + */ +import java.util.regex.*; + +@:coreApi class EReg { + + private var pattern:String; + private var matcher:Matcher; + private var cur:String; + private var isGlobal:Bool; + + public function new( r : String, opt : String ) { + var flags = 0; + for (i in 0...opt.length) + { + switch(StringTools.fastCodeAt(opt, i)) + { + case 'i'.code: + flags |= Pattern.CASE_INSENSITIVE; + case 'm'.code: + flags |= Pattern.MULTILINE; + case 's'.code: + flags |= Pattern.DOTALL; + case 'g'.code: + isGlobal = true; + } + } + + matcher = Pattern.compile(convert(r), flags).matcher(""); + pattern = r; + } + + private static function convert(r:String):String + { + //some references of the implementation: + //http://stackoverflow.com/questions/809647/java-vs-javascript-regex-problem + //http://stackoverflow.com/questions/4788413/how-to-convert-javascript-regex-to-safe-java-regex + //Some necessary changes: + // + // \0 -> \x00 + // \v -> \x0b + // [^] -> [\s\S] + // unescaped ', " -> \', \" + /* FIXME + var pat = new StringBuf(); + var len = r.length; + var i = 0; + while (i < len) + { + var c = StringTools.fastCodeAt(r, i++); + switch(c) + { + case '\\'.code: //escape-sequence + + } + } + */ + return r; + } + + public function match( s : String ) : Bool { + cur = s; + matcher = matcher.reset(s); + return matcher.find(); + } + + public function matched( n : Int ) : String + { + if (n == 0) + return matcher.group(); + else + return matcher.group(n); + } + + public function matchedLeft() : String + { + return untyped cur.substring(0, matcher.start()); + } + + public function matchedRight() : String + { + return untyped cur.substring(matcher.end(), cur.length); + } + + public function matchedPos() : { pos : Int, len : Int } { + var start = matcher.start(); + return { pos : start, len : matcher.end() - start }; + } + + public function matchSub( s : String, pos : Int, len : Int = -1):Bool { + matcher = matcher.reset(len < 0 ? s : s.substr(0,pos + len)); + cur = s; + return matcher.find(pos); + } + + public function split( s : String ) : Array + { + if (isGlobal) + { + var ret = []; + while(this.match(s)) + { + ret.push(matchedLeft()); + s = matchedRight(); + } + ret.push(s); + return ret; + } else { + var m = matcher; + m.reset(s); + if (m.find()) + { + return untyped [s.substring(0, m.start()), s.substring(m.end(), s.length)]; + } else { + return [s]; + } + } + } + + inline function start(group:Int) : Int + { + return matcher.start(group); + } + + inline function len(group:Int) : Int + { + return matcher.end(group) - matcher.start(group); + } + + public function replace( s : String, by : String ) : String + { + matcher.reset(s); + by = by.split("$$").join("\\$"); + return isGlobal ? matcher.replaceAll(by) : matcher.replaceFirst(by); + } + + public function map( s : String, f : EReg -> String ) : String { + var offset = 0; + var buf = new StringBuf(); + do { + if (offset >= s.length) + break; + else if (!matchSub(s, offset)) { + buf.add(s.substr(offset)); + break; + } + var p = matchedPos(); + buf.add(s.substr(offset, p.pos - offset)); + buf.add(f(this)); + if (p.len == 0) { + buf.add(s.substr(p.pos, 1)); + offset = p.pos + 1; + } + else + offset = p.pos + p.len; + } while (isGlobal); + if (!isGlobal && offset > 0 && offset < s.length) + buf.add(s.substr(offset)); + return buf.toString(); + } +} diff --git a/std/java/_std/Math.hx b/std/java/_std/Math.hx index 57d5473c19af970fcec2104d0d7cd84351ada21f..6f159c06ee388ae1d5c40071fbff800c503e5e3c 100644 --- a/std/java/_std/Math.hx +++ b/std/java/_std/Math.hx @@ -1,59 +1,59 @@ -/* - * Copyright (C)2005-2012 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. - */ -/** - This class defines mathematical functions and constants. -**/ -@:coreApi -@:native("java.lang.Math") extern class Math -{ - static var PI(default,null) : Float; - static var NaN(default,null) : Float; - static var NEGATIVE_INFINITY(default,null) : Float; - static var POSITIVE_INFINITY(default,null) : Float; - - static function abs(v:Float):Float; - static function min(a:Float,b:Float):Float; - static function max(a:Float,b:Float):Float; - static function sin(v:Float):Float; - static function cos(v:Float):Float; - static function atan2(y:Float,x:Float):Float; - static function tan(v:Float):Float; - static function exp(v:Float):Float; - static function log(v:Float):Float; - static function sqrt(v:Float):Float; - static function round(v:Float):Int; - static function floor(v:Float):Int; - static function ceil(v:Float):Int; - static function atan(v:Float):Float; - static function fround(v:Float):Float; - static function ffloor(v:Float):Float; - static function fceil(v:Float):Float; - static function asin(v:Float):Float; - static function acos(v:Float):Float; - static function pow(v:Float,exp:Float):Float; - static function random() : Float; - - static function isFinite( f : Float ) : Bool; - static function isNaN( f : Float ) : Bool; -} - - +/* + * Copyright (C)2005-2012 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 +@:native("java.lang.Math") extern class Math +{ + static var PI(default,null) : Float; + static var NaN(default,null) : Float; + static var NEGATIVE_INFINITY(default,null) : Float; + static var POSITIVE_INFINITY(default,null) : Float; + + static function abs(v:Float):Float; + static function min(a:Float,b:Float):Float; + static function max(a:Float,b:Float):Float; + static function sin(v:Float):Float; + static function cos(v:Float):Float; + static function atan2(y:Float,x:Float):Float; + static function tan(v:Float):Float; + static function exp(v:Float):Float; + static function log(v:Float):Float; + static function sqrt(v:Float):Float; + static function round(v:Float):Int; + static function floor(v:Float):Int; + static function ceil(v:Float):Int; + static function atan(v:Float):Float; + inline static function fround(v:Float):Float { + return ffloor(v + 0.5); + } + static function ffloor(v:Float):Float; + static function fceil(v:Float):Float; + static function asin(v:Float):Float; + static function acos(v:Float):Float; + static function pow(v:Float,exp:Float):Float; + static function random() : Float; + + static function isFinite( f : Float ) : Bool; + static function isNaN( f : Float ) : Bool; +} + + diff --git a/std/java/_std/Reflect.hx b/std/java/_std/Reflect.hx index 8fab633a9575ce10e845bc06735bb1dfb283547c..a0e77934fd8187e44a44c52c421954ed001264b8 100644 --- a/std/java/_std/Reflect.hx +++ b/std/java/_std/Reflect.hx @@ -19,227 +19,117 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + import java.internal.Function; +import java.internal.HxObject; +import java.internal.Runtime; import java.Boot; -/* - * Copyright (c) 2005, The haXe Project Contributors - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ -/** - The Reflect API is a way to manipulate values dynamicly through an - abstract interface in an untyped manner. Use with care. -**/ @:keep @:coreApi class Reflect { - /** - Tells if an object has a field set. This doesn't take into account the object prototype (class methods). - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, false, true, false) != haxe.lang.Runtime.undefined; - - return haxe.lang.Runtime.slowHasField(o, field); - ') public static function hasField( o : Dynamic, field : String ) : Bool { - return false; + if (Std.is(o, IHxObject)) { + return untyped (o : IHxObject).__hx_getField(field, false, true, false) != Runtime.undefined; + } + return Runtime.slowHasField(o, field); } - /** - Returns the field of an object, or null if [o] is not an object or doesn't have this field. - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, false, false, false); - - return haxe.lang.Runtime.slowGetField(o, field, false); - ') public static function field( o : Dynamic, field : String ) : Dynamic { - return null; + if (Std.is(o, IHxObject)) { + return untyped (o : IHxObject).__hx_getField(field, false, false, false); + } + return Runtime.slowGetField(o, field, false); } - - /** - Set an object field value. - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - ((haxe.lang.IHxObject) o).__hx_setField(field, value, false); - else - haxe.lang.Runtime.slowSetField(o, field, value); - ') public static function setField( o : Dynamic, field : String, value : Dynamic ) : Void { - + if (Std.is(o, IHxObject)) { + untyped (o : IHxObject).__hx_setField(field, value, false); + } else { + Runtime.slowSetField(o, field, value); + } } - /** - Similar to field but also supports property (might be slower). - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - return ((haxe.lang.IHxObject) o).__hx_getField(field, false, false, true); - - if (haxe.lang.Runtime.slowHasField(o, "get_" + field)) - return haxe.lang.Runtime.slowCallField(o, "get_" + field, null); - - return haxe.lang.Runtime.slowGetField(o, field, false); - ') public static function getProperty( o : Dynamic, field : String ) : Dynamic { - return null; + if (Std.is(o, IHxObject)) { + return untyped (o : IHxObject).__hx_getField(field, false, false, true); + } + if (Runtime.slowHasField(o, "get_" + field)) { + return Runtime.slowCallField(o, "get_" + field, null); + } + return Runtime.slowGetField(o, field, false); } - /** - Similar to setField but also supports property (might be slower). - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - ((haxe.lang.IHxObject) o).__hx_setField(field, value, true); - else if (haxe.lang.Runtime.slowHasField(o, "set_" + field)) - haxe.lang.Runtime.slowCallField(o, "set_" + field, new Array( new java.lang.Object[]{value} )); - else - haxe.lang.Runtime.slowSetField(o, field, value); - ') public static function setProperty( o : Dynamic, field : String, value : Dynamic ) : Void { - + if (Std.is(o, IHxObject)) { + untyped (o : IHxObject).__hx_setField(field, value, true); + } else if (Runtime.slowHasField(o, "set_" + field)) { + Runtime.slowCallField(o, "set_" + field, [value]); + } else { + Runtime.slowSetField(o, field, value); + } } - /** - Call a method with the given object and arguments. - **/ - @:functionCode(' - return ((haxe.lang.Function) func).__hx_invokeDynamic(args); - ') - public static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic + public static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic { - return null; + return untyped (func : Function).__hx_invokeDynamic(args); } - /** - Returns the list of fields of an object, excluding its prototype (class methods). - **/ - @:functionCode(' - if (o instanceof haxe.lang.IHxObject) - { - Array ret = new Array(); - ((haxe.lang.IHxObject) o).__hx_getFields(ret); + public static function fields( o : Dynamic ) : Array + { + if (Std.is(o, IHxObject)) { + var ret:Array = []; + untyped (o : IHxObject).__hx_getFields(ret); return ret; - } else if (o instanceof java.lang.Class) { - return Type.getClassFields( (java.lang.Class) o); + } else if (Std.is(o, java.lang.Class)) { + return Type.getClassFields(cast o); } else { - return new Array(); + return []; } - ') - public static function fields( o : Dynamic ) : Array - { - return null; } - /** - Tells if a value is a function or not. - **/ - @:functionCode(' - return f instanceof haxe.lang.Function; - ') public static function isFunction( f : Dynamic ) : Bool { - return false; + return Std.is(f, Function); } - /** - Generic comparison function, does not work for methods, see [compareMethods] - **/ - @:functionCode(' - return haxe.lang.Runtime.compare(a, b); - ') public static function compare( a : T, b : T ) : Int { - return 0; + return Runtime.compare(a, b); } - /** - Compare two methods closures. Returns true if it's the same method of the same instance. - **/ - @:functionCode(' - if (f1 == f2) - return true; - - if (f1 instanceof haxe.lang.Closure && f2 instanceof haxe.lang.Closure) - { - haxe.lang.Closure f1c = (haxe.lang.Closure) f1; - haxe.lang.Closure f2c = (haxe.lang.Closure) f2; - - return haxe.lang.Runtime.refEq(f1c.obj, f2c.obj) && f1c.field.equals(f2c.field); - } - - - return false; - ') + @:access(java.internal.Closure) public static function compareMethods( f1 : Dynamic, f2 : Dynamic ) : Bool { + if (f1 == f2) { + return true; + } + if (Std.is(f1, Closure) && Std.is(f2, Closure)) { + var f1c:Closure = cast f1; + var f2c:Closure = cast f2; + return Runtime.refEq(f1c.obj, f2c.obj) && f1c.field == f2c.field; + } return false; } - /** - Tells if a value is an object or not. - - **/ - @:functionCode(' - return v != null && !(v instanceof haxe.lang.Enum || v instanceof haxe.lang.Function || v instanceof java.lang.Enum || v instanceof java.lang.Number || v instanceof java.lang.Boolean); - ') public static function isObject( v : Dynamic ) : Bool { - return false; + 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)); } - @:functionCode(' - return v != null && (v instanceof haxe.lang.Enum || v instanceof java.lang.Enum); - ') public static function isEnumValue( v : Dynamic ) : Bool { - return switch(Type.typeof(v)) { - case TEnum(_): true; - case _: false; - } + return v != null && (Std.is(v, HxEnum) || Std.is(v, java.lang.Enum)); } - /** - Delete an object field. - **/ - @:functionCode(' - return (o instanceof haxe.lang.DynamicObject && ((haxe.lang.DynamicObject) o).__hx_deleteField(field)); - ') public static function deleteField( o : Dynamic, field : String ) : Bool { - return false; + return (Std.is(o, DynamicObject) && (o : DynamicObject).__hx_deleteField(field)); } - /** - Make a copy of the fields of an object. - **/ public static function copy( o : T ) : T { var o2 : Dynamic = {}; @@ -248,10 +138,6 @@ import java.Boot; return cast o2; } - /** - 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 { diff --git a/std/java/_std/Std.hx b/std/java/_std/Std.hx index b63d4eea2035c1a6acfda78306c905b08e75570a..b1fff42516245dc90839dc336515ef30bc697ec7 100644 --- a/std/java/_std/Std.hx +++ b/std/java/_std/Std.hx @@ -19,6 +19,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + import java.Boot; import java.Lib; import java.internal.Exceptions; @@ -78,7 +79,7 @@ import java.internal.Exceptions; } } - boolean foundAny = false; + boolean foundAny = i != 0; boolean isNeg = false; for (; i < len; i++) { @@ -90,6 +91,7 @@ import java.internal.Exceptions; case \'-\': isNeg = true; continue; + case \'+\': case \'\\n\': case \'\\t\': case \'\\r\': @@ -133,108 +135,56 @@ import java.internal.Exceptions; return null; } - @:functionCode(' - if (x == null) return java.lang.Double.NaN; - - x = x.trim(); - double ret = 0.0; - double div = 0.0; - double e = 0.0; - - int len = x.length(); - boolean foundAny = false; - boolean isNeg = false; - for (int i = 0; i < len; i++) + public static function parseFloat( x : String ) : Float { + if (x == null) return Math.NaN; + x = StringTools.ltrim(x); + var found = false, hasDot = false, hasSign = false, + hasE = false, hasESign = false, hasEData = false; + var i = -1; + inline function getch(i:Int):Int return cast (untyped x._charAt(i) : java.StdTypes.Char16); + + while (++i < x.length) { - char c = x.charAt(i); - if (!foundAny) + var chr = getch(i); + if (chr >= '0'.code && chr <= '9'.code) { - switch(c) + if (hasE) { - case \'-\': - isNeg = true; - continue; - case \'\\n\': - case \'\\t\': - case \'\\r\': - case \' \': - if (isNeg) return java.lang.Double.NaN; - continue; + hasEData = true; } - } - - if (c == \'.\') { - if (div != 0.0) + 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; - div = 1.0; - - continue; - } - - if (c >= \'0\' && c <= \'9\') - { - if (!foundAny && c == \'0\') - { - foundAny = true; - continue; - } - ret *= 10.0; foundAny = true; div *= 10.0; - - ret += ((int) (c - \'0\')); - } else if (foundAny && c == \'E\' || c == \'e\') { - boolean eNeg = false; - boolean eFoundAny = false; - - char next = x.charAt(i + 1); - if (i + 1 < len) - { - if (next == \'-\') - { - eNeg = true; - i++; - } else if (next == \'+\') { - i++; - } - } - - while (++i < len) - { - c = x.charAt(i); - if (c >= \'0\' && c <= \'9\') - { - if (!eFoundAny && c == \'0\') - continue; - eFoundAny = true; - e *= 10.0; - e += ((int) (c - \'0\')); - } else { - break; - } - } - - if (eNeg) e = -e; - } else { - break; } } + if (hasE && !hasEData) + { + i--; + if (hasESign) + i--; + } - if (div == 0.0) div = 1.0; - - if (foundAny) + if (i != x.length) { - ret = isNeg ? -(ret / div) : (ret / div); - if (e != 0.0) - { - return ret * Math.pow(10.0, e); - } else { - return ret; - } - } else { - return java.lang.Double.NaN; + x = x.substr(0,i); } - ') - public static function parseFloat( x : String ) : Float { - return 0.0; + return try + java.lang.Double.DoubleClass.parseDouble(x) + catch(e:Dynamic) + Math.NaN; + } + + inline public static function instance( value : T, c : Class ) : S { + return Std.is(value, c) ? cast value : null; } public static function random( x : Int ) : Int { diff --git a/std/java/_std/String.hx b/std/java/_std/String.hx index 0884d0e1880a98e6b36047b34761c335845094e4..76a176d9511e112f3d9cb202e2b561101a3f39fb 100644 --- a/std/java/_std/String.hx +++ b/std/java/_std/String.hx @@ -1,59 +1,60 @@ -/* - * Copyright (C)2005-2012 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. - */ - -extern class String implements java.lang.CharSequence { - - var length(default,null) : Int; - - @:overload(function(b:haxe.io.BytesData, offset:Int, length:Int, charsetName:String):Void { }) - @:overload(function(b:haxe.io.BytesData, offset:Int, length:Int):Void { }) - function new(string:String) : Void; - - function toUpperCase() : String; - - function toLowerCase() : String; - - function charAt( index : Int) : String; - - function charCodeAt( index : Int) : Null; - - function indexOf( str : String, ?startIndex : Int ) : Int; - - function lastIndexOf( str : String, ?startIndex : Int ) : Int; - - function split( delimiter : String ) : Array; - - function substr( pos : Int, ?len : Int ) : String; - - function substring( startIndex : Int, ?endIndex : Int ) : String; - - function toString() : String; - - private function compareTo( anotherString : String ) : Int; - - private function codePointAt( idx : Int ) : Int; - - private function getBytes(encoding:String) : haxe.io.BytesData; - - static function fromCharCode( code : Int ) : String; - -} +/* + * Copyright (C)2005-2012 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 extern class String implements java.lang.CharSequence { + + var length(default,null) : Int; + + @:overload(function(b:haxe.io.BytesData, offset:Int, length:Int, charsetName:String):Void { }) + @:overload(function(b:haxe.io.BytesData, offset:Int, length:Int):Void { }) + function new(string:String) : Void; + + function toUpperCase() : String; + + function toLowerCase() : String; + + function charAt( index : Int) : String; + + function charCodeAt( index : Int) : Null; + + function indexOf( str : String, ?startIndex : Int ) : Int; + + function lastIndexOf( str : String, ?startIndex : Int ) : Int; + + function split( delimiter : String ) : Array; + + function substr( pos : Int, ?len : Int ) : String; + + function substring( startIndex : Int, ?endIndex : Int ) : String; + + function toString() : String; + + private function compareTo( anotherString : String ) : Int; + + private function codePointAt( idx : Int ) : Int; + + @:overload(function() : haxe.io.BytesData { }) + private function getBytes(encoding:String) : haxe.io.BytesData; + + static function fromCharCode( code : Int ) : String; + +} diff --git a/std/java/_std/StringBuf.hx b/std/java/_std/StringBuf.hx index bfe7fb4e8e2f0257c0f238900219196fcd711c73..c12851047281b7ba08124fbac1c9c60274ce15d4 100644 --- a/std/java/_std/StringBuf.hx +++ b/std/java/_std/StringBuf.hx @@ -1,55 +1,62 @@ -/* - * Copyright (C)2005-2012 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 function new() : Void { - b = new java.lang.StringBuilder(); - } - - public function add( x : Dynamic ) : Void { - if (Std.is(x, Int)) - { - var x:Int = x; - var xd:Dynamic = x; - b.append(xd); - } else { - b.append(x); - } - } - - 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 untyped { - b.append(cast(c, java.StdTypes.Char16)); - } - - public function toString() : String { - return b.toString(); - } - -} +/* + * Copyright (C)2005-2012 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 (Std.is(x, Int)) + { + var x:Int = cast x; + var xd:Dynamic = x; + b.append(xd); + } else { + b.append(x); + } + } + + 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 untyped { + b.append(cast(c, java.StdTypes.Char16)); + } + + public function toString() : String { + return b.toString(); + } + +} diff --git a/std/java/_std/Sys.hx b/std/java/_std/Sys.hx index 1ea0dc1b89cf4f87cef37d9cdb2238cf8f081334..3e0eba0632703f3a4430dce5746ea784c4b41508 100644 --- a/std/java/_std/Sys.hx +++ b/std/java/_std/Sys.hx @@ -1,254 +1,163 @@ -/* - * Copyright (C)2005-2012 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. - */ -import java.lang.System; -import sys.io.Process; -/* - * Copyright (c) 2005-2012, The haXe Project Contributors - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/** - This class gives you access to many base functionalities of system platforms. Looks in [sys] sub packages for more system APIs. -**/ -@:coreApi class Sys { - private static var _args:java.NativeArray; - private static var _env:haxe.ds.StringMap; - private static var _sysName:String; - - /** - Print any value on the standard output. - **/ - public static inline function print( v : Dynamic ) : Void - { - java.lang.System.out.print(v); - } - - /** - Print any value on the standard output, followed by a newline - **/ - public static inline function println( v : Dynamic ) : Void - { - java.lang.System.out.println(v); - } - - /** - Returns all the arguments that were passed by the commandline. - **/ - public static function args() : Array - { - if (_args == null) - return []; - return java.Lib.array(_args); - } - - /** - Returns the value of the given environment variable. - **/ - public static function getEnv( s : String ) : String - { - return java.lang.System.getenv(s); - } - - /** - Set the value of the given environment variable. - Warning: It is not implemented in Java - **/ - public static function putEnv( s : String, v : String ) : Void - { - //java offers no support for it (!) - throw "Not implemented in this platform"; - } - - /** - Returns the whole environement variables. - **/ - public static function environment() : haxe.ds.StringMap - { - if (_env != null) - return _env; - var _env = _env = new haxe.ds.StringMap(); - for (mv in java.lang.System.getenv().entrySet()) - { - _env.set(mv.getKey(), mv.getValue()); - } - - return _env; - } - - /** - Suspend the current execution for the given time (in seconds). - **/ - public static function sleep( seconds : Float ) : Void - { - try - java.lang.Thread.sleep(cast seconds * 1000) - catch (e:Dynamic) - throw e; - } - - /** - Change the current time locale, which will affect [DateTools.format] date formating. - Returns true if the locale was successfully changed - **/ - public static function setTimeLocale( loc : String ) : Bool - { - return false; - } - - /** - Get the current working directory (usually the one in which the program was started) - **/ - public static function getCwd() : String - { - return new java.io.File(".").getAbsolutePath().substr(0,-1); - } - - /** - Change the current working directory. - **/ - public static function setCwd( s : String ) : Void - { - //java offers no support for it (!) - throw "not implemented"; - } - - /** - Returns the name of the system you are running on. For instance : - "Windows", "Linux", "BSD" and "Mac" depending on your desktop OS. - **/ - public static function systemName() : String - { - if (_sysName != null) return _sysName; - var sname = System.getProperty("os.name").toLowerCase(); - if (sname.indexOf("win") >= 0) - return _sysName = "Windows"; - if (sname.indexOf("mac") >= 0) - return _sysName = "Mac"; - if (sname.indexOf("nux") >= 0) - return _sysName = "Linux"; - if (sname.indexOf("nix") >= 0) - return _sysName = "BSD"; - - return _sysName = System.getProperty("os.name"); - } - - /** - Run the given command with the list of arguments. The command output will be printed on the same output as the current process. - The current process will block until the command terminates and it will return the command result (0 if there was no error). - Read the [sys.io.Process] api for a more complete way to start background processes. - **/ - public static function command( cmd : String, ?args : Array ) : Int - { - var proc:Process = new Process(cmd, args == null ? [] : args); - var ret = proc.exitCode(); - proc.close(); - - return ret; - } - - /** - Exit the current process with the given error code. - **/ - public static function exit( code : Int ) : Void - { - System.exit(code); - } - - /** - Gives the most precise timestamp value (in seconds). - **/ - public static function time() : Float - { - return cast(System.currentTimeMillis(), Float) / 1000; - } - - /** - Gives the most precise timestamp value (in seconds) but only account for the actual time spent running on the CPU for the current thread/process. - **/ - public static function cpuTime() : Float - { - return cast(System.nanoTime(), Float) / 1000000000; - } - - /** - Returns the path to the current executable that we are running. - **/ - public static function executablePath() : String - { - return getCwd(); - } - - /** - Read a single input character from the standard input (without blocking) and returns it. Setting [echo] to true will also display it on the output. - **/ - public static function getChar( echo : Bool ) : Int - { - //TODO - return throw "Not implemented"; - } - - /** - Returns the process standard input, from which you can read what user enters. Usually it will block until the user send a full input line. See [getChar] for an alternative. - **/ - public static function stdin() : haxe.io.Input - { - var _in:java.io.InputStream = Reflect.field(System, "in"); - return new java.io.NativeInput(_in); - } - - /** - Returns the process standard output on which you can write. - **/ - public static function stdout() : haxe.io.Output - { - return new java.io.NativeOutput(System.out); - } - - /** - Returns the process standard error on which you can write. - **/ - public static function stderr() : haxe.io.Output - { - return new java.io.NativeOutput(System.err); - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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. + */ + +import java.lang.System; +import sys.io.Process; +using haxe.Int64; + +@:coreApi class Sys { + private static var _args:java.NativeArray; + private static var _env:haxe.ds.StringMap; + private static var _sysName:String; + + public static inline function print( v : Dynamic ) : Void + { + java.lang.System.out.print(v); + } + + public static inline function println( v : Dynamic ) : Void + { + java.lang.System.out.println(v); + } + + public static function args() : Array + { + if (_args == null) + return []; + return java.Lib.array(_args); + } + + public static function getEnv( s : String ) : String + { + return java.lang.System.getenv(s); + } + + public static function putEnv( s : String, v : String ) : Void + { + //java offers no support for it (!) + throw "Not implemented in this platform"; + } + + public static function environment() : Map + { + if (_env != null) + return _env; + var _env = _env = new haxe.ds.StringMap(); + for (mv in java.lang.System.getenv().entrySet()) + { + _env.set(mv.getKey(), mv.getValue()); + } + + return _env; + } + + public static function sleep( seconds : Float ) : Void + { + try + java.lang.Thread.sleep(cast seconds * 1000) + catch (e:Dynamic) + throw e; + } + + public static function setTimeLocale( loc : String ) : Bool + { + return false; + } + + public static function getCwd() : String + { + return new java.io.File(".").getAbsolutePath().substr(0,-1); + } + + public static function setCwd( s : String ) : Void + { + //java offers no support for it (!) + throw "not implemented"; + } + + public static function systemName() : String + { + if (_sysName != null) return _sysName; + var sname = System.getProperty("os.name").toLowerCase(); + if (sname.indexOf("win") >= 0) + return _sysName = "Windows"; + if (sname.indexOf("mac") >= 0) + return _sysName = "Mac"; + if (sname.indexOf("nux") >= 0) + return _sysName = "Linux"; + if (sname.indexOf("nix") >= 0) + return _sysName = "BSD"; + + return _sysName = System.getProperty("os.name"); + } + + public static function command( cmd : String, ?args : Array ) : Int + { + var proc:Process = new Process(cmd, args == null ? [] : args); + var ret = proc.exitCode(); + proc.close(); + + return ret; + } + + public static function exit( code : Int ) : Void + { + System.exit(code); + } + + public static function time() : Float + { + return cast(System.currentTimeMillis().div(Int64.ofInt(1000)), Float); + } + + public static function cpuTime() : Float + { + return cast(System.nanoTime(), Float) / 1000000000; + } + + public static function executablePath() : String + { + return getCwd(); + } + + public static function getChar( echo : Bool ) : Int + { + //TODO + return throw "Not implemented"; + } + + public static function stdin() : haxe.io.Input + { + var _in:java.io.InputStream = Reflect.field(System, "in"); + return new java.io.NativeInput(_in); + } + + public static function stdout() : haxe.io.Output + { + return new java.io.NativeOutput(System.out); + } + + public static function stderr() : haxe.io.Output + { + return new java.io.NativeOutput(System.err); + } +} diff --git a/std/java/_std/Type.hx b/std/java/_std/Type.hx index 458be2ae0ed88754ccc5ffa1e5b4030c8e015b1d..e077e2cff3ec211959943be1bcabfd3c21f31049 100644 --- a/std/java/_std/Type.hx +++ b/std/java/_std/Type.hx @@ -1,430 +1,433 @@ -/* - * Copyright (C)2005-2012 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. - */ -@:keep enum ValueType { - TNull; - TInt; - TFloat; - TBool; - TObject; - TFunction; - TClass( c : Class ); - TEnum( e : Enum ); - TUnknown; -} - -@:keep @:coreApi class Type { - - @:functionCode(' - if (o == null || o instanceof haxe.lang.DynamicObject || o instanceof java.lang.Class) - return null; - - return (java.lang.Class) o.getClass(); - ') - public static function getClass( o : T ) : Class untyped - { - return null; - } - - @:functionCode(' - if (o instanceof java.lang.Enum || o instanceof haxe.lang.Enum) - return o.getClass(); - return null; - ') - public static function getEnum( o : EnumValue ) : Enum untyped - { - return null; - } - - @:functionCode(' - java.lang.Class cl = (c == null) ? null : c.getSuperclass(); - if (cl != null && !cl.getName().equals("haxe.lang.HxObject") && !cl.getName().equals("java.lang.Object") ) - return cl; - return null; - ') - public static function getSuperClass( c : Class ) : Class untyped - { - return null; - } - - public static function getClassName( c : Class ) : String untyped { - var c : java.lang.Class = c; - var name:String = c.getName(); - if (name.startsWith("haxe.root.")) - return name.substr(10); - if (name.startsWith("java.lang")) - name = name.substr(10); - - return switch(name) - { - case "int", "Integer": "Int"; - case "double", "Double": "Float"; - case "Object": "Dynamic"; - default: name; - } - } - - public static function getEnumName( e : Enum ) : String untyped { - var c : java.lang.Class = e; - var ret:String = c.getName(); - if (ret.startsWith("haxe.root.")) - return ret.substr(10); - else if (ret == "boolean" || ret == "java.lang.Boolean") - return "Bool"; - - return ret; - } - - @:functionCode(' - try { - if (name.indexOf(".") == -1) - name = "haxe.root." + name; - return java.lang.Class.forName(name); - } - catch (java.lang.ClassNotFoundException e) - { - if (name.equals("haxe.root.Int")) return int.class; - else if (name.equals("haxe.root.Float")) return double.class; - else if (name.equals("haxe.root.String")) return java.lang.String.class; - else if (name.equals("haxe.root.Math")) return java.lang.Math.class; - else if (name.equals("haxe.root.Class")) return java.lang.Class.class; - else if (name.equals("haxe.root.Dynamic")) return java.lang.Object.class; - return null; - } - ') - public static function resolveClass( name : String ) : Class untyped - { - return null; - } - - - @:functionCode(' - if ("Bool".equals(name)) return boolean.class; - Class r = resolveClass(name); - if (r != null && (r.getSuperclass() == java.lang.Enum.class || r.getSuperclass() == haxe.lang.Enum.class)) - return r; - return null; - ') - public static function resolveEnum( name : String ) : Enum untyped - { - if (name == "Bool") return Bool; - return resolveClass(name); - } - - @:functionCode(' - int len = args.length; - java.lang.Class[] cls = new java.lang.Class[len]; - java.lang.Object[] objs = new java.lang.Object[len]; - - java.lang.reflect.Constructor[] ms = cl.getConstructors(); - int msl = ms.length; - int realMsl = 0; - for(int i =0; i < msl; i++) - { - if (!ms[i].isVarArgs() && ms[i].getParameterTypes().length != len) - { - ms[i] = null; - } else { - ms[realMsl] = ms[i]; - if (realMsl != i) - ms[i] = null; - realMsl++; - } - } - - boolean hasNumber = false; - - for (int i = 0; i < len; i++) - { - Object o = args.__get(i); - objs[i]= o; - cls[i] = o.getClass(); - boolean isNum = false; - - if (o instanceof java.lang.Number) - { - cls[i] = java.lang.Number.class; - isNum = hasNumber = true; - } - - msl = realMsl; - realMsl = 0; - - for (int j = 0; j < msl; j++) - { - java.lang.Class[] allcls = ms[j].getParameterTypes(); - if (i < allcls.length) - { - if (! ((isNum && allcls[i].isPrimitive()) || allcls[i].isAssignableFrom(cls[i])) ) - { - ms[j] = null; - } else { - ms[realMsl] = ms[j]; - if (realMsl != j) - ms[j] = null; - realMsl++; - } - } - } - - } - - java.lang.reflect.Constructor found = ms[0]; - - if (hasNumber) - { - java.lang.Class[] allcls = found.getParameterTypes(); - - for (int i = 0; i < len; i++) - { - java.lang.Object o = objs[i]; - if (o instanceof java.lang.Number) - { - java.lang.Class curCls = null; - if (i < allcls.length) - { - curCls = allcls[i]; - if (!curCls.isAssignableFrom(o.getClass())) - { - String name = curCls.getName(); - if (name.equals("double") || name.equals("java.lang.Double")) - { - objs[i] = ((java.lang.Number)o).doubleValue(); - } else if (name.equals("int") || name.equals("java.lang.Integer")) - { - objs[i] = ((java.lang.Number)o).intValue(); - } else if (name.equals("float") || name.equals("java.lang.Float")) - { - objs[i] = ((java.lang.Number)o).floatValue(); - } else if (name.equals("byte") || name.equals("java.lang.Byte")) - { - objs[i] = ((java.lang.Number)o).byteValue(); - } else if (name.equals("short") || name.equals("java.lang.Short")) - { - objs[i] = ((java.lang.Number)o).shortValue(); - } - } - } //else varargs not handled TODO - } - } - } - - try { - found.setAccessible(true); - return (T) found.newInstance(objs); - } - catch (java.lang.reflect.InvocationTargetException e) - { - throw haxe.lang.HaxeException.wrap(e.getCause()); - } - - catch (Throwable t) - { - throw haxe.lang.HaxeException.wrap(t); - } - ') - public static function createInstance( cl : Class, args : Array ) : T untyped - { - return null; - } - - public static function createEmptyInstance( cl : Class ) : T untyped - { - if (Reflect.hasField(cl, "__hx_createEmpty")) - return cl.__hx_createEmpty(); - return createInstance(cl, []); - } - - @:functionCode(' - if (params == null || params.length == 0) - { - java.lang.Object ret = haxe.lang.Runtime.slowGetField(e, constr, true); - if (ret instanceof haxe.lang.Function) - throw haxe.lang.HaxeException.wrap("Constructor " + constr + " needs parameters"); - return (T) ret; - } else { - return (T) haxe.lang.Runtime.slowCallField(e, constr, params); - } - ') - public static function createEnum( e : Enum, constr : String, ?params : Array ) : T - { - return null; - } - - public static function createEnumIndex( e : Enum, index : Int, ?params : Array ) : T { - var constr = getEnumConstructs(e); - return createEnum(e, constr[index], params); - } - - @:functionCode(' - if (c == java.lang.String.class) - { - return haxe.lang.StringRefl.fields; - } - - Array ret = new Array(); - for (java.lang.reflect.Field f : c.getFields()) - { - java.lang.String fname = f.getName(); - if (!java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_")) - ret.push(fname); - } - - for (java.lang.reflect.Method m : c.getMethods()) - { - if (m.getDeclaringClass() == java.lang.Object.class) - continue; - java.lang.String mname = m.getName(); - if (!java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_")) - ret.push(mname); - } - - return ret; - ') - public static function getInstanceFields( c : Class ) : Array { - return null; - } - - @:functionCode(' - Array ret = new Array(); - if (c == java.lang.String.class) - { - ret.push("fromCharCode"); - return ret; - } - - for (java.lang.reflect.Field f : c.getDeclaredFields()) - { - java.lang.String fname = f.getName(); - if (java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_")) - ret.push(fname); - } - - for (java.lang.reflect.Method m : c.getDeclaredMethods()) - { - if (m.getDeclaringClass() == java.lang.Object.class) - continue; - java.lang.String mname = m.getName(); - if (java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_")) - ret.push(mname); - } - - return ret; - ') - public static function getClassFields( c : Class ) : Array { - return null; - } - - public static function getEnumConstructs( e : Enum ) : Array { - if (Reflect.hasField(e, "constructs")) - return untyped e.constructs.copy(); - return getClassFields(cast e); - } - - @:functionCode(' - if (v == null) return ValueType.TNull; - - if (v instanceof haxe.lang.IHxObject) { - haxe.lang.IHxObject vobj = (haxe.lang.IHxObject) v; - java.lang.Class cl = vobj.getClass(); - if (v instanceof haxe.lang.DynamicObject) - return ValueType.TObject; - else - return ValueType.TClass(cl); - } else if (v instanceof java.lang.Number) { - java.lang.Number n = (java.lang.Number) v; - if (n.intValue() == n.doubleValue()) - return ValueType.TInt; - else - return ValueType.TFloat; - } else if (v instanceof haxe.lang.Function) { - return ValueType.TFunction; - } else if (v instanceof java.lang.Enum || v instanceof haxe.lang.Enum) { - return ValueType.TEnum(v.getClass()); - } else if (v instanceof java.lang.Boolean) { - return ValueType.TBool; - } else if (v instanceof java.lang.Class) { - return ValueType.TObject; - } else { - return ValueType.TClass(v.getClass()); - } - ') - public static function typeof( v : Dynamic ) : ValueType untyped - { - return null; - } - - @:functionCode(' - if (a instanceof haxe.lang.Enum) - return a.equals(b); - else - return haxe.lang.Runtime.eq(a, b); - ') - public static function enumEq( a : T, b : T ) : Bool untyped - { - return a == b; - } - - @:functionCode(' - if (e instanceof java.lang.Enum) - return ((java.lang.Enum) e).name(); - else - return ((haxe.lang.Enum) e).getTag(); - ') - public static function enumConstructor( e : EnumValue ) : String untyped - { - return null; - } - - @:functionCode(' - return ( e instanceof java.lang.Enum ) ? new haxe.root.Array() : ((haxe.lang.Enum) e).params; - ') - public static function enumParameters( e : EnumValue ) : Array untyped - { - return null; - } - - @:functionCode(' - if (e instanceof java.lang.Enum) - return ((java.lang.Enum) e).ordinal(); - else - return ((haxe.lang.Enum) e).index; - ') - public static function enumIndex( e : EnumValue ) : Int untyped - { - return e.index; - } - - public static function allEnums( e : Enum ) : Array - { - var ctors = getEnumConstructs(e); - var ret = []; - for (ctor in ctors) - { - var v = Reflect.field(e, ctor); - if (Std.is(v, e)) - ret.push(v); - } - - return ret; - } - -} +/* + * Copyright (C)2005-2012 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. + */ + +import java.internal.HxObject; + +using StringTools; + +@:keep enum ValueType { + TNull; + TInt; + TFloat; + TBool; + TObject; + TFunction; + TClass( c : Class ); + TEnum( e : Enum ); + TUnknown; +} + +@:keep @:coreApi class Type { + + public static function getClass( o : T ) : Class + { + if (o == null || Std.is(o, DynamicObject) || Std.is(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)) { + return untyped o.getClass(); + } + return null; + } + + public static function getSuperClass( c : Class ) : Class + { + var c = java.Lib.toNativeType(c); + var cl:java.lang.Class = c == null ? null : untyped c.getSuperclass(); + if (cl != null && cl.getName() != "haxe.lang.HxObject" && cl.getName() != "java.lang.Object") { + return cast cl; + } + return null; + } + + public static function getClassName( c : Class ) : String { + var c : java.lang.Class = cast c; + var name:String = c.getName(); + if (name.startsWith("haxe.root.")) + return name.substr(10); + if (name.startsWith("java.lang")) + name = name.substr(10); + + return switch(name) + { + case "int", "Integer": "Int"; + case "double", "Double": "Float"; + case "Object": "Dynamic"; + default: name; + } + } + + public static function getEnumName( e : Enum ) : String { + var c : java.lang.Class = cast e; + var ret:String = c.getName(); + if (ret.startsWith("haxe.root.")) + return ret.substr(10); + else if (ret == "boolean" || ret == "java.lang.Boolean") + return "Bool"; + + return ret; + } + + public static function resolveClass( name : String ) : Class + { + try { + if (name.indexOf(".") == -1) { + name = "haxe.root." +name; + } + return cast java.lang.Class.forName(name); + } catch (e:java.lang.ClassNotFoundException) { + return untyped switch (name) { + case "haxe.root.Int": Int; + case "haxe.root.Float": Float; + case "haxe.root.String": String; + case "haxe.root.Math": java.lang.Math; + case "haxe.root.Class": java.lang.Class; + case "haxe.root.Dynamic": java.lang.Object; + case _: null; + } + } + } + + + @:functionCode(' + if ("Bool".equals(name)) return boolean.class; + Class r = resolveClass(name); + if (r != null && (r.getSuperclass() == java.lang.Enum.class || haxe.lang.Enum.class.isAssignableFrom(r))) + return r; + return null; + ') + public static function resolveEnum( name : String ) : Enum untyped + { + if (name == "Bool") return Bool; + return resolveClass(name); + } + + @:functionCode(' + int len = args.length; + java.lang.Class[] cls = new java.lang.Class[len]; + java.lang.Object[] objs = new java.lang.Object[len]; + + java.lang.reflect.Constructor[] ms = cl.getConstructors(); + int msl = ms.length; + int realMsl = 0; + for(int i =0; i < msl; i++) + { + if (!ms[i].isVarArgs() && ms[i].getParameterTypes().length != len) + { + ms[i] = null; + } else { + ms[realMsl] = ms[i]; + if (realMsl != i) + ms[i] = null; + realMsl++; + } + } + + boolean hasNumber = false; + + for (int i = 0; i < len; i++) + { + Object o = args.__get(i); + objs[i]= o; + cls[i] = o.getClass(); + boolean isNum = false; + + if (o instanceof java.lang.Number) + { + cls[i] = java.lang.Number.class; + isNum = hasNumber = true; + } + + msl = realMsl; + realMsl = 0; + + for (int j = 0; j < msl; j++) + { + java.lang.Class[] allcls = ms[j].getParameterTypes(); + if (i < allcls.length) + { + if (! ((isNum && allcls[i].isPrimitive()) || allcls[i].isAssignableFrom(cls[i])) ) + { + ms[j] = null; + } else { + ms[realMsl] = ms[j]; + if (realMsl != j) + ms[j] = null; + realMsl++; + } + } + } + + } + + java.lang.reflect.Constructor found = ms[0]; + + if (hasNumber) + { + java.lang.Class[] allcls = found.getParameterTypes(); + + for (int i = 0; i < len; i++) + { + java.lang.Object o = objs[i]; + if (o instanceof java.lang.Number) + { + java.lang.Class curCls = null; + if (i < allcls.length) + { + curCls = allcls[i]; + if (!curCls.isAssignableFrom(o.getClass())) + { + String name = curCls.getName(); + if (name.equals("double") || name.equals("java.lang.Double")) + { + objs[i] = ((java.lang.Number)o).doubleValue(); + } else if (name.equals("int") || name.equals("java.lang.Integer")) + { + objs[i] = ((java.lang.Number)o).intValue(); + } else if (name.equals("float") || name.equals("java.lang.Float")) + { + objs[i] = ((java.lang.Number)o).floatValue(); + } else if (name.equals("byte") || name.equals("java.lang.Byte")) + { + objs[i] = ((java.lang.Number)o).byteValue(); + } else if (name.equals("short") || name.equals("java.lang.Short")) + { + objs[i] = ((java.lang.Number)o).shortValue(); + } + } + } //else varargs not handled TODO + } + } + } + + try { + found.setAccessible(true); + return (T) found.newInstance(objs); + } + catch (java.lang.reflect.InvocationTargetException e) + { + throw haxe.lang.HaxeException.wrap(e.getCause()); + } + + catch (Throwable t) + { + throw haxe.lang.HaxeException.wrap(t); + } + ') + public static function createInstance( cl : Class, args : Array ) : T untyped + { + return null; + } + + public static function createEmptyInstance( cl : Class ) : T untyped + { + if (Reflect.hasField(cl, "__hx_createEmpty")) + return cl.__hx_createEmpty(); + return createInstance(cl, []); + } + + @:functionCode(' + if (params == null || params.length == 0) + { + java.lang.Object ret = haxe.lang.Runtime.slowGetField(e, constr, true); + if (ret instanceof haxe.lang.Function) + throw haxe.lang.HaxeException.wrap("Constructor " + constr + " needs parameters"); + return (T) ret; + } else { + return (T) haxe.lang.Runtime.slowCallField(e, constr, params); + } + ') + public static function createEnum( e : Enum, constr : String, ?params : Array ) : T + { + return null; + } + + public static function createEnumIndex( e : Enum, index : Int, ?params : Array ) : T { + var constr = getEnumConstructs(e); + return createEnum(e, constr[index], params); + } + + @:functionCode(' + if (c == java.lang.String.class) + { + return haxe.lang.StringRefl.fields; + } + + Array ret = new Array(); + for (java.lang.reflect.Field f : c.getFields()) + { + java.lang.String fname = f.getName(); + if (!java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_")) + ret.push(fname); + } + + for (java.lang.reflect.Method m : c.getMethods()) + { + if (m.getDeclaringClass() == java.lang.Object.class) + continue; + java.lang.String mname = m.getName(); + if (!java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_")) + ret.push(mname); + } + + return ret; + ') + public static function getInstanceFields( c : Class ) : Array { + return null; + } + + @:functionCode(' + Array ret = new Array(); + if (c == java.lang.String.class) + { + ret.push("fromCharCode"); + return ret; + } + + for (java.lang.reflect.Field f : c.getDeclaredFields()) + { + java.lang.String fname = f.getName(); + if (java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !fname.startsWith("__hx_")) + ret.push(fname); + } + + for (java.lang.reflect.Method m : c.getDeclaredMethods()) + { + if (m.getDeclaringClass() == java.lang.Object.class) + continue; + java.lang.String mname = m.getName(); + if (java.lang.reflect.Modifier.isStatic(m.getModifiers()) && !mname.startsWith("__hx_")) + ret.push(mname); + } + + return ret; + ') + public static function getClassFields( c : Class ) : Array { + return null; + } + + public static function getEnumConstructs( e : Enum ) : Array { + if (Reflect.hasField(e, "__hx_constructs")) + { + var ret:Array = java.Lib.array(untyped e.__hx_constructs); + return ret.copy(); + } + var vals:java.NativeArray> = untyped e.values(), ret = []; + for (i in 0...vals.length) + ret[i] = vals[i].name(); + return ret; + } + + @:functionCode(' + if (v == null) return ValueType.TNull; + + if (v instanceof haxe.lang.IHxObject) { + haxe.lang.IHxObject vobj = (haxe.lang.IHxObject) v; + java.lang.Class cl = vobj.getClass(); + if (v instanceof haxe.lang.DynamicObject) + return ValueType.TObject; + else + return ValueType.TClass(cl); + } else if (v instanceof java.lang.Number) { + java.lang.Number n = (java.lang.Number) v; + if (n.intValue() == n.doubleValue()) + return ValueType.TInt; + else + return ValueType.TFloat; + } else if (v instanceof haxe.lang.Function) { + return ValueType.TFunction; + } else if (v instanceof java.lang.Enum || v instanceof haxe.lang.Enum) { + return ValueType.TEnum(v.getClass()); + } else if (v instanceof java.lang.Boolean) { + return ValueType.TBool; + } else if (v instanceof java.lang.Class) { + return ValueType.TObject; + } else { + return ValueType.TClass(v.getClass()); + } + ') + public static function typeof( v : Dynamic ) : ValueType untyped + { + return null; + } + + @:functionCode(' + if (a instanceof haxe.lang.Enum) + return a.equals(b); + else + return haxe.lang.Runtime.eq(a, b); + ') + public static function enumEq( a : T, b : T ) : Bool untyped + { + return a == b; + } + + @:functionCode(' + if (e instanceof java.lang.Enum) + return ((java.lang.Enum) e).name(); + else + return ((haxe.lang.Enum) e).getTag(); + ') + public static function enumConstructor( e : EnumValue ) : String untyped + { + return null; + } + + @:functionCode(' + return ( e instanceof java.lang.Enum ) ? new haxe.root.Array() : ((haxe.lang.Enum) e).getParams(); + ') + public static function enumParameters( e : EnumValue ) : Array untyped + { + return null; + } + + @:functionCode(' + if (e instanceof java.lang.Enum) + return ((java.lang.Enum) e).ordinal(); + else + return ((haxe.lang.Enum) e).index; + ') + public static function enumIndex( e : EnumValue ) : Int untyped + { + return e.index; + } + + public static function allEnums( e : Enum ) : Array + { + var ctors = getEnumConstructs(e); + var ret = []; + for (ctor in ctors) + { + var v = Reflect.field(e, ctor); + if (Std.is(v, e)) + ret.push(v); + } + + return ret; + } + +} diff --git a/std/java/_std/Xml.hx b/std/java/_std/Xml.hx deleted file mode 100644 index 9e512f6df25dcfa5ce55fa84d1ce13deeafba1bf..0000000000000000000000000000000000000000 --- a/std/java/_std/Xml.hx +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -@:native("_Xml.RealXmlType") -extern enum XmlType { -} - -private enum RealXmlType { - Element; - PCData; - CData; - Comment; - DocType; - ProcessingInstruction; - Document; -} - -@:coreApi class Xml { - - public static var Element(default,null) : XmlType; - public static var PCData(default,null) : XmlType; - public static var CData(default,null) : XmlType; - public static var Comment(default,null) : XmlType; - public static var DocType(default,null) : XmlType; - public static var ProcessingInstruction(default,null) : XmlType; - public static var Document(default,null) : XmlType; - - public var nodeType(default,null) : XmlType; - public var nodeName(get,set) : String; - public var nodeValue(get,set) : String; - public var parent(get,null) : Xml; - - var _nodeName : String; - var _nodeValue : String; - var _attributes : haxe.ds.StringMap; - var _children : Array; - var _parent : Xml; - - public static function parse( str : String ) : Xml { - return haxe.xml.Parser.parse(str); - } - - private function new() : Void { - } - - public static function createElement( name : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Element; - r._children = new Array(); - r._attributes = new haxe.ds.StringMap(); - r.set_nodeName( name ); - return r; - } - - public static function createPCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.PCData; - r.set_nodeValue( data ); - return r; - } - - public static function createCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.CData; - r.set_nodeValue( data ); - return r; - } - - public static function createComment( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Comment; - r.set_nodeValue( data ); - return r; - } - - public static function createDocType( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.DocType; - r.set_nodeValue( data ); - return r; - } - - public static function createProcessingInstruction( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.ProcessingInstruction; - r.set_nodeValue( data ); - return r; - } - - public static function createDocument() : Xml { - var r = new Xml(); - r.nodeType = Xml.Document; - r._children = new Array(); - return r; - } - - private function get_nodeName() : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName; - } - - private function set_nodeName( n : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName = n; - } - - private function get_nodeValue() : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue; - } - - private function set_nodeValue( v : String ) : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue = v; - } - - private function get_parent() : Xml { - return _parent; - } - - public function get( att : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.get( att ); - } - - public function set( att : String, value : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.set( att, value ); - } - - public function remove( att : String ) : Void{ - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.remove( att ); - } - - public function exists( att : String ) : Bool { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.exists( att ); - } - - public function attributes() : Iterator { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.keys(); - } - - public function iterator() : Iterator { - if ( _children == null ) throw "bad nodetype"; - var cur = 0; - var x = this._children; - return { - hasNext : function(){ - return cur < x.length; - }, - next : function(){ - return x[cur++]; - } - } - } - - public function elements() : Iterator { - if ( _children == null ) throw "bad nodetype"; - var cur = 0; - var x = _children; - return untyped { - hasNext : function() { - var k = cur; - var l = x.length; - while( k < l ) { - if( x[k].nodeType == Xml.Element ) - break; - k += 1; - } - cur = k; - return k < l; - }, - next : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - k += 1; - if( n.nodeType == Xml.Element ) { - cur = k; - return n; - } - } - return null; - } - } - } - - public function elementsNamed( name : String ) : Iterator { - if ( _children == null ) throw "bad nodetype"; - var x = _children; - var cur = 0; - return untyped { - cur: 0, - x: this._children, - hasNext : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - if( n.nodeType == Xml.Element && n._nodeName == name ) - break; - k++; - } - cur = k; - return k < l; - }, - next : function() { - var k = cur; - var l = x.length; - while( k < l ) { - var n = x[k]; - k++; - if( n.nodeType == Xml.Element && n._nodeName == name ) { - cur = k; - return n; - } - } - return null; - } - } - } - - public function firstChild() : Xml { - if( _children == null ) throw "bad nodetype"; - return _children[0]; - } - - public function firstElement() : Xml { - if( _children == null ) throw "bad nodetype"; - var cur = 0; - var l = _children.length; - while( cur < l ) { - var n = _children[cur]; - if( n.nodeType == Xml.Element ) - return n; - cur++; - } - return null; - } - - public function addChild( x : Xml ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.push( x ); - } - - public function removeChild( x : Xml ) : Bool { - if( _children == null ) throw "bad nodetype"; - var b = _children.remove( x ); - if( b ) - x._parent = null; - return b; - } - - public function insertChild( x : Xml, pos : Int ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.insert( pos, x ); - } - - public function toString() : String { - if( nodeType == Xml.PCData ) - return StringTools.htmlEscape(_nodeValue); - if( nodeType == Xml.CData ) - return ""; - if( nodeType == Xml.Comment ) - return ""; - if( nodeType == Xml.DocType ) - return ""; - if( nodeType == Xml.ProcessingInstruction ) - return ""; - var s = new StringBuf(); - - if( nodeType == Xml.Element ) { - s.add("<"); - s.add(_nodeName); - for( k in _attributes.keys() ){ - s.add(" "); - s.add(k); - s.add("=\""); - s.add(_attributes.get(k)); - s.add("\""); - } - if( _children.length == 0 ) { - s.add("/>"); - return s.toString(); - } - s.add(">"); - } - - for( x in iterator() ) - s.add(x.toString()); - - if( nodeType == Xml.Element ) { - s.add(""); - } - return s.toString(); - } - - static function __init__() : Void untyped { - Xml.Element = cast RealXmlType.Element; - Xml.PCData = cast RealXmlType.PCData; - Xml.CData = cast RealXmlType.CData; - Xml.Comment = cast RealXmlType.Comment; - Xml.DocType = cast RealXmlType.DocType; - Xml.ProcessingInstruction = cast RealXmlType.ProcessingInstruction; - Xml.Document = cast RealXmlType.Document; - } - -} diff --git a/std/java/_std/haxe/Int64.hx b/std/java/_std/haxe/Int64.hx index 5d902c4e0794acfb2671b53bd464b439592cbe03..602c26eb2769c98f3c3e8585d94841964c61dcc7 100644 --- a/std/java/_std/haxe/Int64.hx +++ b/std/java/_std/haxe/Int64.hx @@ -1,148 +1,218 @@ -/* - * Copyright (C)2005-2012 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; -using haxe.Int64; -private typedef NativeInt64 = Int; - -@:coreApi -@:nativeGen class Int64 -{ - @:extern private static inline function asNative(i:Int64):NativeInt64 return untyped i; - @:extern private static inline function ofNative(i:NativeInt64):Int64 return untyped i; - @:extern private static inline function mkNative(i:Dynamic):NativeInt64 return i; - - public static inline function make( high : Int, low : Int ) : Int64 - { - return ((cast(high, NativeInt64) << 32 ) | (low & untyped __java__('0xffffffffL'))).ofNative(); - } - - public static inline function getLow( x : Int64 ) : Int - { - return cast (x.asNative() & untyped __java__("0xFFFFFFFFL")); - } - - public static inline function getHigh( x : Int64 ) : Int - { - return cast(cast(x,NativeInt64) >>> cast(32,NativeInt64), Int); - } - - public static inline function ofInt( x : Int ) : Int64 { - return cast x; - } - - public static inline function toInt( x : Int64 ) : Int - { - return cast x; - } - - public static inline function add( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() + b.asNative()).ofNative(); - } - - public static inline function sub( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() - b.asNative()).ofNative(); - } - - public static inline function mul( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() * b.asNative()).ofNative(); - } - - static function divMod( modulus : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } - { - var q:Int64 = (modulus.asNative() / divisor.asNative()).mkNative().ofNative(); - var m:Int64 = (modulus.asNative() % divisor.asNative()).mkNative().ofNative(); - return { quotient : q, modulus : m }; - } - - public static inline function div( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() / b.asNative()).mkNative().ofNative(); - } - - public static inline function mod( a : Int64, b : Int64 ) : Int64 { - return (a.asNative() % b.asNative()).mkNative().ofNative(); - } - - public static inline function shl( a : Int64, b : Int ) : Int64 { - return (a.asNative() << b).ofNative(); - } - - public static inline function shr( a : Int64, b : Int ) : Int64 { - return (a.asNative() >> b).ofNative(); - } - - public static inline function ushr( a : Int64, b : Int ) : Int64 { - return (a.asNative() >>> b).ofNative(); - } - - public static inline function and( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() & b.asNative()).ofNative(); - } - - public static inline function or( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() | b.asNative()).ofNative(); - } - - public static inline function xor( a : Int64, b : Int64 ) : Int64 - { - return (a.asNative() ^ b.asNative()).ofNative(); - } - - public static inline function neg( a : Int64 ) : Int64 - { - return (~a.asNative()).ofNative(); - } - - public static inline function isNeg( a : Int64 ) : Bool - { - return (a.asNative() < 0.mkNative()); - } - - public static inline function isZero( a : Int64 ) : Bool - { - return (a.asNative() == 0.mkNative()); - } - - public static inline function compare( a : Int64, b : Int64 ) : Int - { - return cast(a.asNative() - b.asNative(), Int); - } - - /** - Compare two Int64 in unsigned mode. - **/ - public static function ucompare( a : Int64, b : Int64 ) : Int - { - if (a.asNative() < 0.mkNative()) - return (b.asNative() < 0.mkNative()) ? compare( (~a.asNative()).ofNative(), (~b.asNative()).ofNative()) : 1; - return (b.asNative() < 0.mkNative()) ? -1 : compare(a, b); - } - - public static inline function toStr( a : Int64 ) : String { - return a + ""; - } -} - - +/* + * Copyright (C)2005-2012 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; +using haxe.Int64; + +private typedef __Int64 = java.StdTypes.Int64; + +@:coreApi +abstract Int64(__Int64) from __Int64 to __Int64 +{ + + public static inline function make( high : Int32, low : Int32 ) : Int64 + return new Int64( (cast(high, __Int64) << 32) | (cast(low, __Int64)& untyped __java__('0xffffffffL')) ); + + private inline function new(x : __Int64) + this = x; + + private var val( get, set ) : __Int64; + inline function get_val() : __Int64 return this; + inline function set_val( x : __Int64 ) : __Int64 return this = x; + + public var high( get, never ):Int32; + public inline function get_high():Int32 return cast(this >> 32); + + public var low( get, never ):Int32; + public inline function get_low():Int32 return cast this; + + public inline function copy():Int64 + return new Int64( this ); + + @:from public static inline function ofInt( x : Int ) : Int64 + return cast x; + + inline public static function is( val : Dynamic ) : Bool + return Std.is(val,java.lang.Long.LongClass); + + public static inline function toInt( x : Int64 ) : Int { + if( x.val < 0x80000000 || x.val > 0x7FFFFFFF ) + throw "Overflow"; + return cast x.val; + } + + public static inline function getHigh( x : Int64 ) : Int32 + return cast( x.val >> 32 ); + + public static inline function getLow( x : Int64 ) : Int32 + return cast( x.val ); + + public static inline function isNeg( x : Int64 ) : Bool + return x.val < 0; + + public static inline function isZero( x : Int64 ) : Bool + return x.val == 0; + + public static inline function compare( a : Int64, b : Int64 ) : Int + { + if( a.val < b.val ) return -1; + if( a.val > b.val ) return 1; + return 0; + } + + public static inline function ucompare( a : Int64, b : Int64 ) : Int { + if( a.val < 0 ) + return ( b.val < 0 ) ? compare( a, b ) : 1; + return ( b.val < 0 ) ? -1 : compare( a, b ); + } + + public static inline function toStr( x : Int64 ) : String + return '${x.val}'; + + public static inline function divMod( dividend : Int64, divisor : Int64 ) : { quotient : Int64, modulus : Int64 } + return { quotient: dividend / divisor, modulus: dividend % divisor }; + + private inline function toString() : String + return '$this'; + + @:op(-A) public static function neg( x : Int64 ) : Int64 + return -x.val; + + @:op(++A) private inline function preIncrement() : Int64 + return ++this; + + @:op(A++) private inline function postIncrement() : Int64 + return this++; + + @:op(--A) private inline function preDecrement() : Int64 + return --this; + + @:op(A--) private inline function postDecrement() : Int64 + return this--; + + @:op(A + B) public static inline function add( a : Int64, b : Int64 ) : Int64 + return a.val + b.val; + + @:op(A + B) @:commutative private static inline function addInt( a : Int64, b : Int ) : Int64 + return a.val + b; + + @:op(A - B) public static inline function sub( a : Int64, b : Int64 ) : Int64 + return a.val - b.val; + + @:op(A - B) private static inline function subInt( a : Int64, b : Int ) : Int64 + return a.val - b; + + @:op(A - B) private static inline function intSub( a : Int, b : Int64 ) : Int64 + return a - b.val; + + @:op(A * B) public static inline function mul( a : Int64, b : Int64 ) : Int64 + return a.val * b.val; + + @:op(A * B) @:commutative private static inline function mulInt( a : Int64, b : Int ) : Int64 + return a.val * b; + + @:op(A / B) public static inline function div( a : Int64, b : Int64 ) : Int64 + return a.val / b.val; + + @:op(A / B) private static inline function divInt( a : Int64, b : Int ) : Int64 + return a.val / b; + + @:op(A / B) private static inline function intDiv( a : Int, b : Int64 ) : Int64 + return a / b.val; + + @:op(A % B) public static inline function mod( a : Int64, b : Int64 ) : Int64 + return a.val % b.val; + + @:op(A % B) private static inline function modInt( a : Int64, b : Int ) : Int64 + return a.val % b; + + @:op(A % B) private static inline function intMod( a : Int, b : Int64 ) : Int64 + return a % b.val; + + @:op(A == B) public static inline function eq( a : Int64, b : Int64 ) : Bool + return a.val == b.val; + + @:op(A == B) @:commutative private static inline function eqInt( a : Int64, b : Int ) : Bool + return a.val == b; + + @:op(A != B) public static inline function neq( a : Int64, b : Int64 ) : Bool + return a.val != b.val; + + @:op(A != B) @:commutative private static inline function neqInt( a : Int64, b : Int ) : Bool + return a.val != b; + + @:op(A < B) private static inline function lt( a : Int64, b : Int64 ) : Bool + return a.val < b.val; + + @:op(A < B) private static inline function ltInt( a : Int64, b : Int ) : Bool + return a.val < b; + + @:op(A < B) private static inline function intLt( a : Int, b : Int64 ) : Bool + return a < b.val; + + @:op(A <= B) private static inline function lte( a : Int64, b : Int64 ) : Bool + return a.val <= b.val; + + @:op(A <= B) private static inline function lteInt( a : Int64, b : Int ) : Bool + return a.val <= b; + + @:op(A <= B) private static inline function intLte( a : Int, b : Int64 ) : Bool + return a <= b.val; + + @:op(A > B) private static inline function gt( a : Int64, b : Int64 ) : Bool + return a.val > b.val; + + @:op(A > B) private static inline function gtInt( a : Int64, b : Int ) : Bool + return a.val > b; + + @:op(A > B) private static inline function intGt( a : Int, b : Int64 ) : Bool + return a > b.val; + + @:op(A >= B) private static inline function gte( a : Int64, b : Int64 ) : Bool + return a.val >= b.val; + + @:op(A >= B) private static inline function gteInt( a : Int64, b : Int ) : Bool + return a.val >= b; + + @:op(A >= B) private static inline function intGte( a : Int, b : Int64 ) : Bool + return a >= b.val; + + @:op(~A) private static inline function complement( x : Int64 ) : Int64 + return ~x.val; + + @:op(A & B) public static inline function and( a : Int64, b : Int64 ) : Int64 + return a.val & b.val; + + @:op(A | B) public static inline function or( a : Int64, b : Int64 ) : Int64 + return a.val | b.val; + + @:op(A ^ B) public static inline function xor( a : Int64, b : Int64 ) : Int64 + return a.val ^ b.val; + + @:op(A << B) public static inline function shl( a : Int64, b : Int ) : Int64 + return a.val << b; + + @:op(A >> B) public static inline function shr( a : Int64, b : Int ) : Int64 + return a.val >> b; + + @:op(A >>> B) public static inline function ushr( a : Int64, b : Int ) : Int64 + return a.val >>> b; +} diff --git a/std/cs/system/reflection/ConstructorInfo.hx b/std/java/_std/haxe/Resource.hx similarity index 55% rename from std/cs/system/reflection/ConstructorInfo.hx rename to std/java/_std/haxe/Resource.hx index 81b3ffd0bc7c4f530d306aad7d9f67be60c9bf66..973ba68d30f131ceb56c4042a2f1c1ef565de39e 100644 --- a/std/cs/system/reflection/ConstructorInfo.hx +++ b/std/java/_std/haxe/Resource.hx @@ -1,29 +1,51 @@ -/* - * Copyright (C)2005-2012 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 cs.system.reflection; -import cs.NativeArray; - -@:native('System.Reflection.ConstructorInfo') extern class ConstructorInfo extends MethodBase -{ - @:overload(function(args:NativeArray):Dynamic {}) - override function Invoke(obj:Dynamic, args:NativeArray):Dynamic; -} \ No newline at end of file +/* + * Copyright (C)2005-2014 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 { + + @:keep static var content : Array; + + public static inline function listNames() : Array { + return content.copy(); + } + + @:access(haxe.io.Path.escape) + public static function getString( name : String ) : String { + name = haxe.io.Path.escape(name, true); + var stream = cast(Resource, java.lang.Class).getResourceAsStream("/" + name); + if (stream == null) + return null; + var stream = new java.io.NativeInput(stream); + return stream.readAll().toString(); + } + + @:access(haxe.io.Path.escape) + public static function getBytes( name : String ) : haxe.io.Bytes { + name = haxe.io.Path.escape(name, true); + var stream = cast(Resource, java.lang.Class).getResourceAsStream("/" + name); + if (stream == null) + return null; + var stream = new java.io.NativeInput(stream); + return stream.readAll(); + } +} diff --git a/std/java/_std/haxe/ds/IntMap.hx b/std/java/_std/haxe/ds/IntMap.hx index 063cd10297afdfe82a3c64721c2f2b8f66e75728..4b5a0d0d7d2a24e2f6e784bfee0a4ee3d453ff09 100644 --- a/std/java/_std/haxe/ds/IntMap.hx +++ b/std/java/_std/haxe/ds/IntMap.hx @@ -31,7 +31,7 @@ import java.NativeArray; * (https://jonasmalaco.com/fossil/test/jonas-haxe/artifact/887b53126e237d6c68951111d594033403889304) */ -@:coreApi class IntMap implements Map.IMap +@:coreApi class IntMap implements haxe.Constraints.IMap { private static inline var HASH_UPPER = 0.7; @@ -70,14 +70,17 @@ import java.NativeArray; var k = hash(key); var i = k & mask; + var delKey = -1; //for speed up if (flagIsEmpty(flags, i)) { x = i; } else { var inc = getInc(k, mask); var last = i; - while (! (isEither(flags, i) || _keys[i] == key) ) + while (! (flagIsEmpty(flags, i) || _keys[i] == key) ) { + if (flagIsDel(flags,i) && delKey == -1) + delKey = i; i = (i + inc) & mask; #if DEBUG_HASHTBL if (i == last) @@ -86,7 +89,11 @@ import java.NativeArray; } #end } - x = i; + + if (flagIsEmpty(flags, i) && delKey != -1) + x = delKey; + else + x = i; } } @@ -450,4 +457,4 @@ import java.NativeArray; private static inline function flagsSize(m:Int):Int return ((m) < 16? 1 : (m) >> 4); -} \ No newline at end of file +} diff --git a/std/java/_std/haxe/ds/ObjectMap.hx b/std/java/_std/haxe/ds/ObjectMap.hx index 075929f56be7344cb3e3eed9dae8a671a7c99c0b..997e4f024afa8d69bf13eaafe7124ab17645dba2 100644 --- a/std/java/_std/haxe/ds/ObjectMap.hx +++ b/std/java/_std/haxe/ds/ObjectMap.hx @@ -23,7 +23,7 @@ package haxe.ds; import java.NativeArray; -@:coreApi class ObjectMap implements Map.IMap +@:coreApi class ObjectMap implements haxe.Constraints.IMap { @:extern private static inline var HASH_UPPER = 0.77; @:extern private static inline var FLAG_EMPTY = 0; @@ -79,14 +79,17 @@ import java.NativeArray; k = hash(key); var i = k & mask, nProbes = 0; + var delKey = -1; //for speed up - if (isEither(hashes[i])) { + if (isEmpty(hashes[i])) { x = i; } else { //var inc = getInc(k, mask); var last = i, flag; - while(! (isEither(flag = hashes[i]) || (flag == k && untyped keys[i].equals(key))) ) + while(! (isEmpty(flag = hashes[i]) || (flag == k && untyped keys[i].equals(key))) ) { + if (isDel(flag) && delKey == -1) + delKey = i; i = (i + ++nProbes) & mask; #if DEBUG_HASHTBL probeTimes++; @@ -94,7 +97,11 @@ import java.NativeArray; throw "assert"; #end } - x = i; + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; } #if DEBUG_HASHTBL diff --git a/std/java/_std/haxe/ds/StringMap.hx b/std/java/_std/haxe/ds/StringMap.hx index c9fd183344e9ba36b2ffd8ba02cdd37f9cbcf63a..12caac8c56207d4355c9a8335d660cac85415df8 100644 --- a/std/java/_std/haxe/ds/StringMap.hx +++ b/std/java/_std/haxe/ds/StringMap.hx @@ -23,7 +23,7 @@ package haxe.ds; import java.NativeArray; -@:coreApi class StringMap implements Map.IMap +@:coreApi class StringMap implements haxe.Constraints.IMap { @:extern private static inline var HASH_UPPER = 0.77; @:extern private static inline var FLAG_EMPTY = 0; @@ -79,14 +79,17 @@ import java.NativeArray; k = hash(key); var i = k & mask, nProbes = 0; + var delKey = -1; //for speed up - if (isEither(hashes[i])) { + if (isEmpty(hashes[i])) { x = i; } else { //var inc = getInc(k, mask); var last = i, flag; - while(! (isEither(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) + while(! (isEmpty(flag = hashes[i]) || (flag == k && _keys[i] == key)) ) { + if (isDel(flag) && delKey == -1) + delKey = i; i = (i + ++nProbes) & mask; #if DEBUG_HASHTBL probeTimes++; @@ -94,7 +97,11 @@ import java.NativeArray; throw "assert"; #end } - x = i; + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; } #if DEBUG_HASHTBL diff --git a/std/java/_std/haxe/ds/WeakMap.hx b/std/java/_std/haxe/ds/WeakMap.hx new file mode 100644 index 0000000000000000000000000000000000000000..8e43c0a053b87bb1cea5836f3255e243469b6235 --- /dev/null +++ b/std/java/_std/haxe/ds/WeakMap.hx @@ -0,0 +1,550 @@ +/* + * Copyright (C)2005-2012 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; + +import java.NativeArray; +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; + +@:coreApi class WeakMap implements haxe.Constraints.IMap +{ + @:extern private static inline var HASH_UPPER = 0.77; + @:extern private static inline var FLAG_EMPTY = 0; + @:extern private static inline var FLAG_DEL = 1; + + /** + * This is the most important structure here and the reason why it's so fast. + * It's an array of all the hashes contained in the table. These hashes cannot be 0 nor 1, + * which stand for "empty" and "deleted" states. + * + * The lookup algorithm will keep looking until a 0 or the key wanted is found; + * The insertion algorithm will do the same but will also break when FLAG_DEL is found; + */ + private var hashes:NativeArray; + private var entries:NativeArray>; + + //weak map specific + private var queue:ReferenceQueue; + + private var nBuckets:Int; + private var size:Int; + private var nOccupied:Int; + private var upperBound:Int; + + private var cachedEntry:Entry; + private var cachedIndex:Int; + +#if DEBUG_HASHTBL + private var totalProbes:Int; + private var probeTimes:Int; + private var sameHash:Int; + private var maxProbe:Int; +#end + + public function new() : Void + { + cachedIndex = -1; + queue = new ReferenceQueue(); + } + + @:analyzer(ignore) + private function cleanupRefs():Void + { + var x:Dynamic = null, nOccupied = nOccupied; + while (( x = queue.poll()) != null) + { + //even if not found on hashtable (already removed), release value + var x:Entry = cast x; + x.value = null; + + //lookup index + if (nOccupied != 0) + { + var mask = nBuckets - 1, hash = x.hash, nProbes = 0; + var i = hash & mask; + var last = i, flag; + while(!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != hash || entries[i] != x)) + { + i = (i + ++nProbes) & mask; + } + + if (entries[i] == x) + { + if (cachedIndex == i) + { + cachedIndex = -1; + cachedEntry = null; + } + entries[i] = null; + hashes[i] = FLAG_DEL; + --size; + } + } + } + } + + public function set( key : K, value : V ) : Void + { + cleanupRefs(); + var x:Int, k:Int; + if (nOccupied >= upperBound) + { + if (nBuckets > (size << 1)) + resize(nBuckets - 1); //clear "deleted" elements + else + resize(nBuckets + 2); + } + + k = hash(key); + var hashes = hashes, entries = entries; + { + var mask = (nBuckets == 0) ? 0 : nBuckets - 1; + var site = x = nBuckets; + var i = k & mask, nProbes = 0; + + var delKey = -1; + //for speed up + if (isEmpty(hashes[i])) { + x = i; + } else { + //var inc = getInc(k, mask); + var last = i, flag; + while(! (isEmpty(flag = hashes[i]) || (flag == k && entries[i].keyEquals(key) )) ) + { + if (delKey == -1 && isDel(flag)) + delKey = i; + i = (i + ++nProbes) & mask; +#if DEBUG_HASHTBL + probeTimes++; + if (i == last) + throw "assert"; +#end + } + + if (isEmpty(flag) && delKey != -1) + x = delKey; + else + x = i; + } + +#if DEBUG_HASHTBL + if (nProbes > maxProbe) + maxProbe = nProbes; + totalProbes++; +#end + } + + var flag = hashes[x], entry = new Entry(key,value,k,queue); + if (isEmpty(flag)) + { + entries[x] = entry; + hashes[x] = k; + size++; + nOccupied++; + } else if (isDel(flag)) { + entries[x] = entry; + hashes[x] = k; + size++; + } else { + assert(entries[x].keyEquals(key)); + entries[x] = entry; + } + + cachedIndex = x; + cachedEntry = entry; + } + + @:final private function lookup( key : K ) : Int + { + if (nBuckets != 0) + { + var hashes = hashes, entries = entries; + + var mask = nBuckets - 1, hash = hash(key), k = hash, nProbes = 0; + var i = k & mask; + var last = i, flag; + //var inc = getInc(k, mask); + while (!isEmpty(flag = hashes[i]) && (isDel(flag) || flag != k || !entries[i].keyEquals(key))) + { + i = (i + ++nProbes) & mask; +#if DEBUG_HASHTBL + probeTimes++; + if (i == last) + throw "assert"; +#end + } + +#if DEBUG_HASHTBL + if (nProbes > maxProbe) + maxProbe = nProbes; + totalProbes++; +#end + return isEither(flag) ? -1 : i; + } + + return -1; + } + + @:final @:private function resize(newNBuckets:Int) : Void + { + //This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. + var newHash = null; + var j = 1; + { + newNBuckets = roundUp(newNBuckets); + if (newNBuckets < 4) newNBuckets = 4; + if (size >= (newNBuckets * HASH_UPPER + 0.5)) /* requested size is too small */ + { + j = 0; + } else { /* hash table size to be changed (shrink or expand); rehash */ + var nfSize = newNBuckets; + newHash = new NativeArray( nfSize ); + if (nBuckets < newNBuckets) //expand + { + var e = new NativeArray(newNBuckets); + if (entries != null) + arrayCopy(entries, 0, e, 0, nBuckets); + entries = e; + } //otherwise shrink + } + } + + if (j != 0) + { //rehashing is required + //resetting cache + cachedEntry = null; + cachedIndex = -1; + + j = -1; + var nBuckets = nBuckets, entries = entries, hashes = hashes; + + var newMask = newNBuckets - 1; + while (++j < nBuckets) + { + var k; + if (!isEither(k = hashes[j])) + { + var entry = entries[j]; + + hashes[j] = FLAG_DEL; + while (true) /* kick-out process; sort of like in Cuckoo hashing */ + { + var nProbes = 0; + var i = k & newMask; + + while (!isEmpty(newHash[i])) + i = (i + ++nProbes) & newMask; + + newHash[i] = k; + + if (i < nBuckets && !isEither(k = hashes[i])) /* kick out the existing element */ + { + { + var tmp = entries[i]; + entries[i] = entry; + entry = tmp; + } + + hashes[i] = FLAG_DEL; /* mark it as deleted in the old hash table */ + } else { /* write the element and jump out of the loop */ + entries[i] = entry; + break; + } + } + } + } + + if (nBuckets > newNBuckets) /* shrink the hash table */ + { + { + var e = new NativeArray(newNBuckets); + arrayCopy(entries, 0, e, 0, newNBuckets); + this.entries = e; + } + } + + this.hashes = newHash; + this.nBuckets = newNBuckets; + this.nOccupied = size; + this.upperBound = Std.int(newNBuckets * HASH_UPPER + .5); + } + } + + public function get( key : K ) : Null + { + cleanupRefs(); + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return cachedEntry.value; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return entry.value; + } + + return null; + } + + private function getDefault( key : K, def : V ) : V + { + cleanupRefs(); + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return cachedEntry.value; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return entry.value; + } + + return def; + } + + public function exists( key : K ) : Bool + { + cleanupRefs(); + var idx = -1; + if (cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) + { + return true; + } + + idx = lookup(key); + if (idx != -1) + { + var entry = entries[idx]; + cachedEntry = entry; + cachedIndex = idx; + + return true; + } + + return false; + } + + public function remove( key : K ) : Bool + { + cleanupRefs(); + var idx = -1; + if ( !(cachedEntry != null && cachedEntry.keyEquals(key) && ( (idx = cachedIndex) != -1 )) ) + { + idx = lookup(key); + } + + if (idx == -1) + { + return false; + } else { + if (cachedEntry != null && cachedEntry.keyEquals(key)) + { + cachedIndex = -1; + cachedEntry = null; + } + + hashes[idx] = FLAG_DEL; + entries[idx] = null; + --size; + + return true; + } + } + + /** + Returns an iterator of all keys in the hashtable. + Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration + **/ + public function keys() : Iterator + { + cleanupRefs(); + var i = 0; + var len = nBuckets; + var lastKey = null; //keep a strong reference to the key while iterating, so it can't be collected while iterating + return { + hasNext: function() { + for (j in i...len) + { + if (!isEither(hashes[j])) + { + var entry = entries[j]; + var last = entry.get(); + if (last != null) + { + lastKey = last; + cachedIndex = i; + cachedEntry = entry; + i = j; + return true; + } + } + } + return false; + }, + next: function() { + i = i + 1; + return lastKey; + } + }; + } + + /** + Returns an iterator of all values in the hashtable. + Implementation detail: Do not set() any new value while iterating, as it may cause a resize, which will break iteration + **/ + public function iterator() : Iterator + { + cleanupRefs(); + var i = 0; + var len = nBuckets; + return { + hasNext: function() { + for (j in i...len) + { + if (!isEither(hashes[j])) + { + i = j; + return true; + } + } + return false; + }, + next: function() { + var ret = entries[i].value; + i = i + 1; + return ret; + } + }; + } + + /** + Returns an displayable representation of the hashtable content. + **/ + + public function toString() : String { + var s = new StringBuf(); + s.add("{"); + var it = keys(); + for( i in it ) { + s.add(Std.string(i)); + s.add(" => "); + s.add(Std.string(get(i))); + if( it.hasNext() ) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + @:extern private static inline function roundUp(x:Int):Int + { + --x; + x |= (x) >>> 1; + x |= (x) >>> 2; + x |= (x) >>> 4; + x |= (x) >>> 8; + x |= (x) >>> 16; + return ++x; + } + + @:extern private static inline function getInc(k:Int, mask:Int):Int //return 1 for linear probing + return (((k) >> 3 ^ (k) << 3) | 1) & (mask); + + @:extern private static inline function isEither(v:HashType):Bool + return (v & 0xFFFFFFFE) == 0; + + @:extern private static inline function isEmpty(v:HashType):Bool + return v == FLAG_EMPTY; + + @:extern private static inline function isDel(v:HashType):Bool + return v == FLAG_DEL; + + //guarantee: Whatever this function is, it will never return 0 nor 1 + @:extern private static inline function hash(s:Dynamic):HashType + { + var k:Int = untyped s.hashCode(); + //k *= 357913941; + //k ^= k << 24; + //k += ~357913941; + //k ^= k >> 31; + //k ^= k << 31; + + k = (k+0x7ed55d16) + (k<<12); + k = (k^0xc761c23c) ^ (k>>19); + k = (k+0x165667b1) + (k<<5); + k = (k+0xd3a2646c) ^ (k<<9); + k = (k+0xfd7046c5) + (k<<3); + k = (k^0xb55a4f09) ^ (k>>16); + + var ret = k; + if (isEither(ret)) + { + if (ret == 0) + ret = 2; + else + ret = 0xFFFFFFFF; + } + + return ret; + } + + @:extern private static inline function arrayCopy(sourceArray:Dynamic, sourceIndex:Int, destinationArray:Dynamic, destinationIndex:Int, length:Int):Void + java.lang.System.arraycopy(sourceArray, sourceIndex, destinationArray, destinationIndex, length); + + @:extern private static inline function assert(x:Bool):Void + { +#if DEBUG_HASHTBL + if (!x) throw "assert failed"; +#end + } +} + +private class Entry extends WeakReference +{ + public var value:V; + public var hash(default, null):Int; + public function new(key:K, value:V, hash:Int, queue:ReferenceQueue) + { + super(key, queue); + this.value = value; + this.hash = hash; + } + + @:final inline public function keyEquals(k:K):Bool + { + return k != null && untyped k.equals(get()); + } +} + +private typedef HashType = Int; diff --git a/std/java/_std/haxe/zip/Compress.hx b/std/java/_std/haxe/zip/Compress.hx new file mode 100644 index 0000000000000000000000000000000000000000..45e0749365afd70308c99fb5d4411659c7fb9e4b --- /dev/null +++ b/std/java/_std/haxe/zip/Compress.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2012 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.zip; +import java.util.zip.Deflater; + +class Compress +{ + var deflater:Deflater; + var mode:Int; + var finish:Bool = false; + + public function new( level : Int ) + { + throw "Not implemented for this platform"; //FIXME: Add unit tests for Compress/Uncompress and check current implementation + this.deflater = new Deflater(level); + this.mode = Deflater.NO_FLUSH; + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } + { + deflater.setInput(src.getData(), srcPos, src.length - srcPos); + if (finish) + deflater.finish(); + finish = false; + + var written = deflater.deflate(dst.getData(), dstPos, dst.length - dstPos); + var read = deflater.getTotalIn(); + return { done: deflater.finished(), read: read, write: written }; + } + + public function setFlushMode( f : FlushMode ) + { + this.mode = switch (f) { + case NO: + Deflater.NO_FLUSH; + case SYNC: + Deflater.SYNC_FLUSH; + case FULL: + Deflater.FULL_FLUSH; + case FINISH: + this.finish = true; + Deflater.FULL_FLUSH; + case BLOCK: + throw "Not Implemented"; + } + } + + public function close() + { + deflater.end(); + } + + public static function run( s : haxe.io.Bytes, level : Int ) : haxe.io.Bytes + { + var deflater = new java.util.zip.Deflater(level); + deflater.setInput(s.getData()); + var outputStream = new java.io.ByteArrayOutputStream(s.length); + deflater.finish(); + var buffer = haxe.io.Bytes.alloc(1024).getData(); + while (!deflater.finished()) { + var count = deflater.deflate(buffer); + outputStream.write(buffer, 0, count); + } + outputStream.close(); + return haxe.io.Bytes.ofData(outputStream.toByteArray()); + } +} diff --git a/std/java/_std/haxe/zip/Uncompress.hx b/std/java/_std/haxe/zip/Uncompress.hx new file mode 100644 index 0000000000000000000000000000000000000000..fe698257a93e607e10be884d38d9a9b64f54cd64 --- /dev/null +++ b/std/java/_std/haxe/zip/Uncompress.hx @@ -0,0 +1,58 @@ +/* + * Copyright (C)2005-2012 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.zip; + +class Uncompress +{ + public function new( ?windowBits : Int ) { + throw "Not implemented for this platform"; + } + + public function execute( src : haxe.io.Bytes, srcPos : Int, dst : haxe.io.Bytes, dstPos : Int ) : { done : Bool, read : Int, write : Int } { + return null; + } + + public function setFlushMode( f : FlushMode ) { + } + + public function close() { + } + + public static function run( src : haxe.io.Bytes, ?bufsize : Int ) : haxe.io.Bytes + { + var decompresser = new java.util.zip.Inflater(); + var buf = haxe.io.Bytes.alloc(bufsize == null ? src.length : bufsize).getData(); + + var out = new java.io.ByteArrayOutputStream(src.length); + decompresser.setInput(src.getData(), 0, src.length); + + while (!decompresser.finished()) + { + var count = decompresser.inflate(buf); + out.write(buf, 0, count); + } + out.close(); + return haxe.io.Bytes.ofData(out.toByteArray()); + } + +} + diff --git a/std/java/_std/sys/FileSystem.hx b/std/java/_std/sys/FileSystem.hx index 29eb3ca32a4dc4db8b8c0e005440ccab40f9498e..1bcc3ed7bfa2839daa13b483ee4df446c45f0646 100644 --- a/std/java/_std/sys/FileSystem.hx +++ b/std/java/_std/sys/FileSystem.hx @@ -1,131 +1,109 @@ -/* - * Copyright (C)2005-2012 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; -import java.io.File; -import java.Lib; - -/** - This class allows you to get informations about the files and directories. -**/ -@:coreApi -class FileSystem { - - /** - Tells if the given file or directory exists. - **/ - public static function exists( path : String ) : Bool - { - return new File(path).exists(); - } - - /** - Rename the corresponding file or directory, allow to move it accross directories as well. - **/ - public static function rename( path : String, newpath : String ) : Void - { - if (!new File(path).renameTo(new File(newpath))) - { - throw "Cannot rename " + path + " to " + newpath; - } - } - - /** - Returns informations for the given file/directory. - **/ - public static function stat( path : String ) : FileStat - { - var f = new File(path); - if (!f.exists()) - throw "Path " + path + " doesn't exist"; - return { - gid: 0, //java doesn't let you get this info - uid: 0, //same - atime: Date.now(), //same - mtime: Date.fromTime(cast(f.lastModified(), Float)), - ctime: Date.fromTime(cast(f.lastModified(), Float)), //same - size: cast(f.length(), Int), //TODO: maybe change to Int64 for Haxe 3? - dev: 0, //FIXME: not sure what that is - ino: 0, //FIXME: not sure what that is - nlink: 0, //FIXME: not sure what that is - rdev: 0, //FIXME: not sure what that is - mode: 0 //FIXME: not sure what that is - }; - } - - /** - Returns the full path for the given path which is relative to the current working directory. - **/ - public static function fullPath( relpath : String ) : String - { - return new File(relpath).getAbsolutePath(); - } - - /** - Tells if the given path is a directory. Throw an exception if it does not exists or is not accesible. - **/ - public static function isDirectory( path : String ) : Bool - { - var f = new File(path); - if (!f.exists()) - throw "Path " + path + " doesn't exist"; - return f.isDirectory(); - } - - /** - Create the given directory. Not recursive : the parent directory must exists. - **/ - public static function createDirectory( path : String ) : Void - { - if (!new File(path).mkdirs()) - throw "Cannot create dir " + path; - } - - /** - Delete a given file. - **/ - public static function deleteFile( path : String ) : Void - { - if (!new File(path).delete()) - throw "Cannot delete file " + path; - } - - /** - Delete a given directory. - **/ - public static function deleteDirectory( path : String ) : Void - { - if (!new File(path).delete()) - throw "Cannot delete directory " + path; - } - - /** - Read all the files/directories stored into the given directory. - **/ - public static function readDirectory( path : String ) : Array - { - var f = new File(path); - if (!f.exists()) - throw "Path " + path + " doesn't exist"; - return Lib.array( f.list() ); - } - -} +/* + * Copyright (C)2005-2012 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; +import java.io.File; +import java.Lib; + +@:coreApi +class FileSystem { + + public static function exists( path : String ) : Bool + { + return new File(path).exists(); + } + + public static function rename( path : String, newPath : String ) : Void + { + if (!new File(path).renameTo(new File(newPath))) + { + throw "Cannot rename " + path + " to " + newPath; + } + } + + public static function stat( path : String ) : FileStat + { + var f = new File(path); + if (!f.exists()) + throw "Path " + path + " doesn't exist"; + return { + gid: 0, //java doesn't let you get this info + uid: 0, //same + atime: Date.now(), //same + mtime: Date.fromTime(cast(f.lastModified(), Float)), + ctime: Date.fromTime(cast(f.lastModified(), Float)), //same + size: cast(f.length(), Int), //TODO: maybe change to Int64 for Haxe 3? + dev: 0, //FIXME: not sure what that is + ino: 0, //FIXME: not sure what that is + nlink: 0, //FIXME: not sure what that is + rdev: 0, //FIXME: not sure what that is + mode: 0 //FIXME: not sure what that is + }; + } + + public static function fullPath( relPath : String ) : String + { + try { + return new File(relPath).getCanonicalPath(); + } catch (e: java.io.IOException) { + throw new java.lang.RuntimeException(e); + } + } + + public static function absolutePath ( relPath : String ) : String { + if (haxe.io.Path.isAbsolute(relPath)) return relPath; + return haxe.io.Path.join([Sys.getCwd(), relPath]); + } + + public static function isDirectory( path : String ) : Bool + { + var f = new File(path); + if (!f.exists()) + throw "Path " + path + " doesn't exist"; + return f.isDirectory(); + } + + public static function createDirectory( path : String ) : Void + { + if (!new File(path).mkdirs()) + throw "Cannot create dir " + path; + } + + public static function deleteFile( path : String ) : Void + { + if (!new File(path).delete()) + throw "Cannot delete file " + path; + } + + public static function deleteDirectory( path : String ) : Void + { + if (!new File(path).delete()) + throw "Cannot delete directory " + path; + } + + public static function readDirectory( path : String ) : Array + { + var f = new File(path); + if (!f.exists()) + throw "Path " + path + " doesn't exist"; + return Lib.array( f.list() ); + } +} diff --git a/std/java/_std/sys/db/Mysql.hx b/std/java/_std/sys/db/Mysql.hx new file mode 100644 index 0000000000000000000000000000000000000000..0b9beb4e18fbc11fc3a1e2c29c4c44633e963dfa --- /dev/null +++ b/std/java/_std/sys/db/Mysql.hx @@ -0,0 +1,57 @@ +/* + * Copyright (C)2005-2012 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.db; + +class Mysql { + + static var init = false; + + public static function connect( params : { + host : String, + ?port : Int, + user : String, + pass : String, + ?socket : String, + database : String + } ) : sys.db.Connection { + if (!init) + { + java.lang.Class.forName("com.mysql.jdbc.Driver"); + init = true; + } + var url = new StringBuf(); + url.add('jdbc:mysql:'); + if (params.socket != null) + { + url.add(params.socket); + } else { + url.add('//'); + url.add(params.host); + if (params.port != null) + url.add(':${params.port}'); + } + url.add('/${params.database}'); + var cnx = java.sql.DriverManager.getConnection(url.toString(), params.user, params.pass); + return java.db.Jdbc.create(cnx); + } + +} diff --git a/std/java/_std/sys/db/Sqlite.hx b/std/java/_std/sys/db/Sqlite.hx new file mode 100644 index 0000000000000000000000000000000000000000..1583091258232e6d5d0531e8b14ed14296da78d2 --- /dev/null +++ b/std/java/_std/sys/db/Sqlite.hx @@ -0,0 +1,23 @@ +package sys.db; + +class Sqlite +{ + static var init = false; + /** + Opens a new SQLite connection on the specified path. + Note that you will need a SQLite JDBC driver (like https://bitbucket.org/xerial/sqlite-jdbc). + **/ + public static function open(file:String):sys.db.Connection + { + if (!init) + { + try java.lang.Class.forName("org.sqlite.JDBC") catch(e:Dynamic) throw e; + init = true; + } + try + { + var cnx = java.sql.DriverManager.getConnection("jdbc:sqlite:" + file); + return java.db.Jdbc.create(cnx); + } catch(e:Dynamic) throw e; + } +} diff --git a/std/java/_std/sys/io/File.hx b/std/java/_std/sys/io/File.hx index 9f0bf8e2dcaabb617e02adf052a0c06eed3d694e..34d5b311c7e1cbf4b74c8bd7565c9b93dff23230 100644 --- a/std/java/_std/sys/io/File.hx +++ b/std/java/_std/sys/io/File.hx @@ -1,127 +1,124 @@ -/* - * Copyright (C)2005-2012 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.io; - -/** - API for reading and writing to files. -**/ -@:coreApi -class File { - - public static function getContent( path : String ) : String - { - var f = read(path, false); - var ret = f.readAll().toString(); - f.close(); - return ret; - } - - public static function saveContent( path : String, content : String ) : Void - { - var f = write(path, false); - f.writeString(content); - f.close(); - } - - public static function getBytes( path : String ) : haxe.io.Bytes - { - var f = read(path, true); - var ret = f.readAll(); - f.close(); - return ret; - } - - public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void - { - var f = write(path, true); - f.writeBytes(bytes, 0, bytes.length); - f.close(); - } - - 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 - { - throw e; - } - } - - public static function write( path : String, binary : Bool = true ) : FileOutput - { - var f = new java.io.File(path); - if (f.exists()) - { - f.delete(); - } - - try - { - return new FileOutput( new java.io.RandomAccessFile(f, "rw") ); - } - catch (e:Dynamic) //swallow checked exceptions - { - throw e; - } - } - - public static function append( path : String, binary : Bool = true ) : FileOutput - { - var f = new java.io.File(path); - - try - { - var ra = new java.io.RandomAccessFile(f, "rw"); - if (f.exists()) - { - ra.seek(f.length()); - } - return new FileOutput( ra ); - } - catch (e:Dynamic) //swallow checked exceptions - { - throw e; - } - } - - public static function copy( src : String, dst : String ) : Void - { - var r:FileInput = null; - var w:FileOutput = null; - try - { - r = read(src); - w = write(dst); - w.writeInput(r); - } - - catch (e:Dynamic) - { - if (r != null) r.close(); - if (w != null) w.close(); - throw e; - } - } +/* + * Copyright (C)2005-2012 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.io; + +@:coreApi +class File { + + public static function getContent( path : String ) : String + { + var f = read(path, false); + var ret = f.readAll().toString(); + f.close(); + return ret; + } + + public static function saveContent( path : String, content : String ) : Void + { + var f = write(path, false); + f.writeString(content); + f.close(); + } + + public static function getBytes( path : String ) : haxe.io.Bytes + { + var f = read(path, true); + var ret = f.readAll(); + f.close(); + return ret; + } + + public static function saveBytes( path : String, bytes : haxe.io.Bytes ) : Void + { + var f = write(path, true); + f.writeBytes(bytes, 0, bytes.length); + f.close(); + } + + 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 + { + throw e; + } + } + + public static function write( path : String, binary : Bool = true ) : FileOutput + { + var f = new java.io.File(path); + if (f.exists()) + { + f.delete(); + } + + try + { + return new FileOutput( new java.io.RandomAccessFile(f, "rw") ); + } + catch (e:Dynamic) //swallow checked exceptions + { + throw e; + } + } + + public static function append( path : String, binary : Bool = true ) : FileOutput + { + var f = new java.io.File(path); + + try + { + var ra = new java.io.RandomAccessFile(f, "rw"); + if (f.exists()) + { + ra.seek(f.length()); + } + return new FileOutput( ra ); + } + catch (e:Dynamic) //swallow checked exceptions + { + throw e; + } + } + + public static function copy( srcPath : String, dstPath : String ) : Void + { + var r:FileInput = null; + var w:FileOutput = null; + try + { + r = read(srcPath); + w = write(dstPath); + w.writeInput(r); + } + + catch (e:Dynamic) + { + if (r != null) r.close(); + if (w != null) w.close(); + throw e; + } + } } \ No newline at end of file diff --git a/std/java/_std/sys/io/FileInput.hx b/std/java/_std/sys/io/FileInput.hx index d1762e2a17444592182eb96910e97f49109b5373..4c98c6db84619b16135b6570ab522a4dfa44b4e7 100644 --- a/std/java/_std/sys/io/FileInput.hx +++ b/std/java/_std/sys/io/FileInput.hx @@ -1,127 +1,125 @@ -/* - * Copyright (C)2005-2012 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.io; -import haxe.Int64; -import haxe.io.Bytes; -import haxe.io.Eof; -import haxe.io.Input; -import java.io.EOFException; -import java.io.IOException; - -/** - Use [sys.io.File.read] to create a [FileInput] -**/ -class FileInput extends Input { - var f:java.io.RandomAccessFile; - public function new(f) - { - this.f = f; - } - - override public function close() - { - try f.close() catch(e:Dynamic) throw e; - } - - override public function readByte():Int - { - try - { - return f.readUnsignedByte(); - } - - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function readBytes(s:Bytes, pos:Int, len:Int):Int - { - var ret = 0; - try - { - ret = f.read(s.getData(), pos, len); - } - - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - - if (ret == -1) - throw new Eof(); - - return ret; - } - - public function seek( p : Int, pos : FileSeek ) : Void - { - try - { - switch(pos) - { - case SeekBegin: f.seek(cast p); - case SeekCur: f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, Int64))); - case SeekEnd: f.seek(haxe.Int64.add(f.length(), cast p)); - } - } - - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - public function tell() : Int - { - try - { - return cast f.getFilePointer(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - public function eof() : Bool - { - try - { - return f.getFilePointer() == f.length(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } -} +/* + * Copyright (C)2005-2012 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.io; +import haxe.Int64; +import haxe.io.Bytes; +import haxe.io.Eof; +import haxe.io.Input; +import java.io.EOFException; +import java.io.IOException; + +class FileInput extends Input { + var f:java.io.RandomAccessFile; + var _eof:Bool; + public function new(f) + { + this.f = f; + this._eof = false; + } + + override public function close() + { + try f.close() catch(e:Dynamic) throw e; + } + + override public function readByte():Int + { + try + { + return f.readUnsignedByte(); + } + + catch (e:EOFException) { + _eof = true; + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + override public function readBytes(s:Bytes, pos:Int, len:Int):Int + { + var ret = 0; + try + { + ret = f.read(s.getData(), pos, len); + } + + catch (e:EOFException) { + _eof = true; + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + + if (ret == -1) { + _eof = true; + throw new Eof(); + } + + return ret; + } + + public function seek( p : Int, pos : FileSeek ) : Void + { + _eof = false; + try + { + switch(pos) + { + case SeekBegin: f.seek(cast p); + case SeekCur: f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, Int64))); + case SeekEnd: f.seek(haxe.Int64.add(f.length(), cast p)); + } + } + + catch (e:EOFException) { + _eof = true; + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + public function tell() : Int + { + try + { + return cast f.getFilePointer(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + public inline function eof() : Bool + { + return _eof; + } +} diff --git a/std/java/_std/sys/io/FileOutput.hx b/std/java/_std/sys/io/FileOutput.hx index e56d6ed9830fa8f431915e148c2e33f70f8da5aa..6fad33c8f35940f7520299677b1cf33544239ef5 100644 --- a/std/java/_std/sys/io/FileOutput.hx +++ b/std/java/_std/sys/io/FileOutput.hx @@ -1,112 +1,109 @@ -/* - * Copyright (C)2005-2012 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.io; -import haxe.io.Bytes; -import haxe.io.Eof; -import haxe.io.Output; -import java.io.EOFException; -import java.io.IOException; - -/** - Use [sys.io.File.write] to create a [FileOutput] -**/ -class FileOutput extends Output { - var f:java.io.RandomAccessFile; - public function new(f) - { - this.f = f; - } - - override public function close() - { - try f.close() catch(e:Dynamic) throw e; - } - - override public function writeByte(c:Int):Void - { - try - { - this.f.write(c); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function write(s:Bytes):Void - { - try - { - this.f.write(s.getData()); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function writeBytes(s:Bytes, pos:Int, len:Int):Int - { - try - { - this.f.write(s.getData(), pos, len); - return len; - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - public function seek( p : Int, pos : FileSeek ) : Void - { - try - { - switch(pos) - { - case SeekBegin: f.seek(cast p); - case SeekCur: f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, haxe.Int64))); - case SeekEnd: f.seek(haxe.Int64.add(f.length(), cast p)); - } - } - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - public function tell() : Int - { - try - { - return cast f.getFilePointer(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } -} +/* + * Copyright (C)2005-2012 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.io; +import haxe.io.Bytes; +import haxe.io.Eof; +import haxe.io.Output; +import java.io.EOFException; +import java.io.IOException; + +class FileOutput extends Output { + var f:java.io.RandomAccessFile; + public function new(f) + { + this.f = f; + } + + override public function close() + { + try f.close() catch(e:Dynamic) throw e; + } + + override public function writeByte(c:Int):Void + { + try + { + this.f.write(c); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + override public function write(s:Bytes):Void + { + try + { + this.f.write(s.getData()); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + override public function writeBytes(s:Bytes, pos:Int, len:Int):Int + { + try + { + this.f.write(s.getData(), pos, len); + return len; + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + public function seek( p : Int, pos : FileSeek ) : Void + { + try + { + switch(pos) + { + case SeekBegin: f.seek(cast p); + case SeekCur: f.seek(haxe.Int64.add(f.getFilePointer(), cast(p, haxe.Int64))); + case SeekEnd: f.seek(haxe.Int64.add(f.length(), cast p)); + } + } + catch (e:EOFException) { + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + public function tell() : Int + { + try + { + return cast f.getFilePointer(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } +} diff --git a/std/java/_std/sys/io/Process.hx b/std/java/_std/sys/io/Process.hx index 7f9087609a73b03bc3680129bb71075a7c1993e8..75396d2a8f237d7c3375307cc45d227408001686 100644 --- a/std/java/_std/sys/io/Process.hx +++ b/std/java/_std/sys/io/Process.hx @@ -104,17 +104,17 @@ private class ProcessInput extends java.io.NativeInput { if (chained != null) return chained.readByte(); + var ret = 0; try { - return stream.read(); + ret = stream.read(); } - catch (e:EOFException) { - throw new Eof(); - } - catch (e:IOException) { throw haxe.io.Error.Custom(e); } + if ( ret == -1 ) + throw new Eof(); + return ret; } override public function readBytes(s:Bytes, pos:Int, len:Int):Int diff --git a/std/java/_std/sys/net/Host.hx b/std/java/_std/sys/net/Host.hx index 9dcaace75bab5887b5362dceb7a231188595c500..c0e6548661ad5980ba3ac7a997e69c6e9cad0fc8 100644 --- a/std/java/_std/sys/net/Host.hx +++ b/std/java/_std/sys/net/Host.hx @@ -22,20 +22,11 @@ package sys.net; import java.net.InetAddress; -/** - A given IP host name. -**/ class Host { - /** - The actual IP corresponding to the host. - **/ public var ip(default,null) : Int; @:allow(sys.net) private var wrapped:InetAddress; - /** - Creates a new Host : the name can be an IP in the form "127.0.0.1" or an host name such as "google.com", in which case - the corresponding IP address is resolved using DNS. An exception occur if the host name could not be found. - **/ + public function new( name : String ) : Void { try @@ -46,25 +37,16 @@ class Host { this.ip = cast(rawIp[3], Int) | (cast(rawIp[2], Int) << 8) | (cast(rawIp[1], Int) << 16) | (cast(rawIp[0], Int) << 24); } - /** - Returns the IP representation of the host - **/ public function toString() : String { return wrapped.getHostAddress(); } - /** - Perform a reverse-DNS query to resolve a host name from an IP. - **/ public function reverse() : String { return wrapped.getHostName(); } - /** - Returns the local computer host name - **/ public static function localhost() : String { try diff --git a/std/java/_std/sys/net/Socket.hx b/std/java/_std/sys/net/Socket.hx index 9bfe8f5b794aef7533f5585f60b00d943c9a5c1a..52202d120d212c463ffd7ad1c76ba5def1460342 100644 --- a/std/java/_std/sys/net/Socket.hx +++ b/std/java/_std/sys/net/Socket.hx @@ -28,17 +28,12 @@ class Socket { public var input(default,null) : haxe.io.Input; public var output(default,null) : haxe.io.Output; - /** - A custom value that can be associated with the socket. Can be used to retreive your custom infos after a [select]. - ***/ public var custom : Dynamic; private var sock:java.net.Socket; private var server:java.net.ServerSocket; private var boundAddr:java.net.SocketAddress; - /** - Creates a new unconnected socket. - **/ + public function new() : Void { create(); @@ -53,9 +48,6 @@ class Socket { } catch(e:Dynamic) throw e; } - /** - Closes the socket : make sure to properly close all your sockets or you will crash when you run out of file descriptors. - **/ public function close() : Void { try @@ -68,25 +60,16 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Read the whole data available on the socket. - **/ public function read() : String { return input.readAll().toString(); } - /** - Write the whole data to the socket output. - **/ public function write( content : String ) : Void { output.writeString(content); } - /** - Connect to the given server host/port. Throw an exception in case we couldn't sucessfully connect. - **/ public function connect( host : Host, port : Int ) : Void { try @@ -98,9 +81,6 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Allow the socket to listen for incoming questions. The parameter tells how many pending connections we can have until they get refused. Use [accept()] to accept incoming connections. - **/ public function listen( connections : Int ) : Void { if (boundAddr == null) throw "You must bind the Socket to an address!"; @@ -109,9 +89,6 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Shutdown the socket, either for reading or writing. - **/ public function shutdown( read : Bool, write : Bool ) : Void { try @@ -124,9 +101,6 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Bind the socket to the given host/port so it can afterwards listen for connections there. - **/ public function bind( host : Host, port : Int ) : Void { if (boundAddr != null) @@ -136,47 +110,37 @@ class Socket { this.boundAddr = new java.net.InetSocketAddress(host.wrapped, port); } - /** - Accept a new connected client. This will return a connected socket on which you can read/write some data. - **/ public function accept() : Socket { var ret = try server.accept() catch(e:Dynamic) throw e; var s = new Socket(); s.sock = ret; + s.output = new java.io.NativeOutput(ret.getOutputStream()); + s.input = new java.io.NativeInput(ret.getInputStream()); return s; } - /** - Return the informations about the other side of a connected socket. - **/ public function peer() : { host : Host, port : Int } { - var rem:java.net.InetSocketAddress = cast sock.getInetAddress(); + var rem = sock.getInetAddress(); if (rem == null) return null; var host = new Host(null); - host.wrapped = rem.getAddress(); - return { host: host, port: rem.getPort() }; + host.wrapped = rem; + return { host: host, port: sock.getPort() }; } - /** - Return the informations about our side of a connected socket. - **/ public function host() : { host : Host, port : Int } { var local = sock.getLocalAddress(); var host = new Host(null); host.wrapped = local; - return { host: host, port: sock.getPort() }; + return { host: host, port: sock.getLocalPort() }; } - /** - Gives a timeout after which blocking socket operations (such as reading and writing) will abort and throw an exception. - **/ public function setTimeout( timeout : Float ) : Void { try @@ -184,25 +148,16 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Block until some data is available for read on the socket. - **/ public function waitForRead() : Void { throw "Not implemented"; } - /** - Change the blocking mode of the socket. A blocking socket is the default behavior. A non-blocking socket will abort blocking operations immediatly by throwing a haxe.io.Error.Blocking value. - **/ public function setBlocking( b : Bool ) : Void { throw "Not implemented"; } - /** - Allows the socket to immediatly send the data when written to its output : this will cause less ping but might increase the number of packets / data size, especially when doing a lot of small writes. - **/ public function setFastSend( b : Bool ) : Void { try @@ -210,18 +165,9 @@ class Socket { catch(e:Dynamic) throw e; } - /** - Wait until one of the sockets groups is ready for the given operation : - [read] contains sockets on which we want to wait for available data to be read, - [write] contains sockets on which we want to wait until we are allowed to write some data to their output buffers, - [others] contains sockets on which we want to wait for exceptional conditions. - [select] will block until one of the condition is met, in which case it will return the sockets for which the condition was true. - In case a [timeout] (in seconds) is specified, select might wait at worse until the timeout expires. - **/ public static function select(read : Array, write : Array, others : Array, ?timeout : Float) : { read: Array,write: Array,others: Array } { throw "Not implemented"; return null; } - } diff --git a/std/java/db/Jdbc.hx b/std/java/db/Jdbc.hx new file mode 100644 index 0000000000000000000000000000000000000000..c1e007044231afc3a8a42c7ce72aa135abdeca6f --- /dev/null +++ b/std/java/db/Jdbc.hx @@ -0,0 +1,333 @@ +package java.db; +import java.util.concurrent.atomic.AtomicInteger; +import haxe.io.Bytes; +import java.sql.Types; + +@:native('haxe.java.db.Jdbc') +class Jdbc +{ + + public static function create(cnx:java.sql.Connection):sys.db.Connection + { + return new JdbcConnection(cnx); + } + +} + +@:native('haxe.java.db.JdbcConnection') +private class JdbcConnection implements sys.db.Connection +{ + private static var ids = new AtomicInteger(0); + private var id:Int; + + private var cnx:java.sql.Connection; + private var _lastInsertId:Int; + //escape handling + private var escapeRegex:EReg; + private var escapes:Array; + + public function new(cnx) + { + this.id = ids.getAndIncrement(); + this.cnx = cnx; + this.escapes = []; + this.escapeRegex = ~/@@HX_ESCAPE(\d+)_(\d+)@@/; + } + + public function close() + { + try + this.cnx.close() + catch(e:Dynamic) throw e; + } + + public function escape(s:String):String + { + return "@@HX_ESCAPE" + id + "_" +escapes.push(s) + "@@"; + } + + public function quote(s:String):String + { + return "@@HX_ESCAPE" + id + "_" +escapes.push(s) + "@@"; + } + + public function addValue(s:StringBuf, v:Dynamic) + { + if (Std.is(v, Date)) + { + v = Std.string(v); + } else if (Std.is(v, Bytes)) { + var bt:Bytes = v; + v = bt.getData(); + } + s.add("@@HX_ESCAPE"); + s.add(id); + s.add("_"); + s.add(escapes.push(v)); + s.add("@@"); + } + + public function lastInsertId():Int + { + return _lastInsertId; + } + + public function dbName():String + { + try { + var ret = cnx.getMetaData().getDriverName(); + var retc = ret.toLowerCase(); + if (retc.indexOf("mysql") != -1) + return "MySQL"; + else if (retc.indexOf("sqlite") != -1) + return "SQLite"; + return ret; + } catch(e:Dynamic) { throw e; } + } + + public function startTransaction() + { + try + { + cnx.setAutoCommit(false); + } + catch(e:Dynamic) throw e; + } + + public function commit() + { + try + { + cnx.commit(); + } + catch(e:Dynamic) + { + throw e; + } + } + + public function rollback() + { + try + cnx.rollback() + catch(e:Dynamic) throw e; + } + + public function request(s:String):sys.db.ResultSet + { + var newst = new StringBuf(); + var sentArray = []; + + //cycle through the request string, adding any @@HX_ESCAPE@@ reference to the sentArray + var r = escapeRegex; + var myid = id + "", escapes = escapes, elen = escapes.length; + try + { + while (r.match(s)) + { + var id = r.matched(1); + if (id != myid) throw "Request quotes are only valid for one single request; They can't be cached."; + + newst.add(r.matchedLeft()); + var eid = Std.parseInt(r.matched(2)); + if (eid == null || eid > elen) + throw "Invalid request quote ID " + eid; + sentArray.push(escapes[eid - 1]); + newst.add("?"); + s = r.matchedRight(); + } + newst.add(s); + var stmt = cnx.prepareStatement(newst.toString(), java.sql.Statement.Statement_Statics.RETURN_GENERATED_KEYS); + for (i in 0...sentArray.length) + { + stmt.setObject(i + 1, sentArray[i]); + } + + var ret = null, dbName = dbName(); + if (stmt.execute()) + { + //is a result set + var rs = stmt.getResultSet(); + ret = new JdbcResultSet(rs, dbName, stmt.getMetaData()); + } else { + //is an update + var affected = stmt.getUpdateCount(); + if (affected == 1) + { + var autogen = stmt.getGeneratedKeys(); + if (autogen.next()) + { + this._lastInsertId = autogen.getInt(1); + } + } + ret = new JdbcResultSet(null, dbName,null); + } + + if (escapes.length != 0) + escapes = []; + this.id = ids.getAndIncrement(); + return ret; + } + catch(e:Dynamic) + { + if (escapes.length != 0) + escapes = []; + this.id = ids.getAndIncrement(); + throw e; + } + } + +} + +@:native('haxe.java.db.JdbcResultSet') +private class JdbcResultSet implements sys.db.ResultSet +{ + @:isVar public var length(get,null) : Int; + public var nfields(get,null) : Int; + + private var rs:java.sql.ResultSet; + private var names:Array; + private var types:java.NativeArray; + private var dbName:String; + private var didNext:Bool; + + public function new(rs, dbName, meta:java.sql.ResultSetMetaData) + { + this.dbName = dbName; + this.rs = rs; + if (meta != null) + { + try { + var count = meta.getColumnCount(); + var names = [], types = new NativeArray(count); + for (i in 0...count) + { + names.push(meta.getColumnName(i+1)); + types[i] = meta.getColumnType(i+1); + } + this.types = types; + this.names = names; + } catch(e:Dynamic) throw e; + } + } + + private function get_length():Int + { + if (length == 0) + { + try + { + var cur = rs.getRow(); + rs.last(); + this.length = rs.getRow(); + rs.absolute(cur); + } catch(e:Dynamic) throw e; + } + return length; + } + + private function get_nfields():Int + { + return names == null ? 0 : names.length; + } + + public function hasNext() : Bool + { + try + { + didNext = true; + return rs != null && rs.next(); + } + catch(e:Dynamic) { return throw e; } + } + + public function next() : Dynamic + { + try { + if (rs == null) return null; + if (didNext) + { + didNext = false; + } else { + if (!rs.next()) + { + return null; + } + } + var ret = {}, names = names, types = types; + for (i in 0...names.length) + { + var name = names[i], t = types[i], val:Dynamic = null; + if (t == Types.FLOAT) + { + val = rs.getDouble(i+1); + } else if (t == Types.DATE || t == Types.TIME) { + if (dbName == "SQLite") + { + var str = rs.getString(i+1); + if (str != null) + { + var d:Date = Date.fromString(str); + val = d; + } + } else { + var d:java.sql.Date = rs.getDate(i+1); + if (d != null) + val = Date.fromTime(cast d.getTime()); + } + } else if (t == Types.LONGVARBINARY || t == Types.VARBINARY || t == Types.BINARY || t == Types.BLOB) { + var b = rs.getBytes(i+1); + if (b != null) + val = Bytes.ofData(b); + } else { + untyped __java__("val = rs.getObject(i + 1)"); //type parameter constraint + overloads + } + Reflect.setField(ret, name, val); + } + return ret; + } catch(e:Dynamic) throw e; + } + + public function results() : List + { + var l = new List(); + if (rs == null) return l; + + try + { + while(hasNext()) + l.add(next()); + } catch(e:Dynamic) throw e; + return l; + } + + public function getResult( n : Int ) : String + { + try + { + return rs.getString(n); + } catch(e:Dynamic) throw e; + } + + public function getIntResult( n : Int ) : Int + { + try + { + return rs.getInt(n); + } + catch(e:Dynamic) { return throw e; }; + } + + public function getFloatResult( n : Int ) : Float + { + try + { + return rs.getFloat(n); + } catch(e:Dynamic) { return throw e; }; + } + + public function getFieldsNames() : Null> + { + return this.names; + } +} diff --git a/std/java/internal/Exceptions.hx b/std/java/internal/Exceptions.hx index 3e0b7e6f70e4d2fc6bdc170653863822990494b5..88e98ba3281f8ed31aa5bece2aa86caa2ebbf939 100644 --- a/std/java/internal/Exceptions.hx +++ b/std/java/internal/Exceptions.hx @@ -1,66 +1,90 @@ -/* - * Copyright (C)2005-2012 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; - -@: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; - } - - @:overload override public function toString():String - { - return "Haxe Exception: " + obj; - } - - public static function wrap(obj:Dynamic):RuntimeException - { - if (Std.is(obj, RuntimeException)) - return obj; - - if (Std.is(obj, String)) - return new HaxeException(obj, obj, null); - else if (Std.is(obj, Throwable)) - return new HaxeException(obj, null, obj); - - return new HaxeException(obj, null, null); - } -} +/* + * Copyright (C)2005-2012 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; + } + + 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, null, obj); + else + ret = new HaxeException(obj, null, null); + return ret; + } +} diff --git a/std/java/internal/FieldLookup.hx b/std/java/internal/FieldLookup.hx index 9b40be935090b655891c0e18636230bde368e1a6..c0c6f71e8507760c9a3abf51d42c2c60ec1a53f3 100644 --- a/std/java/internal/FieldLookup.hx +++ b/std/java/internal/FieldLookup.hx @@ -1,59 +1,124 @@ -/* - * Copyright (C)2005-2012 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; - -@:native('haxe.lang.FieldLookup') -@:keep -@:static private class FieldLookup -{ - - @:functionCode(' - return s.hashCode(); - ') - public static function hash(s:String):Int - { - return 0; - } - - public static function findHash(hash:String, hashs:Array):Int - { - var min = 0; - var max = hashs.length; - - while (min < max) - { - var mid = Std.int((max + min) / 2); //overflow safe - var classify = untyped hash.compareTo(hashs[mid]); - if (classify < 0) - { - max = mid; - } else if (classify > 0) { - min = mid + 1; - } else { - return mid; - } - } - //if not found, return a negative value of where it should be inserted - return ~min; - } - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.System; + +@:native('haxe.lang.FieldLookup') +@:keep +@:static private class FieldLookup +{ + + @:functionCode(' + return s.hashCode(); + ') + public static function hash(s:String):Int + { + return 0; + } + + public static function findHash(hash:String, hashs:java.NativeArray, length:Int):Int + { + var min = 0; + var max = length; + + while (min < max) + { + var mid = Std.int((max + min) / 2); //overflow safe + var classify = untyped hash.compareTo(hashs[mid]); + if (classify < 0) + { + max = mid; + } else if (classify > 0) { + min = mid + 1; + } else { + return mid; + } + } + //if not found, return a negative value of where it should be inserted + return ~min; + } + + static function removeString(a:java.NativeArray, length:Int, pos:Int) { + System.arraycopy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = null; + } + + static function removeFloat(a:java.NativeArray, length:Int, pos:Int) { + System.arraycopy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = 0; + } + + static function removeDynamic(a:java.NativeArray, length:Int, pos:Int) { + System.arraycopy(a, pos + 1, a, pos, length - pos - 1); + a[length - 1] = null; + } + + @:extern + static inline function __insert(a:java.NativeArray, length:Int, pos:Int, x:T):java.NativeArray + { + var capacity = a.length; + if (pos == length) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + System.arraycopy(a, 0, newarr, 0, a.length); + a = newarr; + } + } + else if (pos == 0) + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + System.arraycopy(a, 0, newarr, 1, length); + a = newarr; + } + else + { + System.arraycopy(a, 0, a, 1, length); + } + } + else + { + if (capacity == length) + { + var newarr = new NativeArray((length << 1) + 1); + System.arraycopy(a, 0, newarr, 0, pos); + System.arraycopy(a, pos, newarr, pos + 1, length - pos); + a = newarr; + } + else + { + System.arraycopy(a, pos, a, pos + 1, length - pos); + System.arraycopy(a, 0, a, 0, pos); + } + } + a[pos] = x; + return a; + } + + static function insertString(a:java.NativeArray, length:Int, pos:Int, x:String):java.NativeArray return __insert(a, length, pos, x); + static function insertFloat(a:java.NativeArray, length:Int, pos:Int, x:Float):java.NativeArray return __insert(a, length, pos, x); + static function insertDynamic(a:java.NativeArray, length:Int, pos:Int, x:Dynamic):java.NativeArray return __insert(a, length, pos, x); +} diff --git a/std/java/internal/Function.hx b/std/java/internal/Function.hx index 9173a56e8ca0da89b2b62e1834db557c4fff9c43..4bcae251451b17114d22b742c8de628a5684ae39 100644 --- a/std/java/internal/Function.hx +++ b/std/java/internal/Function.hx @@ -1,81 +1,94 @@ -/* - * Copyright (C)2005-2012 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.internal.Runtime; - -/** - * These classes are automatically generated by the compiler. They are only - * here so there is an option for e.g. defining them as externs if you are compiling - * in modules (untested) - * - * @author waneck - */ -@:abstract @:nativeGen @:native("haxe.lang.Function") @:keep private class Function -{ - function new(arity:Int, type:Int) - { - - } -} - -@:nativeGen @:native("haxe.lang.VarArgsBase") @:keep private class VarArgsBase extends Function -{ - public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - throw "Abstract implementation"; - return null; - } -} - -@:nativeGen @:native('haxe.lang.VarArgsFunction') @:keep class VarArgsFunction extends VarArgsBase -{ - private var fun:Array->Dynamic; - - public function new(fun) - { - super(-1, -1); - this.fun = fun; - } - - override public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - return fun(dynArgs); - } -} - -@:nativeGen @:native('haxe.lang.Closure') @:keep class Closure extends VarArgsBase -{ - private var obj:Dynamic; - private var field:String; - - public function new(obj:Dynamic, field) - { - super(-1, -1); - this.obj = obj; - this.field = field; - } - - override public function __hx_invokeDynamic(dynArgs:Array):Dynamic - { - return Runtime.callField(obj, field, dynArgs); - } -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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.internal.Runtime; + +/** + * These classes are automatically generated by the compiler. They are only + * here so there is an option for e.g. defining them as externs if you are compiling + * in modules (untested) + * + * @author waneck + */ +@:abstract @:nativeGen @:native("haxe.lang.Function") @:keep class Function +{ + function new(arity:Int, type:Int) + { + + } +} + +@:nativeGen @:native("haxe.lang.VarArgsBase") @:keep private class VarArgsBase extends Function +{ + public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + throw "Abstract implementation"; + } +} + +@:nativeGen @:native('haxe.lang.VarArgsFunction') @:keep class VarArgsFunction extends VarArgsBase +{ + private var fun:Array->Dynamic; + + public function new(fun) + { + super(-1, -1); + this.fun = fun; + } + + override public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + return fun(dynArgs); + } +} + +@:nativeGen @:native('haxe.lang.Closure') @:keep class Closure extends VarArgsBase +{ + private var obj:Dynamic; + private var field:String; + + public function new(obj:Dynamic, field) + { + super(-1, -1); + this.obj = obj; + this.field = field; + } + + override public function __hx_invokeDynamic(dynArgs:Array):Dynamic + { + return Runtime.callField(obj, field, dynArgs); + } + + public function equals(obj:Dynamic):Bool + { + if (obj == null) + return false; + + var c:Closure = cast obj; + return (c.obj == this.obj && c.field == this.field); + } + + public function hashCode():Int + { + return obj.hashCode() ^ untyped field.hashCode(); + } +} diff --git a/std/java/internal/HxObject.hx b/std/java/internal/HxObject.hx index a37408a042bf6b05e7196b004c94df7a5d13cded..875a265f358715f9708c76d711066ea8a03df202 100644 --- a/std/java/internal/HxObject.hx +++ b/std/java/internal/HxObject.hx @@ -21,6 +21,8 @@ */ package java.internal; import java.internal.IEquatable; +import haxe.ds.Vector; + private typedef StdType = Type; @:native('haxe.lang.HxObject') @@ -31,14 +33,14 @@ private class HxObject implements IHxObject @:native('haxe.lang.IHxObject') @:keep -private interface IHxObject +interface IHxObject { } @:native('haxe.lang.DynamicObject') @:replaceReflection @:keep -private class DynamicObject extends HxObject implements Dynamic +class DynamicObject extends HxObject implements Dynamic { @:skipReflection public function toString():String { @@ -64,26 +66,49 @@ private class DynamicObject extends HxObject implements Dynamic } } -@:native('haxe.lang.Enum') -//@:skipCtor -@:nativeGen -@:keep -private class Enum +@:keep @:native('haxe.lang.Enum') @:nativeGen +class HxEnum { - @:readOnly private var index:Int; - @:readOnly private var params:Array<{}>; + @:readOnly private var index(default,never):Int; + + public function new(index:Int) + { + untyped this.index = index; + } - public function new(index:Int, params:Array<{}>) + public function getTag():String { - this.index = index; - this.params = params; + return throw 'Not Implemented'; } - @:final public function getTag():String + + public function getParams():Array<{}> { - var cl:Dynamic = StdType.getEnum(cast this); - return cl.constructs[index]; + return []; } + public function toString():String + { + return getTag(); + } +} + +@:keep @:native('haxe.lang.ParamEnum') @:nativeGen +private class ParamEnum extends HxEnum +{ + @:readOnly private var params(default,never):Vector; + + public function new(index:Int, params:Vector) + { + super(index); + untyped this.params = params; + } + + override public function getParams():Array<{}> + { + return params == null ? [] : cast params.toArray(); + } + + override public function toString():String { if (params == null || params.length == 0) return getTag(); var ret = new StringBuf(); @@ -100,11 +125,12 @@ private class Enum ret.add(")"); return ret.toString(); } + public function equals(obj:Dynamic) { if (obj == this) //we cannot use == as .Equals ! return true; - var obj:Enum = cast obj; + 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; if (!ret) return false; @@ -128,7 +154,7 @@ private class Enum { h = h * 31; if (p != null) - h += untyped p.hashCode(); + untyped h += p.hashCode(); } h += index; return h; diff --git a/std/java/internal/IEquatable.hx b/std/java/internal/IEquatable.hx index cb0acf090663da638e537eb948f4791eb50ce496..d04115ac76eec6ef8d851724614d18fd04e0f919 100644 --- a/std/java/internal/IEquatable.hx +++ b/std/java/internal/IEquatable.hx @@ -1,31 +1,32 @@ -/* - * Copyright (C)2005-2012 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; - -@:native('haxe.lang.IEquatable') -@:keep -interface IEquatable -{ - - public function equals(to:Dynamic):Bool; - -} \ No newline at end of file +/* + * Copyright (C)2005-2012 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; + +@:native('haxe.lang.IEquatable') +@:keep +@:nativeGen +interface IEquatable +{ + + public function equals(to:Dynamic):Bool; + +} diff --git a/std/java/internal/Iterator.hx b/std/java/internal/Iterator.hx index cdb889146a8442611818334aa8284f6baa4e168f..98982e07d7100f64d654ab356d8bce7616990b2e 100644 --- a/std/java/internal/Iterator.hx +++ b/std/java/internal/Iterator.hx @@ -1,42 +1,42 @@ -/* - * Copyright (C)2005-2012 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; - -@:native('haxe.lang.Iterator') -@:keep -interface Iterator -{ - - public function hasNext():Bool; - - public function next():T; - -} - -@:native('haxe.lang.Iterable') -@:keep -interface Iterable -{ - - public function iterator():Iterator; - +/* + * Copyright (C)2005-2012 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; + +@:native('haxe.lang.Iterator') +@:keep +interface Iterator +{ + + public function hasNext():Bool; + + public function next():T; + +} + +@:native('haxe.lang.Iterable') +@:keep +interface Iterable +{ + + public function iterator():Iterator; + } \ No newline at end of file diff --git a/std/java/internal/Runtime.hx b/std/java/internal/Runtime.hx index 9b8aa8c7d082a5360b8a3754289f9903aa2fac92..79d696dd51e64f407ff69940c69ae461a5cdce0c 100644 --- a/std/java/internal/Runtime.hx +++ b/std/java/internal/Runtime.hx @@ -223,12 +223,12 @@ package java.internal; { long l1 = (v1 == null) ? 0L : v1c.longValue(); long l2 = (v2 == null) ? 0L : v2c.longValue(); - return (int) (l1 - l2); + return (l1 < l2) ? -1 : (l1 > l2) ? 1 : 0; } else { double d1 = (v1 == null) ? 0.0 : v1c.doubleValue(); double d2 = (v2 == null) ? 0.0 : v2c.doubleValue(); - return (int) (d1 - d2); + return (d1 < d2) ? -1 : (d1 > d2) ? 1 : 0; } } //if it\'s not a number it must be a String @@ -373,7 +373,7 @@ package java.internal; java.lang.Class[] cls = new java.lang.Class[len]; java.lang.Object[] objs = new java.lang.Object[len]; - java.lang.reflect.Method[] ms = cl.getDeclaredMethods(); + java.lang.reflect.Method[] ms = cl.getMethods(); int msl = ms.length; int realMsl = 0; for(int i =0; i < msl; i++) @@ -394,6 +394,10 @@ package java.internal; for (int i = 0; i < len; i++) { Object o = args.__get(i); + if (o == null) + { + continue; //can be anything + } objs[i]= o; cls[i] = o.getClass(); boolean isNum = false; @@ -402,6 +406,9 @@ package java.internal; { cls[i] = java.lang.Number.class; isNum = hasNumber = true; + } else if (o instanceof java.lang.Boolean) { + cls[i] = java.lang.Boolean.class; + isNum = true; } msl = realMsl; @@ -461,6 +468,9 @@ package java.internal; } else if (name.equals("short") || name.equals("java.lang.Short")) { objs[i] = ((java.lang.Number)o).shortValue(); + } else if (name.equals("long") || name.equals("java.lang.Long")) + { + objs[i] = ((java.lang.Number)o).longValue(); } } } //else varargs not handled TODO @@ -565,7 +575,7 @@ package java.internal; public static function isFinite(v:Float):Bool { - return (v == v) && !java.lang.Double._isInfinite(v); + return (v == v) && !java.lang.Double.DoubleClass._isInfinite(v); } } diff --git a/std/java/internal/StringExt.hx b/std/java/internal/StringExt.hx index 41bf0bf37522b6dc2c83f6b00cc53abc63c033b5..f2923532ffb9b8230f36096f7d92bf611a3e9dd8 100644 --- a/std/java/internal/StringExt.hx +++ b/std/java/internal/StringExt.hx @@ -169,6 +169,11 @@ private typedef NativeString = String; return null; } + public static function toString(me:NativeString):NativeString + { + return me; + } + @:functionCode(' return me.toLowerCase(); ') diff --git a/std/java/io/NativeInput.hx b/std/java/io/NativeInput.hx index c45279642dc883bf0fe48e9d7cde1c5f5fa332c3..a9dcd03d2fa1c2e32ab69888c808a2779764bc84 100644 --- a/std/java/io/NativeInput.hx +++ b/std/java/io/NativeInput.hx @@ -1,85 +1,85 @@ -/* - * Copyright (C)2005-2012 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.io; -import haxe.Int64; -import haxe.io.Bytes; -import haxe.io.Eof; -import haxe.io.Input; -import java.io.IOException; -import java.io.EOFException; - -@:native('haxe.java.io.NativeInput') class NativeInput extends Input -{ - var stream:java.io.InputStream; - public function new(stream) - { - this.stream = stream; - } - - override public function readByte():Int - { - try - { - return stream.read(); - } - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function readBytes(s:Bytes, pos:Int, len:Int):Int - { - var ret = 0; - try - { - ret = stream.read(s.getData(), pos, len); - } - - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - - if (ret == -1) - throw new Eof(); - return ret; - } - - override public function close():Void - { - try - { - stream.close(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } -} +/* + * Copyright (C)2005-2012 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.io; +import haxe.Int64; +import haxe.io.Bytes; +import haxe.io.Eof; +import haxe.io.Input; +import java.io.IOException; +import java.io.EOFException; + +@:native('haxe.java.io.NativeInput') class NativeInput extends Input +{ + var stream:java.io.InputStream; + public function new(stream) + { + this.stream = stream; + } + + override public function readByte():Int + { + var ret = 0; + try + { + ret = stream.read(); + } + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + if ( ret == -1 ) + throw new Eof(); + return ret; + } + + override public function readBytes(s:Bytes, pos:Int, len:Int):Int + { + var ret = 0; + try + { + ret = stream.read(s.getData(), pos, len); + } + + catch (e:EOFException) { + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + + if (ret == -1) + throw new Eof(); + return ret; + } + + override public function close():Void + { + try + { + stream.close(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } +} diff --git a/std/java/io/NativeOutput.hx b/std/java/io/NativeOutput.hx index 23262801bac23d770e51a0f320258207b2ead014..20ebb756b3389802454f77618ce64274630f3172 100644 --- a/std/java/io/NativeOutput.hx +++ b/std/java/io/NativeOutput.hx @@ -1,77 +1,77 @@ -/* - * Copyright (C)2005-2012 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.io; -import haxe.Int64; -import haxe.io.Bytes; -import haxe.io.Eof; -import haxe.io.Output; -import java.io.IOException; -import java.io.EOFException; - -@:native('haxe.java.io.NativeOutput') class NativeOutput extends Output -{ - var stream:java.io.OutputStream; - public function new(stream) - { - this.stream = stream; - } - - override public function writeByte(c:Int):Void - { - try - { - stream.write(c); - } - - catch (e:EOFException) { - throw new Eof(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function close():Void - { - try - { - stream.close(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } - - override public function flush():Void - { - try - { - stream.flush(); - } - - catch (e:IOException) { - throw haxe.io.Error.Custom(e); - } - } -} +/* + * Copyright (C)2005-2012 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.io; +import haxe.Int64; +import haxe.io.Bytes; +import haxe.io.Eof; +import haxe.io.Output; +import java.io.IOException; +import java.io.EOFException; + +@:native('haxe.java.io.NativeOutput') class NativeOutput extends Output +{ + var stream:java.io.OutputStream; + public function new(stream) + { + this.stream = stream; + } + + override public function writeByte(c:Int):Void + { + try + { + stream.write(c); + } + + catch (e:EOFException) { + throw new Eof(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + override public function close():Void + { + try + { + stream.close(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } + + override public function flush():Void + { + try + { + stream.flush(); + } + + catch (e:IOException) { + throw haxe.io.Error.Custom(e); + } + } +} diff --git a/std/java/lang/Boolean.hx b/std/java/lang/Boolean.hx new file mode 100644 index 0000000000000000000000000000000000000000..48448b50c1a852767c120ab471c2526ece7bedab --- /dev/null +++ b/std/java/lang/Boolean.hx @@ -0,0 +1,46 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Boolean(BooleanClass) from BooleanClass to BooleanClass +{ + @:to @:extern inline public function toBool():Bool + return this.booleanValue(); + @:from @:extern inline public static function fromBool(b:Bool):Boolean + return BooleanClass.valueOf(b); + + public static var FALSE(get,set):Boolean; + @:extern static inline function get_FALSE():Boolean return BooleanClass.FALSE; + @:extern static inline function set_FALSE(val:Boolean):Boolean return BooleanClass.FALSE = val; + public static var TRUE(get,set):Boolean; + @:extern static inline function get_TRUE():Boolean return BooleanClass.TRUE; + @:extern static inline function set_TRUE(val:Boolean):Boolean return BooleanClass.TRUE = val; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return BooleanClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return BooleanClass.TYPE = val; + @:extern @:overload inline public static function compare(param1:Bool, param2:Bool):Int return BooleanClass.compare(param1, param2); + @:extern @:overload inline public static function getBoolean(param1:String):Bool return BooleanClass.getBoolean(param1); + @:extern @:overload inline public static function parseBoolean(param1:String):Bool return BooleanClass.parseBoolean(param1); + @:extern @:overload inline public static function _toString(param1:Bool):String return BooleanClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:Bool):Boolean return BooleanClass.valueOf(param1); +} + +@:native("java.lang.Boolean") extern class BooleanClass extends Number implements Comparable +{ + @:overload public function new(bool:Bool):Void; + @:overload public function new(string:String):Void; + @:overload public function booleanValue() : Bool; + @:overload public function compareTo(param1 : Boolean) : Int; + @:overload public function compareTo(param1 : Dynamic) : Int; + @:overload public function equals(param1 : Dynamic) : Bool; + @:overload public function hashCode() : Int; + @:overload public function toString() : String; + @:final public static var FALSE : Boolean; + @:final public static var TRUE : Boolean; + @:final public static var TYPE : Class; + @:overload public static function compare(param1 : Bool, param2 : Bool) : Int; + @:overload public static function getBoolean(param1 : String) : Bool; + @:overload public static function parseBoolean(param1 : String) : Bool; + @:native("toString") @:overload public static function _toString(param1 : Bool) : String; + @:overload public static function valueOf(param1 : Bool) : Boolean; + @:overload public static function valueOf(param1 : String) : Boolean; +} diff --git a/std/java/lang/Byte.hx b/std/java/lang/Byte.hx new file mode 100644 index 0000000000000000000000000000000000000000..6e130d5018fbcff443b904a965fb6d50b095c778 --- /dev/null +++ b/std/java/lang/Byte.hx @@ -0,0 +1,51 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Byte(ByteClass) from ByteClass to ByteClass +{ + @:to @:extern inline public function toByte():java.types.Int8 + return this.byteValue(); + @:from @:extern inline public static function fromByte(b:java.types.Int8):Byte + return ByteClass.valueOf(b); + + public static var MAX_VALUE(get,never):java.types.Int8; + @:extern static inline function get_MAX_VALUE():java.types.Int8 return ByteClass.MAX_VALUE; + public static var MIN_VALUE(get,never):java.types.Int8; + @:extern static inline function get_MIN_VALUE():java.types.Int8 return ByteClass.MIN_VALUE; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return ByteClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return ByteClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return ByteClass.TYPE = val; + @:extern @:overload inline public static function compare(param1:java.types.Int8, param2:java.types.Int8):Int return ByteClass.compare(param1, param2); + @:extern @:overload inline public static function decode(param1:String):Byte return ByteClass.decode(param1); + @:extern @:overload inline public static function parseByte(param1:String, param2:Int):java.types.Int8 return ByteClass.parseByte(param1, param2); + @:extern @:overload inline public static function _toString(param1:java.types.Int8):String return ByteClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:java.types.Int8):Byte return ByteClass.valueOf(param1); +} + +@:native("java.lang.Byte") extern class ByteClass extends Number implements Comparable +{ + @:overload function new(param1 : java.types.Int8) : Void; + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function compareTo(param1 : Byte) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function toString() : String; + @:final static var MAX_VALUE(default,null) : java.types.Int8; + @:final static var MIN_VALUE(default,null) : java.types.Int8; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function compare(param1 : java.types.Int8, param2 : java.types.Int8) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function decode(param1 : String) : Byte; + @:overload @:throws("java.lang.NumberFormatException") static function parseByte(param1 : String, param2 : Int) : java.types.Int8; + @:overload @:throws("java.lang.NumberFormatException") static function parseByte(param1 : String) : java.types.Int8; + @:native("toString") @:overload static function _toString(param1 : java.types.Int8) : String; + @:overload static function valueOf(param1 : java.types.Int8) : Byte; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Byte; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Byte; +} + +@:realPath("java.lang.Byte_ByteCache") @:javaNative @:native("java.lang.Byte$ByteCache") @:javaCanonical("java.lang","Byte.ByteCache") extern class Byte_ByteCache { +} diff --git a/std/java/lang/Character.hx b/std/java/lang/Character.hx new file mode 100644 index 0000000000000000000000000000000000000000..adea71b7ab2d6864dd3f9cd61c48c334f94f4461 --- /dev/null +++ b/std/java/lang/Character.hx @@ -0,0 +1,672 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Character(CharacterClass) from CharacterClass to CharacterClass +{ + @:to @:extern inline public function toCharacter():java.types.Char16 + return this.charValue(); + @:from @:extern inline public static function fromCharacter(b:java.types.Char16):Character + return CharacterClass.valueOf(b); + + public static var COMBINING_SPACING_MARK(get,never):java.types.Char16; + @:extern static inline function get_COMBINING_SPACING_MARK():java.types.Char16 return CharacterClass.COMBINING_SPACING_MARK; + public static var CONNECTOR_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_CONNECTOR_PUNCTUATION():java.types.Char16 return CharacterClass.CONNECTOR_PUNCTUATION; + public static var CONTROL(get,never):java.types.Char16; + @:extern static inline function get_CONTROL():java.types.Char16 return CharacterClass.CONTROL; + public static var CURRENCY_SYMBOL(get,never):java.types.Char16; + @:extern static inline function get_CURRENCY_SYMBOL():java.types.Char16 return CharacterClass.CURRENCY_SYMBOL; + public static var DASH_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_DASH_PUNCTUATION():java.types.Char16 return CharacterClass.DASH_PUNCTUATION; + public static var DECIMAL_DIGIT_NUMBER(get,never):java.types.Char16; + @:extern static inline function get_DECIMAL_DIGIT_NUMBER():java.types.Char16 return CharacterClass.DECIMAL_DIGIT_NUMBER; + public static var DIRECTIONALITY_ARABIC_NUMBER(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_ARABIC_NUMBER():java.types.Char16 return CharacterClass.DIRECTIONALITY_ARABIC_NUMBER; + public static var DIRECTIONALITY_BOUNDARY_NEUTRAL(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_BOUNDARY_NEUTRAL():java.types.Char16 return CharacterClass.DIRECTIONALITY_BOUNDARY_NEUTRAL; + public static var DIRECTIONALITY_COMMON_NUMBER_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_COMMON_NUMBER_SEPARATOR():java.types.Char16 return CharacterClass.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR; + public static var DIRECTIONALITY_EUROPEAN_NUMBER(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_EUROPEAN_NUMBER():java.types.Char16 return CharacterClass.DIRECTIONALITY_EUROPEAN_NUMBER; + public static var DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR():java.types.Char16 return CharacterClass.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR; + public static var DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR():java.types.Char16 return CharacterClass.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR; + public static var DIRECTIONALITY_LEFT_TO_RIGHT(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_LEFT_TO_RIGHT():java.types.Char16 return CharacterClass.DIRECTIONALITY_LEFT_TO_RIGHT; + public static var DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING():java.types.Char16 return CharacterClass.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING; + public static var DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE():java.types.Char16 return CharacterClass.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE; + public static var DIRECTIONALITY_NONSPACING_MARK(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_NONSPACING_MARK():java.types.Char16 return CharacterClass.DIRECTIONALITY_NONSPACING_MARK; + public static var DIRECTIONALITY_OTHER_NEUTRALS(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_OTHER_NEUTRALS():java.types.Char16 return CharacterClass.DIRECTIONALITY_OTHER_NEUTRALS; + public static var DIRECTIONALITY_PARAGRAPH_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_PARAGRAPH_SEPARATOR():java.types.Char16 return CharacterClass.DIRECTIONALITY_PARAGRAPH_SEPARATOR; + public static var DIRECTIONALITY_POP_DIRECTIONAL_FORMAT(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_POP_DIRECTIONAL_FORMAT():java.types.Char16 return CharacterClass.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT; + public static var DIRECTIONALITY_RIGHT_TO_LEFT(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_RIGHT_TO_LEFT():java.types.Char16 return CharacterClass.DIRECTIONALITY_RIGHT_TO_LEFT; + public static var DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC():java.types.Char16 return CharacterClass.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC; + public static var DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING():java.types.Char16 return CharacterClass.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING; + public static var DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE():java.types.Char16 return CharacterClass.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE; + public static var DIRECTIONALITY_SEGMENT_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_SEGMENT_SEPARATOR():java.types.Char16 return CharacterClass.DIRECTIONALITY_SEGMENT_SEPARATOR; + public static var DIRECTIONALITY_UNDEFINED(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_UNDEFINED():java.types.Char16 return CharacterClass.DIRECTIONALITY_UNDEFINED; + public static var DIRECTIONALITY_WHITESPACE(get,never):java.types.Char16; + @:extern static inline function get_DIRECTIONALITY_WHITESPACE():java.types.Char16 return CharacterClass.DIRECTIONALITY_WHITESPACE; + public static var ENCLOSING_MARK(get,never):java.types.Char16; + @:extern static inline function get_ENCLOSING_MARK():java.types.Char16 return CharacterClass.ENCLOSING_MARK; + public static var END_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_END_PUNCTUATION():java.types.Char16 return CharacterClass.END_PUNCTUATION; + public static var FINAL_QUOTE_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_FINAL_QUOTE_PUNCTUATION():java.types.Char16 return CharacterClass.FINAL_QUOTE_PUNCTUATION; + public static var FORMAT(get,never):java.types.Char16; + @:extern static inline function get_FORMAT():java.types.Char16 return CharacterClass.FORMAT; + public static var INITIAL_QUOTE_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_INITIAL_QUOTE_PUNCTUATION():java.types.Char16 return CharacterClass.INITIAL_QUOTE_PUNCTUATION; + public static var LETTER_NUMBER(get,never):java.types.Char16; + @:extern static inline function get_LETTER_NUMBER():java.types.Char16 return CharacterClass.LETTER_NUMBER; + public static var LINE_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_LINE_SEPARATOR():java.types.Char16 return CharacterClass.LINE_SEPARATOR; + public static var LOWERCASE_LETTER(get,never):java.types.Char16; + @:extern static inline function get_LOWERCASE_LETTER():java.types.Char16 return CharacterClass.LOWERCASE_LETTER; + public static var MATH_SYMBOL(get,never):java.types.Char16; + @:extern static inline function get_MATH_SYMBOL():java.types.Char16 return CharacterClass.MATH_SYMBOL; + public static var MAX_CODE_POINT(get,never):Int; + @:extern static inline function get_MAX_CODE_POINT():Int return CharacterClass.MAX_CODE_POINT; + public static var MAX_HIGH_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MAX_HIGH_SURROGATE():java.types.Char16 return CharacterClass.MAX_HIGH_SURROGATE; + public static var MAX_LOW_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MAX_LOW_SURROGATE():java.types.Char16 return CharacterClass.MAX_LOW_SURROGATE; + public static var MAX_RADIX(get,never):Int; + @:extern static inline function get_MAX_RADIX():Int return CharacterClass.MAX_RADIX; + public static var MAX_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MAX_SURROGATE():java.types.Char16 return CharacterClass.MAX_SURROGATE; + public static var MAX_VALUE(get,never):java.types.Char16; + @:extern static inline function get_MAX_VALUE():java.types.Char16 return CharacterClass.MAX_VALUE; + public static var MIN_CODE_POINT(get,never):Int; + @:extern static inline function get_MIN_CODE_POINT():Int return CharacterClass.MIN_CODE_POINT; + public static var MIN_HIGH_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MIN_HIGH_SURROGATE():java.types.Char16 return CharacterClass.MIN_HIGH_SURROGATE; + public static var MIN_LOW_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MIN_LOW_SURROGATE():java.types.Char16 return CharacterClass.MIN_LOW_SURROGATE; + public static var MIN_RADIX(get,never):Int; + @:extern static inline function get_MIN_RADIX():Int return CharacterClass.MIN_RADIX; + public static var MIN_SUPPLEMENTARY_CODE_POINT(get,never):Int; + @:extern static inline function get_MIN_SUPPLEMENTARY_CODE_POINT():Int return CharacterClass.MIN_SUPPLEMENTARY_CODE_POINT; + public static var MIN_SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_MIN_SURROGATE():java.types.Char16 return CharacterClass.MIN_SURROGATE; + public static var MIN_VALUE(get,never):java.types.Char16; + @:extern static inline function get_MIN_VALUE():java.types.Char16 return CharacterClass.MIN_VALUE; + public static var MODIFIER_LETTER(get,never):java.types.Char16; + @:extern static inline function get_MODIFIER_LETTER():java.types.Char16 return CharacterClass.MODIFIER_LETTER; + public static var MODIFIER_SYMBOL(get,never):java.types.Char16; + @:extern static inline function get_MODIFIER_SYMBOL():java.types.Char16 return CharacterClass.MODIFIER_SYMBOL; + public static var NON_SPACING_MARK(get,never):java.types.Char16; + @:extern static inline function get_NON_SPACING_MARK():java.types.Char16 return CharacterClass.NON_SPACING_MARK; + public static var OTHER_LETTER(get,never):java.types.Char16; + @:extern static inline function get_OTHER_LETTER():java.types.Char16 return CharacterClass.OTHER_LETTER; + public static var OTHER_NUMBER(get,never):java.types.Char16; + @:extern static inline function get_OTHER_NUMBER():java.types.Char16 return CharacterClass.OTHER_NUMBER; + public static var OTHER_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_OTHER_PUNCTUATION():java.types.Char16 return CharacterClass.OTHER_PUNCTUATION; + public static var OTHER_SYMBOL(get,never):java.types.Char16; + @:extern static inline function get_OTHER_SYMBOL():java.types.Char16 return CharacterClass.OTHER_SYMBOL; + public static var PARAGRAPH_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_PARAGRAPH_SEPARATOR():java.types.Char16 return CharacterClass.PARAGRAPH_SEPARATOR; + public static var PRIVATE_USE(get,never):java.types.Char16; + @:extern static inline function get_PRIVATE_USE():java.types.Char16 return CharacterClass.PRIVATE_USE; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return CharacterClass.SIZE; + public static var SPACE_SEPARATOR(get,never):java.types.Char16; + @:extern static inline function get_SPACE_SEPARATOR():java.types.Char16 return CharacterClass.SPACE_SEPARATOR; + public static var START_PUNCTUATION(get,never):java.types.Char16; + @:extern static inline function get_START_PUNCTUATION():java.types.Char16 return CharacterClass.START_PUNCTUATION; + public static var SURROGATE(get,never):java.types.Char16; + @:extern static inline function get_SURROGATE():java.types.Char16 return CharacterClass.SURROGATE; + public static var TITLECASE_LETTER(get,never):java.types.Char16; + @:extern static inline function get_TITLECASE_LETTER():java.types.Char16 return CharacterClass.TITLECASE_LETTER; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return CharacterClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return CharacterClass.TYPE = val; + public static var UNASSIGNED(get,never):java.types.Char16; + @:extern static inline function get_UNASSIGNED():java.types.Char16 return CharacterClass.UNASSIGNED; + public static var UPPERCASE_LETTER(get,never):java.types.Char16; + @:extern static inline function get_UPPERCASE_LETTER():java.types.Char16 return CharacterClass.UPPERCASE_LETTER; + @:extern @:overload inline public static function charCount(param1:Int):Int return CharacterClass.charCount(param1); + @:extern @:overload inline public static function codePointAt(param1:CharSequence, param2:Int):Int return CharacterClass.codePointAt(param1, param2); + @:extern @:overload inline public static function codePointBefore(param1:CharSequence, param2:Int):Int return CharacterClass.codePointBefore(param1, param2); + @:extern @:overload inline public static function codePointCount(param1:CharSequence, param2:Int, param3:Int):Int return CharacterClass.codePointCount(param1, param2, param3); + @:extern @:overload inline public static function compare(param1:java.types.Char16, param2:java.types.Char16):Int return CharacterClass.compare(param1, param2); + @:extern @:overload inline public static function digit(param1:java.types.Char16, param2:Int):Int return CharacterClass.digit(param1, param2); + @:extern @:overload inline public static function forDigit(param1:Int, param2:Int):java.types.Char16 return CharacterClass.forDigit(param1, param2); + @:extern @:overload inline public static function getDirectionality(param1:java.types.Char16):java.types.Char16 return CharacterClass.getDirectionality(param1); + @:extern @:overload inline public static function getName(param1:Int):String return CharacterClass.getName(param1); + @:extern @:overload inline public static function getNumericValue(param1:java.types.Char16):Int return CharacterClass.getNumericValue(param1); + @:extern @:overload inline public static function getType(param1:java.types.Char16):Int return CharacterClass.getType(param1); + @:extern @:overload inline public static function highSurrogate(param1:Int):java.types.Char16 return CharacterClass.highSurrogate(param1); + @:extern @:overload inline public static function isAlphabetic(param1:Int):Bool return CharacterClass.isAlphabetic(param1); + @:extern @:overload inline public static function isBmpCodePoint(param1:Int):Bool return CharacterClass.isBmpCodePoint(param1); + @:extern @:overload inline public static function isDefined(param1:java.types.Char16):Bool return CharacterClass.isDefined(param1); + @:extern @:overload inline public static function isDigit(param1:java.types.Char16):Bool return CharacterClass.isDigit(param1); + @:extern @:overload inline public static function isHighSurrogate(param1:java.types.Char16):Bool return CharacterClass.isHighSurrogate(param1); + @:extern @:overload inline public static function isISOControl(param1:java.types.Char16):Bool return CharacterClass.isISOControl(param1); + @:extern @:overload inline public static function isIdentifierIgnorable(param1:java.types.Char16):Bool return CharacterClass.isIdentifierIgnorable(param1); + @:extern @:overload inline public static function isIdeographic(param1:Int):Bool return CharacterClass.isIdeographic(param1); + @:extern @:overload inline public static function isJavaIdentifierPart(param1:java.types.Char16):Bool return CharacterClass.isJavaIdentifierPart(param1); + @:extern @:overload inline public static function isJavaIdentifierStart(param1:java.types.Char16):Bool return CharacterClass.isJavaIdentifierStart(param1); + + + @:extern @:overload inline public static function isLetter(param1:java.types.Char16):Bool return CharacterClass.isLetter(param1); + @:extern @:overload inline public static function isLetterOrDigit(param1:java.types.Char16):Bool return CharacterClass.isLetterOrDigit(param1); + @:extern @:overload inline public static function isLowSurrogate(param1:java.types.Char16):Bool return CharacterClass.isLowSurrogate(param1); + @:extern @:overload inline public static function isLowerCase(param1:java.types.Char16):Bool return CharacterClass.isLowerCase(param1); + @:extern @:overload inline public static function isMirrored(param1:java.types.Char16):Bool return CharacterClass.isMirrored(param1); + + @:extern @:overload inline public static function isSpaceChar(param1:java.types.Char16):Bool return CharacterClass.isSpaceChar(param1); + @:extern @:overload inline public static function isSupplementaryCodePoint(param1:Int):Bool return CharacterClass.isSupplementaryCodePoint(param1); + @:extern @:overload inline public static function isSurrogate(param1:java.types.Char16):Bool return CharacterClass.isSurrogate(param1); + @:extern @:overload inline public static function isSurrogatePair(param1:java.types.Char16, param2:java.types.Char16):Bool return CharacterClass.isSurrogatePair(param1, param2); + @:extern @:overload inline public static function isTitleCase(param1:java.types.Char16):Bool return CharacterClass.isTitleCase(param1); + @:extern @:overload inline public static function isUnicodeIdentifierPart(param1:java.types.Char16):Bool return CharacterClass.isUnicodeIdentifierPart(param1); + @:extern @:overload inline public static function isUnicodeIdentifierStart(param1:java.types.Char16):Bool return CharacterClass.isUnicodeIdentifierStart(param1); + @:extern @:overload inline public static function isUpperCase(param1:java.types.Char16):Bool return CharacterClass.isUpperCase(param1); + @:extern @:overload inline public static function isValidCodePoint(param1:Int):Bool return CharacterClass.isValidCodePoint(param1); + @:extern @:overload inline public static function isWhitespace(param1:java.types.Char16):Bool return CharacterClass.isWhitespace(param1); + @:extern @:overload inline public static function lowSurrogate(param1:Int):java.types.Char16 return CharacterClass.lowSurrogate(param1); + @:extern @:overload inline public static function offsetByCodePoints(param1:CharSequence, param2:Int, param3:Int):Int return CharacterClass.offsetByCodePoints(param1, param2, param3); + @:extern @:overload inline public static function reverseBytes(param1:java.types.Char16):java.types.Char16 return CharacterClass.reverseBytes(param1); + @:extern @:overload inline public static function toChars(param1:Int, param2:java.NativeArray, param3:Int):Int return CharacterClass.toChars(param1, param2, param3); + @:extern @:overload inline public static function toCodePoint(param1:java.types.Char16, param2:java.types.Char16):Int return CharacterClass.toCodePoint(param1, param2); + @:extern @:overload inline public static function toLowerCase(param1:java.types.Char16):java.types.Char16 return CharacterClass.toLowerCase(param1); + @:extern @:overload inline public static function _toString(param1:java.types.Char16):String return CharacterClass._toString(param1); + @:extern @:overload inline public static function toTitleCase(param1:java.types.Char16):java.types.Char16 return CharacterClass.toTitleCase(param1); + @:extern @:overload inline public static function toUpperCase(param1:java.types.Char16):java.types.Char16 return CharacterClass.toUpperCase(param1); + @:extern @:overload inline public static function valueOf(param1:java.types.Char16):Character return CharacterClass.valueOf(param1); +} + +@:native("java.lang.Character") extern class CharacterClass implements Comparable +{ + @:overload function new(param1 : java.types.Char16) : Void; + @:overload function charValue() : java.types.Char16; + @:overload function compareTo(param1 : Character) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function toString() : String; + @:final static var COMBINING_SPACING_MARK(default,null) : java.types.Char16; + @:final static var CONNECTOR_PUNCTUATION(default,null) : java.types.Char16; + @:final static var CONTROL(default,null) : java.types.Char16; + @:final static var CURRENCY_SYMBOL(default,null) : java.types.Char16; + @:final static var DASH_PUNCTUATION(default,null) : java.types.Char16; + @:final static var DECIMAL_DIGIT_NUMBER(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_ARABIC_NUMBER(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_BOUNDARY_NEUTRAL(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_COMMON_NUMBER_SEPARATOR(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_EUROPEAN_NUMBER(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_LEFT_TO_RIGHT(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_NONSPACING_MARK(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_OTHER_NEUTRALS(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_PARAGRAPH_SEPARATOR(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_POP_DIRECTIONAL_FORMAT(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_RIGHT_TO_LEFT(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_SEGMENT_SEPARATOR(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_UNDEFINED(default,null) : java.types.Char16; + @:final static var DIRECTIONALITY_WHITESPACE(default,null) : java.types.Char16; + @:final static var ENCLOSING_MARK(default,null) : java.types.Char16; + @:final static var END_PUNCTUATION(default,null) : java.types.Char16; + @:final static var FINAL_QUOTE_PUNCTUATION(default,null) : java.types.Char16; + @:final static var FORMAT(default,null) : java.types.Char16; + @:final static var INITIAL_QUOTE_PUNCTUATION(default,null) : java.types.Char16; + @:final static var LETTER_NUMBER(default,null) : java.types.Char16; + @:final static var LINE_SEPARATOR(default,null) : java.types.Char16; + @:final static var LOWERCASE_LETTER(default,null) : java.types.Char16; + @:final static var MATH_SYMBOL(default,null) : java.types.Char16; + @:final static var MAX_CODE_POINT(default,null) : Int; + @:final static var MAX_HIGH_SURROGATE(default,null) : java.types.Char16; + @:final static var MAX_LOW_SURROGATE(default,null) : java.types.Char16; + @:final static var MAX_RADIX(default,null) : Int; + @:final static var MAX_SURROGATE(default,null) : java.types.Char16; + @:final static var MAX_VALUE(default,null) : java.types.Char16; + @:final static var MIN_CODE_POINT(default,null) : Int; + @:final static var MIN_HIGH_SURROGATE(default,null) : java.types.Char16; + @:final static var MIN_LOW_SURROGATE(default,null) : java.types.Char16; + @:final static var MIN_RADIX(default,null) : Int; + @:final static var MIN_SUPPLEMENTARY_CODE_POINT(default,null) : Int; + @:final static var MIN_SURROGATE(default,null) : java.types.Char16; + @:final static var MIN_VALUE(default,null) : java.types.Char16; + @:final static var MODIFIER_LETTER(default,null) : java.types.Char16; + @:final static var MODIFIER_SYMBOL(default,null) : java.types.Char16; + @:final static var NON_SPACING_MARK(default,null) : java.types.Char16; + @:final static var OTHER_LETTER(default,null) : java.types.Char16; + @:final static var OTHER_NUMBER(default,null) : java.types.Char16; + @:final static var OTHER_PUNCTUATION(default,null) : java.types.Char16; + @:final static var OTHER_SYMBOL(default,null) : java.types.Char16; + @:final static var PARAGRAPH_SEPARATOR(default,null) : java.types.Char16; + @:final static var PRIVATE_USE(default,null) : java.types.Char16; + @:final static var SIZE(default,null) : Int; + @:final static var SPACE_SEPARATOR(default,null) : java.types.Char16; + @:final static var START_PUNCTUATION(default,null) : java.types.Char16; + @:final static var SURROGATE(default,null) : java.types.Char16; + @:final static var TITLECASE_LETTER(default,null) : java.types.Char16; + @:final static var TYPE : Class; + @:final static var UNASSIGNED(default,null) : java.types.Char16; + @:final static var UPPERCASE_LETTER(default,null) : java.types.Char16; + @:overload static function charCount(param1 : Int) : Int; + @:overload static function codePointAt(param1 : CharSequence, param2 : Int) : Int; + @:overload static function codePointAt(param1 : java.NativeArray, param2 : Int, param3 : Int) : Int; + @:overload static function codePointAt(param1 : java.NativeArray, param2 : Int) : Int; + @:overload static function codePointBefore(param1 : CharSequence, param2 : Int) : Int; + @:overload static function codePointBefore(param1 : java.NativeArray, param2 : Int, param3 : Int) : Int; + @:overload static function codePointBefore(param1 : java.NativeArray, param2 : Int) : Int; + @:overload static function codePointCount(param1 : CharSequence, param2 : Int, param3 : Int) : Int; + @:overload static function codePointCount(param1 : java.NativeArray, param2 : Int, param3 : Int) : Int; + @:overload static function compare(param1 : java.types.Char16, param2 : java.types.Char16) : Int; + @:overload static function digit(param1 : java.types.Char16, param2 : Int) : Int; + @:overload static function digit(param1 : Int, param2 : Int) : Int; + @:overload static function forDigit(param1 : Int, param2 : Int) : java.types.Char16; + @:overload static function getDirectionality(param1 : java.types.Char16) : java.types.Char16; + @:overload static function getDirectionality(param1 : Int) : java.types.Char16; + @:overload static function getName(param1 : Int) : String; + @:overload static function getNumericValue(param1 : java.types.Char16) : Int; + @:overload static function getNumericValue(param1 : Int) : Int; + @:overload static function getType(param1 : java.types.Char16) : Int; + @:overload static function getType(param1 : Int) : Int; + @:overload static function highSurrogate(param1 : Int) : java.types.Char16; + @:overload static function isAlphabetic(param1 : Int) : Bool; + @:overload static function isBmpCodePoint(param1 : Int) : Bool; + @:overload static function isDefined(param1 : java.types.Char16) : Bool; + @:overload static function isDefined(param1 : Int) : Bool; + @:overload static function isDigit(param1 : java.types.Char16) : Bool; + @:overload static function isDigit(param1 : Int) : Bool; + @:overload static function isHighSurrogate(param1 : java.types.Char16) : Bool; + @:overload static function isISOControl(param1 : java.types.Char16) : Bool; + @:overload static function isISOControl(param1 : Int) : Bool; + @:overload static function isIdentifierIgnorable(param1 : java.types.Char16) : Bool; + @:overload static function isIdentifierIgnorable(param1 : Int) : Bool; + @:overload static function isIdeographic(param1 : Int) : Bool; + @:overload static function isJavaIdentifierPart(param1 : java.types.Char16) : Bool; + @:overload static function isJavaIdentifierPart(param1 : Int) : Bool; + @:overload static function isJavaIdentifierStart(param1 : java.types.Char16) : Bool; + @:overload static function isJavaIdentifierStart(param1 : Int) : Bool; + @:overload @:deprecated static function isJavaLetter(param1 : java.types.Char16) : Bool; + @:overload @:deprecated static function isJavaLetterOrDigit(param1 : java.types.Char16) : Bool; + @:overload static function isLetter(param1 : java.types.Char16) : Bool; + @:overload static function isLetter(param1 : Int) : Bool; + @:overload static function isLetterOrDigit(param1 : java.types.Char16) : Bool; + @:overload static function isLetterOrDigit(param1 : Int) : Bool; + @:overload static function isLowSurrogate(param1 : java.types.Char16) : Bool; + @:overload static function isLowerCase(param1 : java.types.Char16) : Bool; + @:overload static function isLowerCase(param1 : Int) : Bool; + @:overload static function isMirrored(param1 : java.types.Char16) : Bool; + @:overload static function isMirrored(param1 : Int) : Bool; + @:overload @:deprecated static function isSpace(param1 : java.types.Char16) : Bool; + @:overload static function isSpaceChar(param1 : java.types.Char16) : Bool; + @:overload static function isSpaceChar(param1 : Int) : Bool; + @:overload static function isSupplementaryCodePoint(param1 : Int) : Bool; + @:overload static function isSurrogate(param1 : java.types.Char16) : Bool; + @:overload static function isSurrogatePair(param1 : java.types.Char16, param2 : java.types.Char16) : Bool; + @:overload static function isTitleCase(param1 : java.types.Char16) : Bool; + @:overload static function isTitleCase(param1 : Int) : Bool; + @:overload static function isUnicodeIdentifierPart(param1 : java.types.Char16) : Bool; + @:overload static function isUnicodeIdentifierPart(param1 : Int) : Bool; + @:overload static function isUnicodeIdentifierStart(param1 : java.types.Char16) : Bool; + @:overload static function isUnicodeIdentifierStart(param1 : Int) : Bool; + @:overload static function isUpperCase(param1 : java.types.Char16) : Bool; + @:overload static function isUpperCase(param1 : Int) : Bool; + @:overload static function isValidCodePoint(param1 : Int) : Bool; + @:overload static function isWhitespace(param1 : java.types.Char16) : Bool; + @:overload static function isWhitespace(param1 : Int) : Bool; + @:overload static function lowSurrogate(param1 : Int) : java.types.Char16; + @:overload static function offsetByCodePoints(param1 : CharSequence, param2 : Int, param3 : Int) : Int; + @:overload static function offsetByCodePoints(param1 : java.NativeArray, param2 : Int, param3 : Int, param4 : Int, param5 : Int) : Int; + @:overload static function reverseBytes(param1 : java.types.Char16) : java.types.Char16; + @:overload static function toChars(param1 : Int, param2 : java.NativeArray, param3 : Int) : Int; + @:overload static function toChars(param1 : Int) : java.NativeArray; + @:overload static function toCodePoint(param1 : java.types.Char16, param2 : java.types.Char16) : Int; + @:overload static function toLowerCase(param1 : java.types.Char16) : java.types.Char16; + @:overload static function toLowerCase(param1 : Int) : Int; + @:native("toString") @:overload static function _toString(param1 : java.types.Char16) : String; + @:overload static function toTitleCase(param1 : java.types.Char16) : java.types.Char16; + @:overload static function toTitleCase(param1 : Int) : Int; + @:overload static function toUpperCase(param1 : java.types.Char16) : java.types.Char16; + @:overload static function toUpperCase(param1 : Int) : Int; + @:overload static function valueOf(param1 : java.types.Char16) : Character; +} + +@:realPath("java.lang.Character_CharacterCache") @:javaNative @:native("java.lang.Character$CharacterCache") @:javaCanonical("java.lang","Character.CharacterCache") extern class Character_CharacterCache { +} + +@:realPath("java.lang.Character_Subset") @:javaNative @:native("java.lang.Character$Subset") @:javaCanonical("java.lang","Character.Subset") extern class Character_Subset { + @:overload @:final function equals(param1 : Dynamic) : Bool; + @:overload @:final function hashCode() : Int; + @:overload @:final function toString() : String; +} + +@:realPath("java.lang.Character_UnicodeBlock") @:final @:javaNative @:native("java.lang.Character$UnicodeBlock") @:javaCanonical("java.lang","Character.UnicodeBlock") extern class Character_UnicodeBlock extends Character_Subset { + @:final static var AEGEAN_NUMBERS : Character_UnicodeBlock; + @:final static var ALCHEMICAL_SYMBOLS : Character_UnicodeBlock; + @:final static var ALPHABETIC_PRESENTATION_FORMS : Character_UnicodeBlock; + @:final static var ANCIENT_GREEK_MUSICAL_NOTATION : Character_UnicodeBlock; + @:final static var ANCIENT_GREEK_NUMBERS : Character_UnicodeBlock; + @:final static var ANCIENT_SYMBOLS : Character_UnicodeBlock; + @:final static var ARABIC : Character_UnicodeBlock; + @:final static var ARABIC_PRESENTATION_FORMS_A : Character_UnicodeBlock; + @:final static var ARABIC_PRESENTATION_FORMS_B : Character_UnicodeBlock; + @:final static var ARABIC_SUPPLEMENT : Character_UnicodeBlock; + @:final static var ARMENIAN : Character_UnicodeBlock; + @:final static var ARROWS : Character_UnicodeBlock; + @:final static var AVESTAN : Character_UnicodeBlock; + @:final static var BALINESE : Character_UnicodeBlock; + @:final static var BAMUM : Character_UnicodeBlock; + @:final static var BAMUM_SUPPLEMENT : Character_UnicodeBlock; + @:final static var BASIC_LATIN : Character_UnicodeBlock; + @:final static var BATAK : Character_UnicodeBlock; + @:final static var BENGALI : Character_UnicodeBlock; + @:final static var BLOCK_ELEMENTS : Character_UnicodeBlock; + @:final static var BOPOMOFO : Character_UnicodeBlock; + @:final static var BOPOMOFO_EXTENDED : Character_UnicodeBlock; + @:final static var BOX_DRAWING : Character_UnicodeBlock; + @:final static var BRAHMI : Character_UnicodeBlock; + @:final static var BRAILLE_PATTERNS : Character_UnicodeBlock; + @:final static var BUGINESE : Character_UnicodeBlock; + @:final static var BUHID : Character_UnicodeBlock; + @:final static var BYZANTINE_MUSICAL_SYMBOLS : Character_UnicodeBlock; + @:final static var CARIAN : Character_UnicodeBlock; + @:final static var CHAM : Character_UnicodeBlock; + @:final static var CHEROKEE : Character_UnicodeBlock; + @:final static var CJK_COMPATIBILITY : Character_UnicodeBlock; + @:final static var CJK_COMPATIBILITY_FORMS : Character_UnicodeBlock; + @:final static var CJK_COMPATIBILITY_IDEOGRAPHS : Character_UnicodeBlock; + @:final static var CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT : Character_UnicodeBlock; + @:final static var CJK_RADICALS_SUPPLEMENT : Character_UnicodeBlock; + @:final static var CJK_STROKES : Character_UnicodeBlock; + @:final static var CJK_SYMBOLS_AND_PUNCTUATION : Character_UnicodeBlock; + @:final static var CJK_UNIFIED_IDEOGRAPHS : Character_UnicodeBlock; + @:final static var CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A : Character_UnicodeBlock; + @:final static var CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B : Character_UnicodeBlock; + @:final static var CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C : Character_UnicodeBlock; + @:final static var CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D : Character_UnicodeBlock; + @:final static var COMBINING_DIACRITICAL_MARKS : Character_UnicodeBlock; + @:final static var COMBINING_DIACRITICAL_MARKS_SUPPLEMENT : Character_UnicodeBlock; + @:final static var COMBINING_HALF_MARKS : Character_UnicodeBlock; + @:final static var COMBINING_MARKS_FOR_SYMBOLS : Character_UnicodeBlock; + @:final static var COMMON_INDIC_NUMBER_FORMS : Character_UnicodeBlock; + @:final static var CONTROL_PICTURES : Character_UnicodeBlock; + @:final static var COPTIC : Character_UnicodeBlock; + @:final static var COUNTING_ROD_NUMERALS : Character_UnicodeBlock; + @:final static var CUNEIFORM : Character_UnicodeBlock; + @:final static var CUNEIFORM_NUMBERS_AND_PUNCTUATION : Character_UnicodeBlock; + @:final static var CURRENCY_SYMBOLS : Character_UnicodeBlock; + @:final static var CYPRIOT_SYLLABARY : Character_UnicodeBlock; + @:final static var CYRILLIC : Character_UnicodeBlock; + @:final static var CYRILLIC_EXTENDED_A : Character_UnicodeBlock; + @:final static var CYRILLIC_EXTENDED_B : Character_UnicodeBlock; + @:final static var CYRILLIC_SUPPLEMENTARY : Character_UnicodeBlock; + @:final static var DESERET : Character_UnicodeBlock; + @:final static var DEVANAGARI : Character_UnicodeBlock; + @:final static var DEVANAGARI_EXTENDED : Character_UnicodeBlock; + @:final static var DINGBATS : Character_UnicodeBlock; + @:final static var DOMINO_TILES : Character_UnicodeBlock; + @:final static var EGYPTIAN_HIEROGLYPHS : Character_UnicodeBlock; + @:final static var EMOTICONS : Character_UnicodeBlock; + @:final static var ENCLOSED_ALPHANUMERICS : Character_UnicodeBlock; + @:final static var ENCLOSED_ALPHANUMERIC_SUPPLEMENT : Character_UnicodeBlock; + @:final static var ENCLOSED_CJK_LETTERS_AND_MONTHS : Character_UnicodeBlock; + @:final static var ENCLOSED_IDEOGRAPHIC_SUPPLEMENT : Character_UnicodeBlock; + @:final static var ETHIOPIC : Character_UnicodeBlock; + @:final static var ETHIOPIC_EXTENDED : Character_UnicodeBlock; + @:final static var ETHIOPIC_EXTENDED_A : Character_UnicodeBlock; + @:final static var ETHIOPIC_SUPPLEMENT : Character_UnicodeBlock; + @:final static var GENERAL_PUNCTUATION : Character_UnicodeBlock; + @:final static var GEOMETRIC_SHAPES : Character_UnicodeBlock; + @:final static var GEORGIAN : Character_UnicodeBlock; + @:final static var GEORGIAN_SUPPLEMENT : Character_UnicodeBlock; + @:final static var GLAGOLITIC : Character_UnicodeBlock; + @:final static var GOTHIC : Character_UnicodeBlock; + @:final static var GREEK : Character_UnicodeBlock; + @:final static var GREEK_EXTENDED : Character_UnicodeBlock; + @:final static var GUJARATI : Character_UnicodeBlock; + @:final static var GURMUKHI : Character_UnicodeBlock; + @:final static var HALFWIDTH_AND_FULLWIDTH_FORMS : Character_UnicodeBlock; + @:final static var HANGUL_COMPATIBILITY_JAMO : Character_UnicodeBlock; + @:final static var HANGUL_JAMO : Character_UnicodeBlock; + @:final static var HANGUL_JAMO_EXTENDED_A : Character_UnicodeBlock; + @:final static var HANGUL_JAMO_EXTENDED_B : Character_UnicodeBlock; + @:final static var HANGUL_SYLLABLES : Character_UnicodeBlock; + @:final static var HANUNOO : Character_UnicodeBlock; + @:final static var HEBREW : Character_UnicodeBlock; + @:final static var HIGH_PRIVATE_USE_SURROGATES : Character_UnicodeBlock; + @:final static var HIGH_SURROGATES : Character_UnicodeBlock; + @:final static var HIRAGANA : Character_UnicodeBlock; + @:final static var IDEOGRAPHIC_DESCRIPTION_CHARACTERS : Character_UnicodeBlock; + @:final static var IMPERIAL_ARAMAIC : Character_UnicodeBlock; + @:final static var INSCRIPTIONAL_PAHLAVI : Character_UnicodeBlock; + @:final static var INSCRIPTIONAL_PARTHIAN : Character_UnicodeBlock; + @:final static var IPA_EXTENSIONS : Character_UnicodeBlock; + @:final static var JAVANESE : Character_UnicodeBlock; + @:final static var KAITHI : Character_UnicodeBlock; + @:final static var KANA_SUPPLEMENT : Character_UnicodeBlock; + @:final static var KANBUN : Character_UnicodeBlock; + @:final static var KANGXI_RADICALS : Character_UnicodeBlock; + @:final static var KANNADA : Character_UnicodeBlock; + @:final static var KATAKANA : Character_UnicodeBlock; + @:final static var KATAKANA_PHONETIC_EXTENSIONS : Character_UnicodeBlock; + @:final static var KAYAH_LI : Character_UnicodeBlock; + @:final static var KHAROSHTHI : Character_UnicodeBlock; + @:final static var KHMER : Character_UnicodeBlock; + @:final static var KHMER_SYMBOLS : Character_UnicodeBlock; + @:final static var LAO : Character_UnicodeBlock; + @:final static var LATIN_1_SUPPLEMENT : Character_UnicodeBlock; + @:final static var LATIN_EXTENDED_A : Character_UnicodeBlock; + @:final static var LATIN_EXTENDED_ADDITIONAL : Character_UnicodeBlock; + @:final static var LATIN_EXTENDED_B : Character_UnicodeBlock; + @:final static var LATIN_EXTENDED_C : Character_UnicodeBlock; + @:final static var LATIN_EXTENDED_D : Character_UnicodeBlock; + @:final static var LEPCHA : Character_UnicodeBlock; + @:final static var LETTERLIKE_SYMBOLS : Character_UnicodeBlock; + @:final static var LIMBU : Character_UnicodeBlock; + @:final static var LINEAR_B_IDEOGRAMS : Character_UnicodeBlock; + @:final static var LINEAR_B_SYLLABARY : Character_UnicodeBlock; + @:final static var LISU : Character_UnicodeBlock; + @:final static var LOW_SURROGATES : Character_UnicodeBlock; + @:final static var LYCIAN : Character_UnicodeBlock; + @:final static var LYDIAN : Character_UnicodeBlock; + @:final static var MAHJONG_TILES : Character_UnicodeBlock; + @:final static var MALAYALAM : Character_UnicodeBlock; + @:final static var MANDAIC : Character_UnicodeBlock; + @:final static var MATHEMATICAL_ALPHANUMERIC_SYMBOLS : Character_UnicodeBlock; + @:final static var MATHEMATICAL_OPERATORS : Character_UnicodeBlock; + @:final static var MEETEI_MAYEK : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_SYMBOLS : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_SYMBOLS_AND_ARROWS : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS : Character_UnicodeBlock; + @:final static var MISCELLANEOUS_TECHNICAL : Character_UnicodeBlock; + @:final static var MODIFIER_TONE_LETTERS : Character_UnicodeBlock; + @:final static var MONGOLIAN : Character_UnicodeBlock; + @:final static var MUSICAL_SYMBOLS : Character_UnicodeBlock; + @:final static var MYANMAR : Character_UnicodeBlock; + @:final static var MYANMAR_EXTENDED_A : Character_UnicodeBlock; + @:final static var NEW_TAI_LUE : Character_UnicodeBlock; + @:final static var NKO : Character_UnicodeBlock; + @:final static var NUMBER_FORMS : Character_UnicodeBlock; + @:final static var OGHAM : Character_UnicodeBlock; + @:final static var OLD_ITALIC : Character_UnicodeBlock; + @:final static var OLD_PERSIAN : Character_UnicodeBlock; + @:final static var OLD_SOUTH_ARABIAN : Character_UnicodeBlock; + @:final static var OLD_TURKIC : Character_UnicodeBlock; + @:final static var OL_CHIKI : Character_UnicodeBlock; + @:final static var OPTICAL_CHARACTER_RECOGNITION : Character_UnicodeBlock; + @:final static var ORIYA : Character_UnicodeBlock; + @:final static var OSMANYA : Character_UnicodeBlock; + @:final static var PHAGS_PA : Character_UnicodeBlock; + @:final static var PHAISTOS_DISC : Character_UnicodeBlock; + @:final static var PHOENICIAN : Character_UnicodeBlock; + @:final static var PHONETIC_EXTENSIONS : Character_UnicodeBlock; + @:final static var PHONETIC_EXTENSIONS_SUPPLEMENT : Character_UnicodeBlock; + @:final static var PLAYING_CARDS : Character_UnicodeBlock; + @:final static var PRIVATE_USE_AREA : Character_UnicodeBlock; + @:final static var REJANG : Character_UnicodeBlock; + @:final static var RUMI_NUMERAL_SYMBOLS : Character_UnicodeBlock; + @:final static var RUNIC : Character_UnicodeBlock; + @:final static var SAMARITAN : Character_UnicodeBlock; + @:final static var SAURASHTRA : Character_UnicodeBlock; + @:final static var SHAVIAN : Character_UnicodeBlock; + @:final static var SINHALA : Character_UnicodeBlock; + @:final static var SMALL_FORM_VARIANTS : Character_UnicodeBlock; + @:final static var SPACING_MODIFIER_LETTERS : Character_UnicodeBlock; + @:final static var SPECIALS : Character_UnicodeBlock; + @:final static var SUNDANESE : Character_UnicodeBlock; + @:final static var SUPERSCRIPTS_AND_SUBSCRIPTS : Character_UnicodeBlock; + @:final static var SUPPLEMENTAL_ARROWS_A : Character_UnicodeBlock; + @:final static var SUPPLEMENTAL_ARROWS_B : Character_UnicodeBlock; + @:final static var SUPPLEMENTAL_MATHEMATICAL_OPERATORS : Character_UnicodeBlock; + @:final static var SUPPLEMENTAL_PUNCTUATION : Character_UnicodeBlock; + @:final static var SUPPLEMENTARY_PRIVATE_USE_AREA_A : Character_UnicodeBlock; + @:final static var SUPPLEMENTARY_PRIVATE_USE_AREA_B : Character_UnicodeBlock; + @:deprecated @:final static var SURROGATES_AREA : Character_UnicodeBlock; + @:final static var SYLOTI_NAGRI : Character_UnicodeBlock; + @:final static var SYRIAC : Character_UnicodeBlock; + @:final static var TAGALOG : Character_UnicodeBlock; + @:final static var TAGBANWA : Character_UnicodeBlock; + @:final static var TAGS : Character_UnicodeBlock; + @:final static var TAI_LE : Character_UnicodeBlock; + @:final static var TAI_THAM : Character_UnicodeBlock; + @:final static var TAI_VIET : Character_UnicodeBlock; + @:final static var TAI_XUAN_JING_SYMBOLS : Character_UnicodeBlock; + @:final static var TAMIL : Character_UnicodeBlock; + @:final static var TELUGU : Character_UnicodeBlock; + @:final static var THAANA : Character_UnicodeBlock; + @:final static var THAI : Character_UnicodeBlock; + @:final static var TIBETAN : Character_UnicodeBlock; + @:final static var TIFINAGH : Character_UnicodeBlock; + @:final static var TRANSPORT_AND_MAP_SYMBOLS : Character_UnicodeBlock; + @:final static var UGARITIC : Character_UnicodeBlock; + @:final static var UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS : Character_UnicodeBlock; + @:final static var UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED : Character_UnicodeBlock; + @:final static var VAI : Character_UnicodeBlock; + @:final static var VARIATION_SELECTORS : Character_UnicodeBlock; + @:final static var VARIATION_SELECTORS_SUPPLEMENT : Character_UnicodeBlock; + @:final static var VEDIC_EXTENSIONS : Character_UnicodeBlock; + @:final static var VERTICAL_FORMS : Character_UnicodeBlock; + @:final static var YIJING_HEXAGRAM_SYMBOLS : Character_UnicodeBlock; + @:final static var YI_RADICALS : Character_UnicodeBlock; + @:final static var YI_SYLLABLES : Character_UnicodeBlock; + @:overload @:final static function forName(param1 : String) : Character_UnicodeBlock; + @:overload static function of(param1 : java.types.Char16) : Character_UnicodeBlock; + @:overload static function of(param1 : Int) : Character_UnicodeBlock; +} + +@:realPath("java.lang.Character_UnicodeScript") @:javaCanonical("java.lang","Character.UnicodeScript") @:native("java.lang.Character$UnicodeScript") extern enum Character_UnicodeScript { + COMMON; + LATIN; + GREEK; + CYRILLIC; + ARMENIAN; + HEBREW; + ARABIC; + SYRIAC; + THAANA; + DEVANAGARI; + BENGALI; + GURMUKHI; + GUJARATI; + ORIYA; + TAMIL; + TELUGU; + KANNADA; + MALAYALAM; + SINHALA; + THAI; + LAO; + TIBETAN; + MYANMAR; + GEORGIAN; + HANGUL; + ETHIOPIC; + CHEROKEE; + CANADIAN_ABORIGINAL; + OGHAM; + RUNIC; + KHMER; + MONGOLIAN; + HIRAGANA; + KATAKANA; + BOPOMOFO; + HAN; + YI; + OLD_ITALIC; + GOTHIC; + DESERET; + INHERITED; + TAGALOG; + HANUNOO; + BUHID; + TAGBANWA; + LIMBU; + TAI_LE; + LINEAR_B; + UGARITIC; + SHAVIAN; + OSMANYA; + CYPRIOT; + BRAILLE; + BUGINESE; + COPTIC; + NEW_TAI_LUE; + GLAGOLITIC; + TIFINAGH; + SYLOTI_NAGRI; + OLD_PERSIAN; + KHAROSHTHI; + BALINESE; + CUNEIFORM; + PHOENICIAN; + PHAGS_PA; + NKO; + SUNDANESE; + BATAK; + LEPCHA; + OL_CHIKI; + VAI; + SAURASHTRA; + KAYAH_LI; + REJANG; + LYCIAN; + CARIAN; + LYDIAN; + CHAM; + TAI_THAM; + TAI_VIET; + AVESTAN; + EGYPTIAN_HIEROGLYPHS; + SAMARITAN; + MANDAIC; + LISU; + BAMUM; + JAVANESE; + MEETEI_MAYEK; + IMPERIAL_ARAMAIC; + OLD_SOUTH_ARABIAN; + INSCRIPTIONAL_PARTHIAN; + INSCRIPTIONAL_PAHLAVI; + OLD_TURKIC; + BRAHMI; + KAITHI; + UNKNOWN; +} diff --git a/std/java/lang/Double.hx b/std/java/lang/Double.hx new file mode 100644 index 0000000000000000000000000000000000000000..0ba3bc1e985c836329a8d48035c1b52394e79c4b --- /dev/null +++ b/std/java/lang/Double.hx @@ -0,0 +1,76 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Double(DoubleClass) from DoubleClass to DoubleClass +{ + @:to @:extern inline public function toFloat():Float + return this.doubleValue(); + @:from @:extern inline public static function fromFloat(b:Float):Double + return DoubleClass.valueOf(b); + + public static var MAX_EXPONENT(get,never):Int; + @:extern static inline function get_MAX_EXPONENT():Int return DoubleClass.MAX_EXPONENT; + public static var MAX_VALUE(get,never):Float; + @:extern static inline function get_MAX_VALUE():Float return DoubleClass.MAX_VALUE; + public static var MIN_EXPONENT(get,never):Int; + @:extern static inline function get_MIN_EXPONENT():Int return DoubleClass.MIN_EXPONENT; + public static var MIN_NORMAL(get,never):Float; + @:extern static inline function get_MIN_NORMAL():Float return DoubleClass.MIN_NORMAL; + public static var MIN_VALUE(get,never):Float; + @:extern static inline function get_MIN_VALUE():Float return DoubleClass.MIN_VALUE; + public static var NEGATIVE_INFINITY(get,never):Float; + @:extern static inline function get_NEGATIVE_INFINITY():Float return DoubleClass.NEGATIVE_INFINITY; + public static var NaN(get,never):Float; + @:extern static inline function get_NaN():Float return DoubleClass.NaN; + public static var POSITIVE_INFINITY(get,never):Float; + @:extern static inline function get_POSITIVE_INFINITY():Float return DoubleClass.POSITIVE_INFINITY; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return DoubleClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return DoubleClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return DoubleClass.TYPE = val; + @:extern @:overload inline public static function compare(param1:Float, param2:Float):Int return DoubleClass.compare(param1, param2); + @:extern @:overload inline public static function doubleToLongBits(param1:Float):haxe.Int64 return DoubleClass.doubleToLongBits(param1); + @:extern @:overload inline public static function doubleToRawLongBits(param1:Float):haxe.Int64 return DoubleClass.doubleToRawLongBits(param1); + @:extern @:overload inline public static function _isInfinite(param1:Float):Bool return DoubleClass._isInfinite(param1); + @:extern @:overload inline public static function _isNaN(param1:Float):Bool return DoubleClass._isNaN(param1); + @:extern @:overload inline public static function longBitsToDouble(param1:haxe.Int64):Float return DoubleClass.longBitsToDouble(param1); + @:extern @:overload inline public static function parseDouble(param1:String):Float return DoubleClass.parseDouble(param1); + @:extern @:overload inline public static function toHexString(param1:Float):String return DoubleClass.toHexString(param1); + @:extern @:overload inline public static function _toString(param1:Float):String return DoubleClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:String):Double return DoubleClass.valueOf(param1); +} + +@:native("java.lang.Double") extern class DoubleClass extends Number implements Comparable +{ + @:overload function new(param1 : Float) : Void; + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function compareTo(param1 : Double) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function isInfinite() : Bool; + @:overload function isNaN() : Bool; + @:overload function toString() : String; + @:final static var MAX_EXPONENT(default,null) : Int; + @:final static var MAX_VALUE(default,null) : Float; + @:final static var MIN_EXPONENT(default,null) : Int; + @:final static var MIN_NORMAL(default,null) : Float; + @:final static var MIN_VALUE(default,null) : Float; + @:final static var NEGATIVE_INFINITY(default,null) : Float; + @:final static var NaN(default,null) : Float; + @:final static var POSITIVE_INFINITY(default,null) : Float; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function compare(param1 : Float, param2 : Float) : Int; + @:overload static function doubleToLongBits(param1 : Float) : haxe.Int64; + @:overload static function doubleToRawLongBits(param1 : Float) : haxe.Int64; + @:native("isInfinite") @:overload static function _isInfinite(param1 : Float) : Bool; + @:native("isNaN") @:overload static function _isNaN(param1 : Float) : Bool; + @:overload static function longBitsToDouble(param1 : haxe.Int64) : Float; + @:overload @:throws("java.lang.NumberFormatException") static function parseDouble(param1 : String) : Float; + @:overload static function toHexString(param1 : Float) : String; + @:native("toString") @:overload static function _toString(param1 : Float) : String; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Double; + @:overload static function valueOf(param1 : Float) : Double; +} diff --git a/std/java/lang/Float.hx b/std/java/lang/Float.hx new file mode 100644 index 0000000000000000000000000000000000000000..c3e62b6178a4f8e04e0f2c080ff287d1d9d69b4a --- /dev/null +++ b/std/java/lang/Float.hx @@ -0,0 +1,79 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Float(FloatClass) from FloatClass to FloatClass +{ + @:to @:extern inline public function toFloat():std.StdTypes.Float + return this.floatValue(); + @:from @:extern inline public static function fromFloat(b:std.StdTypes.Single):Float + return FloatClass.valueOf(b); + + public static var MAX_EXPONENT(get,never):Int; + @:extern static inline function get_MAX_EXPONENT():Int return FloatClass.MAX_EXPONENT; + public static var MAX_VALUE(get,never):Single; + @:extern static inline function get_MAX_VALUE():Single return FloatClass.MAX_VALUE; + public static var MIN_EXPONENT(get,never):Int; + @:extern static inline function get_MIN_EXPONENT():Int return FloatClass.MIN_EXPONENT; + public static var MIN_NORMAL(get,never):Single; + @:extern static inline function get_MIN_NORMAL():Single return FloatClass.MIN_NORMAL; + public static var MIN_VALUE(get,never):Single; + @:extern static inline function get_MIN_VALUE():Single return FloatClass.MIN_VALUE; + public static var NEGATIVE_INFINITY(get,never):Single; + @:extern static inline function get_NEGATIVE_INFINITY():Single return FloatClass.NEGATIVE_INFINITY; + public static var NaN(get,never):Single; + @:extern static inline function get_NaN():Single return FloatClass.NaN; + public static var POSITIVE_INFINITY(get,never):Single; + @:extern static inline function get_POSITIVE_INFINITY():Single return FloatClass.POSITIVE_INFINITY; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return FloatClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return FloatClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return FloatClass.TYPE = val; + @:extern @:overload inline public static function compare(param1:Single, param2:Single):Int return FloatClass.compare(param1, param2); + @:extern @:overload inline public static function floatToIntBits(param1:Single):Int return FloatClass.floatToIntBits(param1); + @:extern @:overload inline public static function floatToRawIntBits(param1:Single):Int return FloatClass.floatToRawIntBits(param1); + @:extern @:overload inline public static function intBitsToFloat(param1:Int):Single return FloatClass.intBitsToFloat(param1); + @:extern @:overload inline public static function _isInfinite(param1:Single):Bool return FloatClass._isInfinite(param1); + @:extern @:overload inline public static function _isNaN(param1:Single):Bool return FloatClass._isNaN(param1); + @:extern @:overload inline public static function parseFloat(param1:String):Single return FloatClass.parseFloat(param1); + @:extern @:overload inline public static function toHexString(param1:Single):String return FloatClass.toHexString(param1); + @:extern @:overload inline public static function _toString(param1:Single):String return FloatClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:String):Float return FloatClass.valueOf(param1); +} + +@:native("java.lang.Float") extern class FloatClass extends Number implements Comparable +{ + @:overload function new(param1 : Single) : Void; + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function new(param1 : std.StdTypes.Float) : Void; + @:overload function compareTo(param1 : Float) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function isInfinite() : Bool; + @:overload function isNaN() : Bool; + @:overload function toString() : String; + @:final static var MAX_EXPONENT(default,null) : Int; + @:final static var MAX_VALUE(default,null) : Single; + @:final static var MIN_EXPONENT(default,null) : Int; + @:final static var MIN_NORMAL(default,null) : Single; + @:final static var MIN_VALUE(default,null) : Single; + @:final static var NEGATIVE_INFINITY(default,null) : Single; + @:final static var NaN(default,null) : Single; + @:final static var POSITIVE_INFINITY(default,null) : Single; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function compare(param1 : Single, param2 : Single) : Int; + @:overload static function floatToIntBits(param1 : Single) : Int; + @:overload static function floatToRawIntBits(param1 : Single) : Int; + @:overload static function intBitsToFloat(param1 : Int) : Single; + @:native("isInfinite") @:overload static function _isInfinite(param1 : Single) : Bool; + @:native("isNaN") @:overload static function _isNaN(param1 : Single) : Bool; + @:overload @:throws("java.lang.NumberFormatException") static function parseFloat(param1 : String) : Single; + @:overload static function toHexString(param1 : Single) : String; + @:native("toString") @:overload static function _toString(param1 : Single) : String; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Float; + @:overload static function valueOf(param1 : Single) : Float; + +} + diff --git a/std/java/lang/Integer.hx b/std/java/lang/Integer.hx new file mode 100644 index 0000000000000000000000000000000000000000..b4576c24632ad4456b4210068de8b7498d89a3c4 --- /dev/null +++ b/std/java/lang/Integer.hx @@ -0,0 +1,82 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Integer(IntegerClass) from IntegerClass to IntegerClass +{ + @:to @:extern inline public function toInt():Int + return this.intValue(); + @:from @:extern inline public static function fromInt(b:Int):Integer + return IntegerClass.valueOf(b); + + public static var MAX_VALUE(get,never):Int; + @:extern static inline function get_MAX_VALUE():Int return IntegerClass.MAX_VALUE; + public static var MIN_VALUE(get,never):Int; + @:extern static inline function get_MIN_VALUE():Int return IntegerClass.MIN_VALUE; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return IntegerClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return IntegerClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return IntegerClass.TYPE = val; + @:extern @:overload inline public static function bitCount(param1:Int):Int return IntegerClass.bitCount(param1); + @:extern @:overload inline public static function compare(param1:Int, param2:Int):Int return IntegerClass.compare(param1, param2); + @:extern @:overload inline public static function decode(param1:String):Integer return IntegerClass.decode(param1); + @:extern @:overload inline public static function getInteger(param1:String):Integer return IntegerClass.getInteger(param1); + @:extern @:overload inline public static function highestOneBit(param1:Int):Int return IntegerClass.highestOneBit(param1); + @:extern @:overload inline public static function lowestOneBit(param1:Int):Int return IntegerClass.lowestOneBit(param1); + @:extern @:overload inline public static function numberOfLeadingZeros(param1:Int):Int return IntegerClass.numberOfLeadingZeros(param1); + @:extern @:overload inline public static function numberOfTrailingZeros(param1:Int):Int return IntegerClass.numberOfTrailingZeros(param1); + @:extern @:overload inline public static function parseInt(param1:String, param2:Int):Int return IntegerClass.parseInt(param1, param2); + @:extern @:overload inline public static function reverse(param1:Int):Int return IntegerClass.reverse(param1); + @:extern @:overload inline public static function reverseBytes(param1:Int):Int return IntegerClass.reverseBytes(param1); + @:extern @:overload inline public static function rotateLeft(param1:Int, param2:Int):Int return IntegerClass.rotateLeft(param1, param2); + @:extern @:overload inline public static function rotateRight(param1:Int, param2:Int):Int return IntegerClass.rotateRight(param1, param2); + @:extern @:overload inline public static function signum(param1:Int):Int return IntegerClass.signum(param1); + @:extern @:overload inline public static function toBinaryString(param1:Int):String return IntegerClass.toBinaryString(param1); + @:extern @:overload inline public static function toHexString(param1:Int):String return IntegerClass.toHexString(param1); + @:extern @:overload inline public static function toOctalString(param1:Int):String return IntegerClass.toOctalString(param1); + @:extern @:overload inline public static function _toString(param1:Int, param2:Int):String return IntegerClass._toString(param1, param2); + @:extern @:overload inline public static function valueOf(param1:String, param2:Int):Integer return IntegerClass.valueOf(param1, param2); +} + +@:native("java.lang.Integer") extern class IntegerClass extends Number implements Comparable +{ + @:overload function new(param1 : Int) : Void; + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function compareTo(param1 : Integer) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function toString() : String; + @:final static var MAX_VALUE(default,null) : Int; + @:final static var MIN_VALUE(default,null) : Int; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function bitCount(param1 : Int) : Int; + @:overload static function compare(param1 : Int, param2 : Int) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function decode(param1 : String) : Integer; + @:overload static function getInteger(param1 : String) : Integer; + @:overload static function getInteger(param1 : String, param2 : Integer) : Integer; + @:overload static function getInteger(param1 : String, param2 : Int) : Integer; + @:overload static function highestOneBit(param1 : Int) : Int; + @:overload static function lowestOneBit(param1 : Int) : Int; + @:overload static function numberOfLeadingZeros(param1 : Int) : Int; + @:overload static function numberOfTrailingZeros(param1 : Int) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function parseInt(param1 : String, param2 : Int) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function parseInt(param1 : String) : Int; + @:overload static function reverse(param1 : Int) : Int; + @:overload static function reverseBytes(param1 : Int) : Int; + @:overload static function rotateLeft(param1 : Int, param2 : Int) : Int; + @:overload static function rotateRight(param1 : Int, param2 : Int) : Int; + @:overload static function signum(param1 : Int) : Int; + @:overload static function toBinaryString(param1 : Int) : String; + @:overload static function toHexString(param1 : Int) : String; + @:overload static function toOctalString(param1 : Int) : String; + @:native("toString") @:overload static function _toString(param1 : Int, param2 : Int) : String; + @:native("toString") @:overload static function _toString(param1 : Int) : String; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Integer; + @:overload static function valueOf(param1 : Int) : Integer; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Integer; +} + +@:realPath("java.lang.Integer_IntegerCache") @:javaNative @:native("java.lang.Integer$IntegerCache") @:javaCanonical("java.lang","Integer.IntegerCache") extern class Integer_IntegerCache { +} diff --git a/std/java/lang/Long.hx b/std/java/lang/Long.hx new file mode 100644 index 0000000000000000000000000000000000000000..a14c098d04adc3c276ff1e6ac457bd3533bfd032 --- /dev/null +++ b/std/java/lang/Long.hx @@ -0,0 +1,82 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Long(LongClass) from LongClass to LongClass +{ + @:to @:extern inline public function toLong():haxe.Int64 + return this.longValue(); + @:from @:extern inline public static function fromLong(b:haxe.Int64):Long + return LongClass.valueOf(b); + + public static var MAX_VALUE(get,never):haxe.Int64; + @:extern static inline function get_MAX_VALUE():haxe.Int64 return LongClass.MAX_VALUE; + public static var MIN_VALUE(get,never):haxe.Int64; + @:extern static inline function get_MIN_VALUE():haxe.Int64 return LongClass.MIN_VALUE; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return LongClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return LongClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return LongClass.TYPE = val; + @:extern @:overload inline public static function bitCount(param1:haxe.Int64):Int return LongClass.bitCount(param1); + @:extern @:overload inline public static function compare(param1:haxe.Int64, param2:haxe.Int64):Int return LongClass.compare(param1, param2); + @:extern @:overload inline public static function decode(param1:String):Long return LongClass.decode(param1); + @:extern @:overload inline public static function getLong(param1:String, param2:Long):Long return LongClass.getLong(param1, param2); + @:extern @:overload inline public static function highestOneBit(param1:haxe.Int64):haxe.Int64 return LongClass.highestOneBit(param1); + @:extern @:overload inline public static function lowestOneBit(param1:haxe.Int64):haxe.Int64 return LongClass.lowestOneBit(param1); + @:extern @:overload inline public static function numberOfLeadingZeros(param1:haxe.Int64):Int return LongClass.numberOfLeadingZeros(param1); + @:extern @:overload inline public static function numberOfTrailingZeros(param1:haxe.Int64):Int return LongClass.numberOfTrailingZeros(param1); + @:extern @:overload inline public static function parseLong(param1:String):haxe.Int64 return LongClass.parseLong(param1); + @:extern @:overload inline public static function reverse(param1:haxe.Int64):haxe.Int64 return LongClass.reverse(param1); + @:extern @:overload inline public static function reverseBytes(param1:haxe.Int64):haxe.Int64 return LongClass.reverseBytes(param1); + @:extern @:overload inline public static function rotateLeft(param1:haxe.Int64, param2:Int):haxe.Int64 return LongClass.rotateLeft(param1, param2); + @:extern @:overload inline public static function rotateRight(param1:haxe.Int64, param2:Int):haxe.Int64 return LongClass.rotateRight(param1, param2); + @:extern @:overload inline public static function signum(param1:haxe.Int64):Int return LongClass.signum(param1); + @:extern @:overload inline public static function toBinaryString(param1:haxe.Int64):String return LongClass.toBinaryString(param1); + @:extern @:overload inline public static function toHexString(param1:haxe.Int64):String return LongClass.toHexString(param1); + @:extern @:overload inline public static function toOctalString(param1:haxe.Int64):String return LongClass.toOctalString(param1); + @:extern @:overload inline public static function _toString(param1:haxe.Int64):String return LongClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:haxe.Int64):Long return LongClass.valueOf(param1); +} + +@:native("java.lang.Long") extern class LongClass extends Number implements Comparable +{ + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function new(param1 : haxe.Int64) : Void; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function compareTo(param1 : Long) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function toString() : String; + @:final static var MAX_VALUE(default,null) : haxe.Int64; + @:final static var MIN_VALUE(default,null) : haxe.Int64; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function bitCount(param1 : haxe.Int64) : Int; + @:overload static function compare(param1 : haxe.Int64, param2 : haxe.Int64) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function decode(param1 : String) : Long; + @:overload static function getLong(param1 : String, param2 : Long) : Long; + @:overload static function getLong(param1 : String) : Long; + @:overload static function getLong(param1 : String, param2 : haxe.Int64) : Long; + @:overload static function highestOneBit(param1 : haxe.Int64) : haxe.Int64; + @:overload static function lowestOneBit(param1 : haxe.Int64) : haxe.Int64; + @:overload static function numberOfLeadingZeros(param1 : haxe.Int64) : Int; + @:overload static function numberOfTrailingZeros(param1 : haxe.Int64) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function parseLong(param1 : String) : haxe.Int64; + @:overload @:throws("java.lang.NumberFormatException") static function parseLong(param1 : String, param2 : Int) : haxe.Int64; + @:overload static function reverse(param1 : haxe.Int64) : haxe.Int64; + @:overload static function reverseBytes(param1 : haxe.Int64) : haxe.Int64; + @:overload static function rotateLeft(param1 : haxe.Int64, param2 : Int) : haxe.Int64; + @:overload static function rotateRight(param1 : haxe.Int64, param2 : Int) : haxe.Int64; + @:overload static function signum(param1 : haxe.Int64) : Int; + @:overload static function toBinaryString(param1 : haxe.Int64) : String; + @:overload static function toHexString(param1 : haxe.Int64) : String; + @:overload static function toOctalString(param1 : haxe.Int64) : String; + @:native("toString") @:overload static function _toString(param1 : haxe.Int64) : String; + @:native("toString") @:overload static function _toString(param1 : haxe.Int64, param2 : Int) : String; + @:overload static function valueOf(param1 : haxe.Int64) : Long; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Long; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Long; +} + +@:realPath("java.lang.Long_LongCache") @:javaNative @:native("java.lang.Long$LongCache") @:javaCanonical("java.lang","Long.LongCache") extern class Long_LongCache { +} diff --git a/std/java/lang/Short.hx b/std/java/lang/Short.hx new file mode 100644 index 0000000000000000000000000000000000000000..9719cfd2b0a8d3c3d091ce4ce34711deb9974254 --- /dev/null +++ b/std/java/lang/Short.hx @@ -0,0 +1,53 @@ +package java.lang; + +@:native("") // make sure the generator won't see this +@:forward abstract Short(ShortClass) from ShortClass to ShortClass +{ + @:to @:extern inline public function toShort():java.types.Int16 + return this.shortValue(); + @:from @:extern inline public static function fromShort(b:java.types.Int16):Short + return ShortClass.valueOf(b); + + public static var MAX_VALUE(get,never):java.types.Int16; + @:extern static inline function get_MAX_VALUE():java.types.Int16 return ShortClass.MAX_VALUE; + public static var MIN_VALUE(get,never):java.types.Int16; + @:extern static inline function get_MIN_VALUE():java.types.Int16 return ShortClass.MIN_VALUE; + public static var SIZE(get,never):Int; + @:extern static inline function get_SIZE():Int return ShortClass.SIZE; + public static var TYPE(get,set):Class; + @:extern static inline function get_TYPE():Class return ShortClass.TYPE; + @:extern static inline function set_TYPE(val:Class):Class return ShortClass.TYPE = val; + @:extern @:overload inline public static function compare(param1:java.types.Int16, param2:java.types.Int16):Int return ShortClass.compare(param1, param2); + @:extern @:overload inline public static function decode(param1:String):Short return ShortClass.decode(param1); + @:extern @:overload inline public static function parseShort(param1:String, param2:Int):java.types.Int16 return ShortClass.parseShort(param1, param2); + @:extern @:overload inline public static function reverseBytes(param1:java.types.Int16):java.types.Int16 return ShortClass.reverseBytes(param1); + @:extern @:overload inline public static function _toString(param1:java.types.Int16):String return ShortClass._toString(param1); + @:extern @:overload inline public static function valueOf(param1:String, param2:Int):Short return ShortClass.valueOf(param1, param2); +} + +@:native("java.lang.Short") extern class ShortClass extends Number implements Comparable +{ + @:overload function new(param1 : java.types.Int16) : Void; + @:overload @:throws("java.lang.NumberFormatException") function new(param1 : String) : Void; + @:overload function compareTo(param1 : Short) : Int; + @:overload function compareTo(param1 : Dynamic) : Int; + @:overload function equals(param1 : Dynamic) : Bool; + @:overload function hashCode() : Int; + @:overload function toString() : String; + @:final static var MAX_VALUE(default,null) : java.types.Int16; + @:final static var MIN_VALUE(default,null) : java.types.Int16; + @:final static var SIZE(default,null) : Int; + @:final static var TYPE : Class; + @:overload static function compare(param1 : java.types.Int16, param2 : java.types.Int16) : Int; + @:overload @:throws("java.lang.NumberFormatException") static function decode(param1 : String) : Short; + @:overload @:throws("java.lang.NumberFormatException") static function parseShort(param1 : String, param2 : Int) : java.types.Int16; + @:overload @:throws("java.lang.NumberFormatException") static function parseShort(param1 : String) : java.types.Int16; + @:overload static function reverseBytes(param1 : java.types.Int16) : java.types.Int16; + @:native("toString") @:overload static function _toString(param1 : java.types.Int16) : String; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Short; + @:overload static function valueOf(param1 : java.types.Int16) : Short; + @:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Short; +} + +@:realPath("java.lang.Short_ShortCache") @:javaNative @:native("java.lang.Short$ShortCache") @:javaCanonical("java.lang","Short.ShortCache") extern class Short_ShortCache { +} diff --git a/std/java/net/SslSocket.hx b/std/java/net/SslSocket.hx new file mode 100644 index 0000000000000000000000000000000000000000..6b333e258420a1e0195337ab85039f7d34d92766 --- /dev/null +++ b/std/java/net/SslSocket.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2012 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.net; + +@:native('haxe.java.net.SslSocket') class SslSocket extends sys.net.Socket { + + override private function create() : Void + { + try + { + this.sock = java.javax.net.ssl.SSLSocketFactory.getDefault().createSocket(); + this.server = java.javax.net.ssl.SSLServerSocketFactory.getDefault().createServerSocket(); + } catch(e:Dynamic) throw e; + } + +} diff --git a/std/java/vm/AtomicList.hx b/std/java/vm/AtomicList.hx new file mode 100644 index 0000000000000000000000000000000000000000..fe55d4d5d743ceebe487bdb15e9b73865432d3dc --- /dev/null +++ b/std/java/vm/AtomicList.hx @@ -0,0 +1,72 @@ +package java.vm; + +import java.util.concurrent.atomic.AtomicReference; + +/** + A lock-free queue implementation +**/ +@:native('haxe.java.vm.AtomicList') +@:nativeGen class AtomicList +{ + @:volatile @:private var head:AtomicNode; + @:volatile @:private var tail:AtomicReference>; + + public function new() + { + this.head = new AtomicNode(null); + this.head.set(new AtomicNode(null)); + this.tail = new AtomicReference(head); + } + + public function add(v:T) + { + var n = new AtomicNode(v), tail = this.tail; + var p = null; + while( !((p = tail.get()).compareAndSet(null, n)) ) + { + tail.compareAndSet(p, p.get()); + } + tail.compareAndSet(p, n); + } + + public function pop():Null + { + var p = null, pget = null, head = head; + do + { + p = head.get(); + if ( (pget = p.get()) == null) + return null; //empty + } while(!head.compareAndSet(p, pget)); + + var ret = pget.value; + pget.value = null; + return ret; + } + + public function peek() + { + var ret = head.get(); + if (ret == null) return null; //empty + return ret.value; + } + + public function peekLast() + { + return tail.get().value; + } + +} + +@:native('haxe.java.vm.AtomicNode') +@:nativeGen class AtomicNode extends AtomicReference> +{ + public var value:T; + + public function new(value) + { + super(); + this.value = value; + } + +} diff --git a/std/java/vm/Deque.hx b/std/java/vm/Deque.hx new file mode 100644 index 0000000000000000000000000000000000000000..d9282880251b093da0285d39b731e9f8667e1318 --- /dev/null +++ b/std/java/vm/Deque.hx @@ -0,0 +1,73 @@ +package java.vm; +import java.Lib; + +/** + A Lock-free Queue implementation +**/ +@:native('haxe.java.vm.Deque') +@:nativeGen class Deque +{ + @:private var head:Node; + @:private var tail:Node; + + public function new() + { + this.head = this.tail = new Node(null); + } + + public function add(i : T) + { + var n = new Node(i); + untyped __lock__(this, + { + tail.next = n; + tail = n; + try { untyped this.notify(); } catch(e:Dynamic) { throw e; } + }); + } + + public function push(i : T) + { + var n = new Node(i); + untyped __lock__(this, + { + n.next = head.next; + head.next = n; + try { untyped this.notify(); } catch(e:Dynamic) { throw e; } + }); + } + + public function pop(block : Bool) : Null + { + var ret = null; + untyped __lock__(this, { + var n = null; + do { + n = head.next; + if (n != null) + { + ret = n.value; + n.value = null; + head = n; + } else if (block) { + //block + try { untyped this.wait(); } catch(e:Dynamic) { throw e; } + } + } while( block && n == null ); + }); + return ret; + } +} + +@:native('haxe.java.vm.DequeNode') +@:nativeGen +class Node +{ + public var value:T; + public var next:Node; + + public function new(val) + { + this.value = val; + } +} diff --git a/std/java/vm/Gc.hx b/std/java/vm/Gc.hx new file mode 100644 index 0000000000000000000000000000000000000000..f6d58862e342748c35739df0dfa1a135ec6ffea6 --- /dev/null +++ b/std/java/vm/Gc.hx @@ -0,0 +1,15 @@ +package java.vm; + +@:native('haxe.java.vm.Gc') class Gc +{ + public static function run( major : Bool ) + { + java.lang.System.gc(); + } + + public static function stats() : { heap : Int, free : Int } + { + var r = java.lang.Runtime.getRuntime(); + return { heap : cast r.totalMemory(), free : cast r.freeMemory() }; + } +} diff --git a/std/java/vm/Lock.hx b/std/java/vm/Lock.hx new file mode 100644 index 0000000000000000000000000000000000000000..e7ebe3ac0b775f7fe3159882625a507b979b0400 --- /dev/null +++ b/std/java/vm/Lock.hx @@ -0,0 +1,84 @@ +package java.vm; +import java.Lib; +import java.lang.System; +using haxe.Int64; + +@:native('haxe.java.vm.Lock') class Lock +{ + @:private @:volatile var releasedCount = 0; + + /** + Creates a new lock, which is initially locked + **/ + public function new() + { + } + + /** + Waits for a lock to be released and acquire it. + If `timeout` (in seconds) is not null and expires then the returned value is false + **/ + public function wait(?timeout : Float) : Bool + { + var ret = false; + java.Lib.lock(this, + { + if (--releasedCount < 0) + { + if (timeout == null) + { + // since .notify() is asynchronous, this `while` is needed + // because there is a very remote possibility of release() awaking a thread, + // but before it releases, another thread calls wait - and since the release count + // is still positive, it will get the lock. + while( releasedCount < 0 ) + { + try + { + untyped __java__("this.wait()"); + } + catch(e:java.lang.InterruptedException) + { + } + } + } else { + var timeout:haxe.Int64 = cast timeout * 1000; + var cur = System.currentTimeMillis(), + max = cur.add(timeout); + // see above comment about this while loop + while ( releasedCount < 0 && cur.compare(max) < 0 ) + { + try + { + var t = max.sub(cur); + untyped __java__("this.wait({0})",t); + cur = System.currentTimeMillis(); + } + catch(e:java.lang.InterruptedException) + { + } + } + } + } + ret = this.releasedCount >= 0; + if (!ret) + this.releasedCount++; //timed out + }); + return ret; + } + + /** + Release a lock. The thread does not need to own the lock to be able to release it. + If a lock is released several times, it can be acquired as many times + **/ + public function release() + { + untyped __lock__(this, + { + if (++releasedCount >= 0) + { + untyped this.notify(); + } + }); + } +} diff --git a/std/java/vm/Mutex.hx b/std/java/vm/Mutex.hx new file mode 100644 index 0000000000000000000000000000000000000000..9a87876ec16b44ee6b977245f5d3fa69e324977e --- /dev/null +++ b/std/java/vm/Mutex.hx @@ -0,0 +1,41 @@ +package java.vm; +import java.util.concurrent.Semaphore; + +@:native('haxe.java.vm.Mutex') class Mutex +{ + @:private var lock:Semaphore; + + /** + Creates a mutex, which can be used to acquire a temporary lock to access some resource. + The main difference with a lock is that a mutex must always be released by the owner thread + **/ + public function new() + { + this.lock = new Semaphore(1); + } + + /** + Try to acquire the mutex, returns true if acquire or false if it's already locked by another thread. + **/ + public function tryAcquire():Bool + { + return this.lock.tryAcquire(); + } + + /** + 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 + { + this.lock.acquire(); + } + + /** + Release a mutex that has been acquired by the current thread. If the current thread does not own the mutex, an exception will be thrown + **/ + public function release():Void + { + this.lock.release(); + } +} diff --git a/std/java/vm/Thread.hx b/std/java/vm/Thread.hx new file mode 100644 index 0000000000000000000000000000000000000000..4bb31128a374bd926ed2b5453108d95f04522659 --- /dev/null +++ b/std/java/vm/Thread.hx @@ -0,0 +1,90 @@ +package java.vm; +import java.Lib; + +@:native('haxe.java.vm.Thread') class Thread +{ + + @:private static var javaThreadToHaxe = new haxe.ds.WeakMap(); + @:private static var mainJavaThread = java.lang.Thread.currentThread(); + @:private static var mainHaxeThread = { + var ret = new Thread(); + javaThreadToHaxe.set(mainJavaThread, ret); + ret; + }; + + + private static function getThread(jt:java.lang.Thread):Thread + { + if (Std.is(jt, HaxeThread)) + { + var t:HaxeThread = cast jt; + return t.threadObject; + } + else if (jt == mainJavaThread) + { + return mainHaxeThread; + } + else + { + var ret = null; + untyped __lock__(javaThreadToHaxe, { + ret = javaThreadToHaxe.get(jt); + if (ret == null) + { + ret = new Thread(); + javaThreadToHaxe.set(jt, ret); + } + + }); + return ret; + } + } + + private var messages:Deque; + + function new() + { + this.messages = new Deque(); + } + + public function sendMessage(obj:Dynamic) + { + messages.add(obj); + } + + public static function current():Thread + { + return getThread( java.lang.Thread.currentThread() ); + } + + public static function readMessage(block : Bool) : Dynamic + { + return current().messages.pop(block); + } + + public static function create(fn:Void->Void):Thread + { + var ret = new Thread(); + var t = new HaxeThread(ret, fn); + t.start(); + return ret; + } +} + +@:native('haxe.java.vm.HaxeThread') +private class HaxeThread extends java.lang.Thread +{ + public var threadObject(default, null):Thread; + private var runFunction:Void->Void; + @:overload override public function run():Void + { + runFunction(); + } + public function new(hxThread:Thread, run:Void->Void) + { + super(); + threadObject = hxThread; + runFunction = run; + setDaemon(true); + } +} diff --git a/std/java/vm/Tls.hx b/std/java/vm/Tls.hx new file mode 100644 index 0000000000000000000000000000000000000000..01fcdae5a0d0bde0a634666c790ccffdb50dba7e --- /dev/null +++ b/std/java/vm/Tls.hx @@ -0,0 +1,27 @@ +package java.vm; + +/** + Thread-local Storage implementation +**/ +@:native('haxe.java.vm.Tls') class Tls +{ + var t : java.lang.ThreadLocal; + public var value(get,set):T; + + public function new() + { + this.t = new java.lang.ThreadLocal(); + } + + inline private function get_value():T + { + return t.get(); + } + + inline private function set_value(v:T):T + { + t.set(v); + return v; + } + +} diff --git a/std/js/Boot.hx b/std/js/Boot.hx old mode 100644 new mode 100755 index 5c33f99afb7a1ce71972e34da9ab8836b7e2891f..ce9c18aae92b5e9b563a7f208367b68482d45b6a --- a/std/js/Boot.hx +++ b/std/js/Boot.hx @@ -21,6 +21,19 @@ */ package js; +private class HaxeError extends js.Error { + + var val:Dynamic; + + public function new(val:Dynamic) untyped { + super(); + this.val = __define_feature__("js.Boot.HaxeError", val); + this.message = String(val); + if (js.Error.captureStackTrace) js.Error.captureStackTrace(this, HaxeError); + } +} + +@:dox(hide) class Boot { private static function __unhtml(s : String) { @@ -41,8 +54,8 @@ class Boot { var d; if( __js__("typeof")(document) != "undefined" && (d = document.getElementById("haxe:trace")) != null ) d.innerHTML += __unhtml(msg)+"
"; - else if( __js__("typeof")(console) != "undefined" && console.log != null ) - console.log(msg); + else if( __js__("typeof console") != "undefined" && __js__("console").log != null ) + __js__("console").log(msg); #end } } @@ -67,8 +80,18 @@ class Boot { return untyped __define_feature__("js.Boot.isEnum", e.__ename__); } - static inline function getClass(o:Dynamic) : Dynamic { - return untyped __define_feature__("js.Boot.getClass", o.__class__); + static function getClass(o:Dynamic) : Dynamic { + if (Std.is(o, Array)) + return Array; + else { + var cl = untyped __define_feature__("js.Boot.getClass", o.__class__); + if (cl != null) + return cl; + var name = __nativeClassName(o); + if (name != null) + return __resolveNativeClass(name); + return null; + } } @:ifFeature("has_enum") @@ -113,7 +136,7 @@ class Boot { // strange error on IE return "???"; } - if( tostr != null && tostr != __js__("Object.toString") ) { + if( tostr != null && tostr != __js__("Object.toString") && __typeof__(tostr) == "function" ) { var s2 = o.toString(); if( s2 != "[object Object]") return s2; @@ -122,7 +145,7 @@ class Boot { var str = "{\n"; s += "\t"; var hasp = (o.hasOwnProperty != null); - __js__("for( var k in o ) { "); + __js__("for( var k in o ) {"); if( hasp && !o.hasOwnProperty(k) ) __js__("continue"); if( k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__" ) @@ -171,20 +194,23 @@ class Boot { return (untyped __js__("typeof"))(o) == "boolean"; case String: return (untyped __js__("typeof"))(o) == "string"; + case Array: + return (untyped __js__("(o instanceof Array)")) && o.__enum__ == null; case Dynamic: return true; default: if( o != null ) { - // Check if o is an instance of a Haxe class + // Check if o is an instance of a Haxe class or a native JS object if( (untyped __js__("typeof"))(cl) == "function" ) { - if( untyped __js__("o instanceof cl") ) { - if( cl == Array ) - return (o.__enum__ == null); + if( untyped __js__("o instanceof cl") ) return true; - } if( __interfLoop(getClass(o),cl) ) return true; } + else if ( (untyped __js__("typeof"))(cl) == "object" && __isNativeObj(cl) ) { + if( untyped __js__("o instanceof cl") ) + return true; + } } else { return false; } @@ -200,4 +226,25 @@ class Boot { else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t); } + static var __toStr = untyped __js__("{}.toString"); + // get native JS [[Class]] + static function __nativeClassName(o:Dynamic):String { + var name = untyped __toStr.call(o).slice(8, -1); + // exclude general Object and Function + // also exclude Math and JSON, because instanceof cannot be called on them + if (name == "Object" || name == "Function" || name == "Math" || name == "JSON") + return null; + return name; + } + + // check for usable native JS object + static function __isNativeObj(o:Dynamic):Bool { + return __nativeClassName(o) != null; + } + + // resolve native JS class in the global scope: + static function __resolveNativeClass(name:String) untyped { + return untyped Function('return typeof $name != "undefined" ? $name : null')(); + } + } diff --git a/std/js/Browser.hx b/std/js/Browser.hx index 17729ba4677f98e8f6e5b502f5651c9fa750ff8f..03bb3332e0db8dcaa3beeb67765df3e68b302bed 100644 --- a/std/js/Browser.hx +++ b/std/js/Browser.hx @@ -25,11 +25,34 @@ import js.html.Storage; import js.html.XMLHttpRequest; class Browser { + /** The global window object. */ + public static var window(get, never):js.html.Window; + inline static function get_window() return untyped __js__("window"); - public static var window(default,null) : js.html.DOMWindow = untyped __js__("typeof window != \"undefined\" ? window : null"); - public static var document(default,null) : js.html.Document = untyped __js__("typeof window != \"undefined\" ? window.document : null"); - public static var location(default,null) : js.html.Location = untyped __js__("typeof window != \"undefined\" ? window.location : null"); - public static var navigator(default,null) : js.html.Navigator = untyped __js__("typeof window != \"undefined\" ? window.navigator : null"); + /** Shortcut to Window.document. */ + public static var document(get, never):js.html.HTMLDocument; + inline static function get_document() return untyped __js__("window.document"); + + /** Shortcut to Window.location. */ + public static var location(get, never):js.html.Location; + inline static function get_location() return untyped __js__("window.location"); + + /** Shortcut to Window.navigator. */ + public static var navigator(get, never):js.html.Navigator; + inline static function get_navigator() return untyped __js__("window.navigator"); + + /** Shortcut to Window.console. */ + public static var console(get, never):js.html.Console; + inline static function get_console() return untyped __js__("window.console"); + + /** + * True if a window object exists, false otherwise. + * + * This can be used to check if the code is being executed in a non-browser + * environment such as node.js. + */ + public static var supported(get, never):Bool; + inline static function get_supported() return untyped __typeof__(window) != "undefined"; /** * Safely gets the browser's local storage, or returns null if localStorage is unsupported or @@ -76,4 +99,10 @@ class Browser { throw "Unable to create XMLHttpRequest object."; } + /** + Display an alert message box containing the given message. See also `Window.alert()`. + **/ + public static function alert( v : Dynamic ) { + @:privateAccess window.alert(Boot.__string_rec(v,"")); + } } diff --git a/std/js/Error.hx b/std/js/Error.hx new file mode 100644 index 0000000000000000000000000000000000000000..bf727f8ae0b91d24dd0267498e20651ebb7beae3 --- /dev/null +++ b/std/js/Error.hx @@ -0,0 +1,68 @@ +/* + * Copyright (C)2005-2012 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 js; + +@:native("Error") +extern class Error +{ + var message : String; + var name : String; + var stack(default,null) : String; + + function new(?message : String) : Void; +} + +@:native("EvalError") +extern class EvalError extends Error +{ + function new(?message : String) : Void; +} + +@:native("RangeError") +extern class RangeError extends Error +{ + function new(?message : String) : Void; +} + +@:native("ReferenceError") +extern class ReferenceError extends Error +{ + function new(?message : String) : Void; +} + +@:native("SyntaxError") +extern class SyntaxError extends Error +{ + function new(?message : String) : Void; +} + +@:native("TypeError") +extern class TypeError extends Error +{ + function new(?message : String) : Void; +} + +@:native("URIError") +extern class URIError extends Error +{ + function new(?message : String) : Void; +} diff --git a/std/js/JQuery.hx b/std/js/JQuery.hx index 6a5d6374be97b9f375c6d110cab61bf3141ff77c..7e7c0683fdcbadccee9bfbef0a96af93d95fa7db 100644 --- a/std/js/JQuery.hx +++ b/std/js/JQuery.hx @@ -1,407 +1,410 @@ -/* - * Copyright (C)2005-2012 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 js; - -import js.html.DOMWindow; -import js.html.Element; - -typedef JqEvent = { - var target : Element; - var currentTarget : Element; - var relatedTarget : Element; - var delegateTarget : Element; - - var type : String; - var timeStamp : Int; - - //var data : Dynamic; - //var namespace : String; - //var result : Dynamic; - - // position - var pageX : Int; - var pageY : Int; - - var wheelDelta : Int; - - // keys - var keyCode : Int; - var charCode : Int; - var shiftKey : Bool; - var ctrlKey : Bool; - var altKey : Bool; - var metaKey : Bool; - - var which : Int; - - // propagation - function isDefaultPrevented() : Bool; - function isImmediatePropagationStopped() : Bool; - function isPropationStopped() : Bool; - function preventDefault() : Void; - function stopImmediatePropagation() : Void; - function stopPropagation() : Void; -} - -extern class JQueryHelper { - @:overload(function(j:JQuery):JQuery{}) - @:overload(function(j:DOMWindow):JQuery{}) - @:overload(function(j:Element):JQuery{}) - public static inline function J( html : String ) : JQuery { - return new JQuery(html); - } - - public static var JTHIS(get, null) : JQuery; - - static inline function get_JTHIS() : JQuery { - return untyped __js__("$(this)"); - } - -} - -@:initPackage -extern class JQuery implements ArrayAccess { - - var context(default,null) : Element; - var length(default, null) : Int; - - @:overload(function(j:JQuery):Void{}) - @:overload(function(j:DOMWindow):Void{}) - @:overload(function(j:Element):Void{}) - function new( html : String ) : Void; - - // attributes - function addClass( className : String ) : JQuery; - function removeClass( ?className : String ) : JQuery; - function hasClass( className : String ) : Bool; - function toggleClass( className : String, ?addRemove : Bool ) : JQuery; - - @:overload(function(name:String,value:String):JQuery{}) - function attr( name : String ) : String; - - function removeAttr( attr : String ) : JQuery; - - @:overload(function(name:String,value:Dynamic):JQuery{}) - function prop( name : String ) : Dynamic; - - @:overload(function(prop:String,value:String):JQuery{}) - @:overload(function(map:{}):JQuery{}) - function css( prop : String ) : String; - - @:overload(function(html:String):JQuery{}) - @:overload(function(html:JQuery):JQuery{}) - function html() : String; - - @:overload(function(value:String):JQuery{}) - function val() : String; - - @:overload(function(text:String):JQuery{}) - function text() : String; - - // Size & Position - @:overload(function(value:Int):JQuery{}) - function width() : Int; - @:overload(function(value:Int):JQuery{}) - function height() : Int; - @:overload(function(value:Int):JQuery{}) - function innerWidth() : Int; - @:overload(function(value:Int):JQuery{}) - function innerHeight() : Int; - - function outerWidth( ?includeMargin : Bool ) : Int; - function outerHeight( ?includeMargin : Bool ) : Int; - - @:overload(function(value:Int):JQuery{}) - function scrollLeft() : Int; - - @:overload(function(value:Int):JQuery{}) - function scrollTop() : Int; - - @:overload(function(value: { left : Int, top : Int }):JQuery{}) - function offset() : { left : Int, top : Int }; - - function offsetParent() : JQuery; - - @:overload(function(value: { left : Int, top : Int }):JQuery{}) - function position() : { left : Int, top : Int }; - - // current group manipulation - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - @:overload(function(value:Array):JQuery{}) - function add( selector : String, ?context : JQuery ) : JQuery; - function andSelf() : JQuery; - function children( ?selector : String ) : JQuery; - function clone( ?withDataAndEvents : Bool ) : JQuery; - function closest( selector : String, ?context : JQuery ) : JQuery; - function contents() : JQuery; - - @:overload(function( f : Int -> Element -> Void ):JQuery{}) - function each( f : Void -> Void ) : JQuery; - function end() : JQuery; - function eq( index : Int ) : JQuery; - function filter( selector : String ) : JQuery; - function find( selector : String ) : JQuery; - function first() : JQuery; - function index( ?selector : String ) : Int; - function last( ?selector : String ) : JQuery; - function has( selector : String ) : JQuery; - function next( ?selector : String ) : JQuery; - function nextAll( ?selector : String ) : JQuery; - function nextUntil( ?selector : String ) : JQuery; - function parent( ?selector : String ) : JQuery; - function parents( ?selector : String ) : JQuery; - function parentsUntil( ?selector : String ) : JQuery; - @:overload(function(value:Element):JQuery{}) - function not( selector : String ) : JQuery; - function prev( ?selector : String ) : JQuery; - function prevAll( ?selector : String ) : JQuery; - function prevUntil( ?selector : String ) : JQuery; - function pushStack( elements : Array ) : JQuery; - function siblings( ?selector : String ) : JQuery; - function size() : Int; - function slice( start : Int, ?end : Int ) : JQuery; - function toArray() : Array; - - // DOM changes - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function before( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function after( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function append( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function appendTo( html : String ) : JQuery; - - function detach( ?selector : String ) : JQuery; - function empty() : JQuery; // remove all texts - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function insertBefore( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function insertAfter( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function prepend( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function prependTo( html : String ) : JQuery; - - function remove( ?selector : String ) : JQuery; - function replaceAll( selector : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function replaceWith( html : String ) : JQuery; - - function unwrap() : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function wrap( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function wrapAll( html : String ) : JQuery; - - @:overload(function(value:JQuery):JQuery{}) - @:overload(function(value:Element):JQuery{}) - function wrapInner( html : String ) : JQuery; - - // animation - @:overload(function(properties:{},?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function animate( properties : { }, ?duration : Int, ?callb : Void -> Void ) : JQuery; - - function delay( duration : Int, ?queueName : String ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function hide( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function fadeIn( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function fadeOut( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(duration:Int,opacity:Float,?easing:String,?call:Void->Void) : JQuery{}) - function fadeTo( duration : Int, opacity : Float, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function fadeToggle( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function show( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function slideDown( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function slideToggle( ?duration : Int, ?call : Void -> Void ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function slideUp( ?duration : Int, ?call : Void -> Void ) : JQuery; - - function stop( ?clearQueue : Bool, ?jumpToEnd : Bool ) : JQuery; - - @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) - function toggle( ?duration : Int, ?call : Void -> Void ) : JQuery; - - // Events - function blur( ?callb : JqEvent -> Void ) : JQuery; - function change( ?callb : JqEvent -> Void ) : JQuery; - - @:overload(function(callb:Void->Void):JQuery { } ) - @:overload(function(callb:JQuery.JqEvent->Void):JQuery{}) - @:overload(function(callb:Void->Bool):JQuery{}) - function click( ?callb : JqEvent -> Void ) : JQuery; - function dblclick( ?callb : JqEvent -> Void ) : JQuery; - function error( ?callb : JqEvent -> Void ) : JQuery; - function focus( ?callb : JqEvent -> Void ) : JQuery; - function focusin( ?callb : JqEvent -> Void ) : JQuery; - function focusout( ?callb : JqEvent -> Void ) : JQuery; - - @:overload(function(onInOut:JqEvent->Void):JQuery{}) - function hover( onIn : JqEvent -> Void, ?onOut : JqEvent -> Void ) : JQuery; - - @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) - function keydown( ?callb : JqEvent -> Void ) : JQuery; - - @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) - function keypress( ?callb : JqEvent -> Void ) : JQuery; - - @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) - function keyup( ?callb : JqEvent -> Void ) : JQuery; - - function mousedown( ?callb : JqEvent -> Void ) : JQuery; - function mouseenter( ?callb : JqEvent -> Void ) : JQuery; - function mouseleave( ?callb : JqEvent -> Void ) : JQuery; - function mouseout( ?callb : JqEvent -> Void ) : JQuery; - function mouseover( ?callb : JqEvent -> Void ) : JQuery; - function mousemove( ?callb : JqEvent -> Void ) : JQuery; - function mouseup( ?callb : JqEvent -> Void ) : JQuery; - - // AJAX overloads - @:overload(function( url:String, ?data : {}, ?callb : String -> String -> Void ) : JQuery {}) - @:overload(function( url:String, ?data : {}, ?callb : String -> Void ) : JQuery {}) - @:overload(function( url:String, ?data : {}, ?callb : Void -> Void ) : JQuery {}) - function load( ?callb : JqEvent -> Void ) : JQuery; - function ready( callb : JqEvent -> Void ) : JQuery; - function resize( ?callb : JqEvent -> Void ) : JQuery; - function scroll( ?callb : JqEvent -> Void ) : JQuery; - function select( ?callb : JqEvent -> Void ) : JQuery; - function submit( ?callb : JqEvent -> Void ) : JQuery; - function unload( ?callb : JqEvent -> Void ) : JQuery; - - function bind( events : String, callb : JqEvent -> Void ) : JQuery; - function delegate( selector : String, events : String, callb : JqEvent -> Void ) : JQuery; - function die( ?events : String, ?callb : JqEvent -> Void ) : JQuery; - function one( events : String, callb : JqEvent -> Void ) : JQuery; - function live( events : String, callb : JqEvent -> Void ) : JQuery; - function trigger( events : String ) : JQuery; - function triggerHandler( events : String ) : JQuery; - function unbind( ?events : String, ?callb : JqEvent -> Void ) : JQuery; - function undelegate( ?selector : String, ?events : String, ?callb : JqEvent -> Void ) : JQuery; - - // JQuery 1.7+ - @:overload(function(events:DynamicVoid>):JQuery{}) - function on( events : String, callb : JqEvent -> Void ) : JQuery; - - // queue - function clearQueue( ?queueName : String ) : JQuery; - function dequeue( ?queueName : String ) : JQuery; - function queue( ?queueName : String, ?callb : (Void -> Void) -> Void ) : { length : Int }; - - // ajax - // TODO - - // deferred - // TODO - - // other tools - @:overload(function(index:Int):Element{}) - function get() : Array; - - @:overload(function(j:JQuery):Bool{}) - function is( selector : String ) : Bool; - - @:overload(function() : Dynamic {}) - @:overload(function( key : String ) : Dynamic {}) - function data( key : String, value : Dynamic ) : JQuery; - function removeData( ?key : String ) : JQuery; - function serialize() : String; - function serializeArray() : Array<{ name : String, value : String }>; - //inline function map( f : JQuery -> T ) : Array { - // return untyped this["map"](function() return f(cur)).get(); - //} - - // haXe addition - @:runtime inline function iterator() : Iterator { - return untyped __define_feature__('js.JQuery.iterator', this["iterator"])(); - } - - /** - Return the current JQuery element (in a callback), similar to $(this) in JS. - **/ - static var cur(get, null) : JQuery; - - static var fx(default, null) : { off : Bool, interval : Int }; - static var browser(default, null) : { webkit : Bool, opera : Bool, msie : Bool, mozilla : Bool, version : String }; - - static function contains( parent : Element, child : Element ) : Bool; - static function noConflict( ?removeAll : Bool ) : Void; - static function parseJSON( json : String ) : Dynamic; - static function globalEval( js : String ) : Void; - - - //static function parseXML - //static function get, post - //static function getJSON, getScript, grep - //static function is*, makeArray, map, merge, noop, now, param, proxy, sub, trim, type, unique - - private static inline function get_cur() : JQuery { - return untyped __js__("$(this)"); - } - - private static function __init__() : Void untyped { - #if embed_js - if( untyped __js__("typeof($) == 'undefined'") ) - haxe.macro.Compiler.includeFile("js/jquery-latest.min.js"); - #end - var q : Dynamic = window.jQuery; - js.JQuery = q; - __feature__('js.JQuery.iterator', - q.fn.iterator = function() return { pos : 0, j : __this__, hasNext : function() return __this__.pos < __this__.j.length, next : function() return $(__this__.j[__this__.pos++]) } - ); - } -} +/* + * Copyright (C)2005-2012 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 js; + +import js.html.Window; +import js.html.Element; + +typedef JqEvent = { + var target : Element; + var currentTarget : Element; + var relatedTarget : Element; + var delegateTarget : Element; + + var type : String; + var timeStamp : Int; + + //var data : Dynamic; + //var namespace : String; + //var result : Dynamic; + + // position + var pageX : Int; + var pageY : Int; + + var wheelDelta : Int; + + // keys + var keyCode : Int; + var charCode : Int; + var shiftKey : Bool; + var ctrlKey : Bool; + var altKey : Bool; + var metaKey : Bool; + + var which : Int; + + // propagation + function isDefaultPrevented() : Bool; + function isImmediatePropagationStopped() : Bool; + function isPropagationStopped() : Bool; + function preventDefault() : Void; + function stopImmediatePropagation() : Void; + function stopPropagation() : Void; +} + +extern class JQueryHelper { + @:overload(function(j:JQuery):JQuery{}) + @:overload(function(j:Window):JQuery{}) + @:overload(function(j:Element):JQuery { } ) + + public static inline function J( html : haxe.extern.EitherType>> ) : JQuery { + return new JQuery(cast html); + } + + public static var JTHIS(get, null) : JQuery; + + static inline function get_JTHIS() : JQuery { + return new JQuery(js.Lib.nativeThis); + } + +} + +@:initPackage +extern class JQuery implements ArrayAccess { + + var context(default,null) : Element; + var length(default, null) : Int; + + @:selfCall + @:overload(function(j:JQuery):Void{}) + @:overload(function(j:Window):Void{}) + @:overload(function(j:Element):Void{}) + function new( html : String ) : Void; + + // attributes + function addClass( className : String ) : JQuery; + function removeClass( ?className : String ) : JQuery; + function hasClass( className : String ) : Bool; + function toggleClass( className : String, ?addRemove : Bool ) : JQuery; + + @:overload(function(name:String,value:String):JQuery{}) + function attr( name : String ) : String; + + function removeAttr( attr : String ) : JQuery; + + @:overload(function(name:String,value:Dynamic):JQuery{}) + function prop( name : String ) : Dynamic; + + @:overload(function(prop:String,value:String):JQuery{}) + @:overload(function(map:{}):JQuery{}) + function css( prop : String ) : String; + + @:overload(function(html:String):JQuery{}) + @:overload(function(html:JQuery):JQuery{}) + function html() : String; + + @:overload(function(value:String):JQuery{}) + function val() : String; + + @:overload(function(text:String):JQuery{}) + function text() : String; + + // Size & Position + @:overload(function(value:Int):JQuery{}) + function width() : Int; + @:overload(function(value:Int):JQuery{}) + function height() : Int; + @:overload(function(value:Int):JQuery{}) + function innerWidth() : Int; + @:overload(function(value:Int):JQuery{}) + function innerHeight() : Int; + + function outerWidth( ?includeMargin : Bool ) : Int; + function outerHeight( ?includeMargin : Bool ) : Int; + + @:overload(function(value:Int):JQuery{}) + function scrollLeft() : Int; + + @:overload(function(value:Int):JQuery{}) + function scrollTop() : Int; + + @:overload(function(value: { left : Int, top : Int }):JQuery{}) + function offset() : { left : Int, top : Int }; + + function offsetParent() : JQuery; + + @:overload(function(value: { left : Int, top : Int }):JQuery{}) + function position() : { left : Int, top : Int }; + + // current group manipulation + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + @:overload(function(value:Array):JQuery{}) + function add( selector : String, ?context : JQuery ) : JQuery; + function andSelf() : JQuery; + function children( ?selector : String ) : JQuery; + function clone( ?withDataAndEvents : Bool ) : JQuery; + function closest( selector : String, ?context : JQuery ) : JQuery; + function contents() : JQuery; + + @:overload(function( f : Int -> Element -> Void ):JQuery{}) + function each( f : Void -> Void ) : JQuery; + function end() : JQuery; + function eq( index : Int ) : JQuery; + function filter( selector : String ) : JQuery; + function find( selector : String ) : JQuery; + function first() : JQuery; + function index( ?selector : String ) : Int; + function last( ?selector : String ) : JQuery; + function has( selector : String ) : JQuery; + function next( ?selector : String ) : JQuery; + function nextAll( ?selector : String ) : JQuery; + function nextUntil( ?selector : String ) : JQuery; + function parent( ?selector : String ) : JQuery; + function parents( ?selector : String ) : JQuery; + function parentsUntil( ?selector : String ) : JQuery; + @:overload(function(value:Element):JQuery{}) + function not( selector : String ) : JQuery; + function prev( ?selector : String ) : JQuery; + function prevAll( ?selector : String ) : JQuery; + function prevUntil( ?selector : String ) : JQuery; + function pushStack( elements : Array ) : JQuery; + function siblings( ?selector : String ) : JQuery; + function size() : Int; + function slice( start : Int, ?end : Int ) : JQuery; + function toArray() : Array; + + // DOM changes + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function before( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function after( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function append( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function appendTo( html : String ) : JQuery; + + function detach( ?selector : String ) : JQuery; + function empty() : JQuery; // remove all texts + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function insertBefore( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function insertAfter( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function prepend( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function prependTo( html : String ) : JQuery; + + function remove( ?selector : String ) : JQuery; + function replaceAll( selector : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function replaceWith( html : String ) : JQuery; + + function unwrap() : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function wrap( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function wrapAll( html : String ) : JQuery; + + @:overload(function(value:JQuery):JQuery{}) + @:overload(function(value:Element):JQuery{}) + function wrapInner( html : String ) : JQuery; + + // animation + @:overload(function(properties:{},?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function animate( properties : { }, ?duration : Int, ?callb : Void -> Void ) : JQuery; + + function delay( duration : Int, ?queueName : String ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function hide( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function fadeIn( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function fadeOut( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(duration:Int,opacity:Float,?easing:String,?call:Void->Void) : JQuery{}) + function fadeTo( duration : Int, opacity : Float, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function fadeToggle( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function show( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function slideDown( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function slideToggle( ?duration : Int, ?call : Void -> Void ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function slideUp( ?duration : Int, ?call : Void -> Void ) : JQuery; + + function stop( ?clearQueue : Bool, ?jumpToEnd : Bool ) : JQuery; + + @:overload(function(?duration:Int,?easing:String,?call:Void->Void) : JQuery{}) + function toggle( ?duration : Int, ?call : Void -> Void ) : JQuery; + + // Events + function blur( ?callb : JqEvent -> Void ) : JQuery; + function change( ?callb : JqEvent -> Void ) : JQuery; + + @:overload(function(callb:Void->Void):JQuery { } ) + @:overload(function(callb:JQuery.JqEvent->Void):JQuery{}) + @:overload(function(callb:Void->Bool):JQuery{}) + function click( ?callb : JqEvent -> Void ) : JQuery; + function dblclick( ?callb : JqEvent -> Void ) : JQuery; + function error( ?callb : JqEvent -> Void ) : JQuery; + function focus( ?callb : JqEvent -> Void ) : JQuery; + function focusin( ?callb : JqEvent -> Void ) : JQuery; + function focusout( ?callb : JqEvent -> Void ) : JQuery; + + @:overload(function(onInOut:JqEvent->Void):JQuery{}) + function hover( onIn : JqEvent -> Void, ?onOut : JqEvent -> Void ) : JQuery; + + @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) + function keydown( ?callb : JqEvent -> Void ) : JQuery; + + @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) + function keypress( ?callb : JqEvent -> Void ) : JQuery; + + @:overload(function( callb : JQuery.JqEvent -> Bool ) : JQuery {}) + function keyup( ?callb : JqEvent -> Void ) : JQuery; + + function mousedown( ?callb : JqEvent -> Void ) : JQuery; + function mouseenter( ?callb : JqEvent -> Void ) : JQuery; + function mouseleave( ?callb : JqEvent -> Void ) : JQuery; + function mouseout( ?callb : JqEvent -> Void ) : JQuery; + function mouseover( ?callb : JqEvent -> Void ) : JQuery; + function mousemove( ?callb : JqEvent -> Void ) : JQuery; + function mouseup( ?callb : JqEvent -> Void ) : JQuery; + + // AJAX overloads + @:overload(function( url:String, ?data : {}, ?callb : String -> String -> Void ) : JQuery {}) + @:overload(function( url:String, ?data : {}, ?callb : String -> Void ) : JQuery {}) + @:overload(function( url:String, ?data : {}, ?callb : Void -> Void ) : JQuery {}) + function load( ?callb : JqEvent -> Void ) : JQuery; + function ready( callb : JqEvent -> Void ) : JQuery; + function resize( ?callb : JqEvent -> Void ) : JQuery; + function scroll( ?callb : JqEvent -> Void ) : JQuery; + function select( ?callb : JqEvent -> Void ) : JQuery; + function submit( ?callb : JqEvent -> Void ) : JQuery; + function unload( ?callb : JqEvent -> Void ) : JQuery; + + function bind( events : String, callb : JqEvent -> Void ) : JQuery; + function delegate( selector : String, events : String, callb : JqEvent -> Void ) : JQuery; + function die( ?events : String, ?callb : JqEvent -> Void ) : JQuery; + function one( events : String, callb : JqEvent -> Void ) : JQuery; + function live( events : String, callb : JqEvent -> Void ) : JQuery; + function trigger( events : String ) : JQuery; + function triggerHandler( events : String ) : JQuery; + function unbind( ?events : String, ?callb : JqEvent -> Void ) : JQuery; + function undelegate( ?selector : String, ?events : String, ?callb : JqEvent -> Void ) : JQuery; + + // JQuery 1.7+ + @:overload(function(events:DynamicVoid>):JQuery{}) + function on( events : String, callb : JqEvent -> Void ) : JQuery; + + // queue + function clearQueue( ?queueName : String ) : JQuery; + function dequeue( ?queueName : String ) : JQuery; + function queue( ?queueName : String, ?callb : (Void -> Void) -> Void ) : { length : Int }; + + // ajax + // TODO + + // deferred + // TODO + + // other tools + @:overload(function(index:Int):Element{}) + function get() : Array; + + @:overload(function(j:JQuery):Bool{}) + function is( selector : String ) : Bool; + + @:overload(function() : Dynamic {}) + @:overload(function( key : String ) : Dynamic {}) + function data( key : String, value : Dynamic ) : JQuery; + function removeData( ?key : String ) : JQuery; + function serialize() : String; + function serializeArray() : Array<{ name : String, value : String }>; + //inline function map( f : JQuery -> T ) : Array { + // return untyped this["map"](function() return f(cur)).get(); + //} + + // Haxe addition + @:runtime inline function iterator() : Iterator { + return untyped __define_feature__('js.JQuery.iterator', this["iterator"])(); + } + + /** + Return the current JQuery element (in a callback), similar to $(this) in JS. + **/ + static var cur(get, null) : JQuery; + + static var fx(default, null) : { off : Bool, interval : Int }; + static var browser(default, null) : { webkit : Bool, opera : Bool, msie : Bool, mozilla : Bool, version : String }; + + static function contains( parent : Element, child : Element ) : Bool; + static function noConflict( ?removeAll : Bool ) : Void; + static function parseJSON( json : String ) : Dynamic; + static function globalEval( js : String ) : Void; + + + //static function parseXML + //static function get, post + //static function getJSON, getScript, grep + //static function is*, makeArray, map, merge, noop, now, param, proxy, sub, trim, type, unique + + private static inline function get_cur() : JQuery { + return new js.JQuery(js.Lib.nativeThis); + } + + private static function __init__() : Void untyped { + #if embed_js + if( untyped __js__("typeof($) == 'undefined'") ) + haxe.macro.Compiler.includeFile("js/jquery-latest.min.js"); + #end + var q : Dynamic = (untyped js.Browser.window).jQuery; + untyped __js__("var js = js || {}"); + js.JQuery = q; + __feature__('js.JQuery.iterator', + q.fn.iterator = function() return { pos : 0, j : __this__, hasNext : function() return __this__.pos < __this__.j.length, next : function() return $(__this__.j[__this__.pos++]) } + ); + } +} diff --git a/std/js/Lib.hx b/std/js/Lib.hx index 157450260b90596b88b000a3c224f1b580ed81be..a05c292d8899222bf86ccba16d3ab0672e57b2fd 100644 --- a/std/js/Lib.hx +++ b/std/js/Lib.hx @@ -31,8 +31,10 @@ class Lib { } /** - Display an alert message box containing the given message + Display an alert message box containing the given message. + @deprecated Use Browser.alert() instead. **/ + @:deprecated("Lib.alert() is deprecated, use Browser.alert() instead") public static function alert( v : Dynamic ) { untyped __js__("alert")(js.Boot.__string_rec(v,"")); } @@ -41,4 +43,43 @@ class Lib { return untyped __js__("eval")(code); } + /** + Inserts a `require` expression that loads JavaScript object from + a module or file specified in the `module` argument. + + This is only supported in environments where `require` function + is available, such as Node.js or RequireJS. + **/ + public static inline function require( module:String ) : Dynamic { + return untyped __js__("require")(module); + } + + /** + Returns JavaScript `undefined` value. + + Note that this is only needed in very rare cases when working with external JavaScript code. + + In Haxe, `null` is used to represent the absence of a value. + **/ + public static var undefined(get,never) : Dynamic; + static inline function get_undefined() : Dynamic { + return untyped __js__("undefined"); + } + + /** + `nativeThis` is the JavaScript `this`, which is semantically different + from the Haxe `this`. Use `nativeThis` only when working with external + JavaScript code. + + In Haxe, `this` is always bound to a class instance. + In JavaScript, `this` in a function can be bound to an arbitrary + variable when the function is called using `func.call(thisObj, ...)` or + `func.apply(thisObj, [...])`. + + Read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this + **/ + public static var nativeThis(get,never) : Dynamic; + @:extern static inline function get_nativeThis() : Dynamic { + return untyped __js__("this"); + } } diff --git a/std/js/Promise.hx b/std/js/Promise.hx new file mode 100644 index 0000000000000000000000000000000000000000..694fc53d66a47141604e2a960ad340e74a3c28a3 --- /dev/null +++ b/std/js/Promise.hx @@ -0,0 +1,53 @@ +/* + * Copyright (C)2005-2015 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 js; + +import haxe.extern.EitherType; + +@:native("Promise") +extern class Promise +{ + @:overload(function(promise : Promise) : Promise {}) + @:overload(function(thenable : Thenable) : Promise {}) + static function resolve( value : T ) : Promise; + + static function reject( ?value : Dynamic ) : Promise; + + static function all( iterable : Array ) : Promise>; + + static function race( iterable : Array ) : Promise; + + /** @throws DOMError */ + function new( init : (T -> Void) -> (Dynamic -> Void) -> Void ) : Void; + + function then( ?fulfillCallback : PromiseCallback, ?rejectCallback : EitherType Void, PromiseCallback> ) : Promise; + + @:native("catch") + function catchError( rejectCallback : EitherType Void, PromiseCallback> ) : Promise; +} + +typedef PromiseCallback = EitherType TOut, T -> Promise>; + +typedef Thenable = { + then : EitherType<(T -> Void) -> (Dynamic -> Void) -> Void, (T -> Void) -> Void> +} diff --git a/std/cs/system/OperatingSystem.hx b/std/js/RegExp.hx similarity index 62% rename from std/cs/system/OperatingSystem.hx rename to std/js/RegExp.hx index ebf23868c761f402e9f1e316c99631b829811ae1..c211f08d4723849c8c866a7db6b29ac277463ef2 100644 --- a/std/cs/system/OperatingSystem.hx +++ b/std/js/RegExp.hx @@ -1,34 +1,45 @@ -/* - * Copyright (C)2005-2012 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 cs.system; - -/** - Warning: This class definition is incomplete. - In order to get most current extern definitions, install/update hxcs library with: - haxelib install hxcs - Please refer to http://lib.haxe.org/p/hxcs for more information. -**/ -@:native('System.OperatingSystem') extern class OperatingSystem -{ - var Platform(default, null):cs.system.PlatformID; - var Version(default, null):cs.system.Version; -} \ No newline at end of file +/* + * Copyright (C)2005-2014 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 js; + +/** + Native JavaScript regular expressions. + + For cross-platform regular expressions, use haxe `EReg` class or regexp literals. +**/ +@:native("RegExp") +extern class RegExp { + var global(default,null):Bool; + var ignoreCase(default,null):Bool; + var multiline(default,null):Bool; + var source(default,null):String; + var lastIndex:Int; + function new(pattern:String, ?flags:String); + function exec(str:String):Null; + function test(str:String):Bool; + function toString():String; +} + +extern class RegExpMatch extends Array { + var index:Int; + var input:String; +} diff --git a/std/js/_std/Array.hx b/std/js/_std/Array.hx index 0ab7f274be6d6d4782eed3ee0122ffc5adba82dd..af9c5ddec70668325b6ef2206e4597155900b18b 100644 --- a/std/js/_std/Array.hx +++ b/std/js/_std/Array.hx @@ -42,9 +42,23 @@ extern class Array { } inline function remove( x : T ) : Bool { - return untyped HxOverrides.remove(this,x); + return @:privateAccess HxOverrides.remove(this,x); } +#if js_es5 + function indexOf( x : T, ?fromIndex:Int ) : Int; + function lastIndexOf( x : T, ?fromIndex:Int ) : Int; + +#else + inline function indexOf( x : T, ?fromIndex:Int ) : Int { + return @:privateAccess HxOverrides.indexOf(this,x,(fromIndex!=null)?fromIndex:0); + } + + inline function lastIndexOf( x : T, ?fromIndex:Int ) : Int { + return @:privateAccess HxOverrides.lastIndexOf(this,x,(fromIndex!=null)?fromIndex:length-1); + } +#end + inline function copy() : Array { return (untyped this).slice(); } diff --git a/std/js/_std/EReg.hx b/std/js/_std/EReg.hx index 69a7f9126b16cf0221d9f5e98d08f13db7544221..30614594cce4dfa917ed4f25dee9ef201165440c 100644 --- a/std/js/_std/EReg.hx +++ b/std/js/_std/EReg.hx @@ -21,11 +21,11 @@ */ @:coreApi class EReg { - var r : Dynamic; + var r : HaxeRegExp; public function new( r : String, opt : String ) : Void { opt = opt.split("u").join(""); // 'u' (utf8) depends on page encoding - this.r = untyped __new__("RegExp",r,opt); + this.r = new HaxeRegExp(r, opt); } public function match( s : String ) : Bool { @@ -110,3 +110,9 @@ return buf.toString(); } } + +@:native("RegExp") +private extern class HaxeRegExp extends js.RegExp { + var m:js.RegExp.RegExpMatch; + var s:String; +} diff --git a/std/js/_std/HxOverrides.hx b/std/js/_std/HxOverrides.hx index 4981ce48d6984ad35c46596db04ce2e506e39bb1..eeb44934790daa15cf105ea40ffa258673c8fecc 100644 --- a/std/js/_std/HxOverrides.hx +++ b/std/js/_std/HxOverrides.hx @@ -60,11 +60,7 @@ class HxOverrides { } static function cca( s : String, index : Int ) : Null { - #if mt - var x = (cast s).cca(index); - #else var x = (cast s).charCodeAt(index); - #end if( x != x ) // fast isNaN return untyped undefined; // isNaN will still return true return x; @@ -83,17 +79,41 @@ class HxOverrides { return (untyped s).substr(pos, len); } - static function remove( a : Array, obj : T ) { - var i = 0; - var l = a.length; - while( i < l ) { - if( a[i] == obj ) { - a.splice(i,1); - return true; - } + static function indexOf( a : Array, obj : T, i : Int) { + var len = a.length; + if (i < 0) { + i += len; + if (i < 0) i = 0; + } + while (i < len) + { + if (untyped __js__("a[i] === obj")) + return i; i++; } - return false; + return -1; + } + + static function lastIndexOf( a : Array, obj : T, i : Int) { + var len = a.length; + if (i >= len) + i = len - 1; + else if (i < 0) + i += len; + while (i >= 0) + { + if (untyped __js__("a[i] === obj")) + return i; + i--; + } + return -1; + } + + static function remove( a : Array, obj : T ) { + var i = a.indexOf(obj); + if( i == -1 ) return false; + a.splice(i,1); + return true; } static function iter( a : Array ) : Iterator untyped { @@ -110,17 +130,10 @@ class HxOverrides { } static function __init__() untyped { - __feature__('HxOverrides.remove', - if( Array.prototype.indexOf ) __js__('HxOverrides').remove = function(a,o) { - var i = a.indexOf(o); - if( i == -1 ) return false; - a.splice(i,1); - return true; - } - ); - #if mt - if( String.prototype.cca == null ) String.prototype.cca = String.prototype.charCodeAt; - #end +#if !js_es5 + __feature__('HxOverrides.indexOf', if( Array.prototype.indexOf ) __js__("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)); +#end } } diff --git a/std/js/_std/Math.hx b/std/js/_std/Math.hx new file mode 100644 index 0000000000000000000000000000000000000000..9538df643698739e6d84cc2452c21fb12104ff8c --- /dev/null +++ b/std/js/_std/Math.hx @@ -0,0 +1,88 @@ +/* + * Copyright (C)2005-2012 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; + +// Can't enable @:coreApi because some fields are now inline getters +// @:coreApi +@:keepInit +extern class Math +{ + static var PI(default,null) : Float; + + static var NEGATIVE_INFINITY(get, null) : Float; + private static inline function get_NEGATIVE_INFINITY () : Float { + return -(untyped __js__("Infinity")); + } + + static var POSITIVE_INFINITY(get,null) : Float; + private static inline function get_POSITIVE_INFINITY () : Float { + return (untyped __js__("Infinity")); + } + + static var NaN(get, null) : Float; + private static inline function get_NaN () : Float { + return (untyped __js__("NaN")); + } + + static function abs(v:Float):Float; + static function acos(v:Float):Float; + static function asin(v:Float):Float; + static function atan(v:Float):Float; + static function atan2(y:Float, x:Float):Float; + static function ceil(v:Float):Int; + static function cos(v:Float):Float; + static function exp(v:Float):Float; + static function floor(v:Float):Int; + static function log(v:Float):Float; + static function max(a:Float, b:Float):Float; + static function min(a:Float, b:Float):Float; + static function pow(v:Float, exp:Float):Float; + static function random() : Float; + static function round(v:Float):Int; + static function sin(v:Float):Float; + static function sqrt(v:Float):Float; + static function tan(v:Float):Float; + + static inline function ffloor( v : Float ) : Float { + return floor(v); + } + + static inline function fceil( v : Float ) : Float { + return ceil(v); + } + + static inline function fround( v : Float ) : Float { + return round(v); + } + + static inline function isFinite( f : Float ) : Bool { + return (untyped __js__("isFinite"))(f); + } + + static inline function isNaN( f : Float ) : Bool { + return (untyped __js__("isNaN"))(f); + } + + static function __init__() : Void { + untyped __feature__("Type.resolveClass", $hxClasses["Math"] = Math); + } +} diff --git a/std/js/_std/Reflect.hx b/std/js/_std/Reflect.hx index 1914bef113bff900553dbb8db2dc0ee1cbbc6431..ce374a317ffc89b0cec459751d537241bb41c836 100644 --- a/std/js/_std/Reflect.hx +++ b/std/js/_std/Reflect.hx @@ -21,17 +21,12 @@ */ @:coreApi class Reflect { - public static function hasField( o : Dynamic, field : String ) : Bool { + public inline static function hasField( o : Dynamic, field : String ) : Bool { return untyped __js__('Object').prototype.hasOwnProperty.call(o, field); } - public inline static function field( o : Dynamic, field : String ) : Dynamic untyped { - var v = null; - try { - v = o[field]; - } catch( e : Dynamic ) { - } - return v; + public static function field( o : Dynamic, field : String ) : Dynamic { + try return untyped o[field] catch( e : Dynamic ) return null; } public inline static function setField( o : Dynamic, field : String, value : Dynamic ) : Void untyped { @@ -48,7 +43,7 @@ if( o.__properties__ && (tmp=o.__properties__["set_"+field]) ) o[tmp](value) else o[field] = __define_feature__("Reflect.setProperty",value); } - public inline static function callMethod( o : Dynamic, func : Dynamic, args : Array ) : Dynamic untyped { + public inline static function callMethod( o : Dynamic, func : haxe.Constraints.Function, args : Array ) : Dynamic untyped { return func.apply(o,args); } @@ -85,7 +80,7 @@ var t = __js__("typeof(v)"); return (t == "string" || (t == "object" && v.__enum__ == null)) || (t == "function" && (js.Boot.isClass(v) || js.Boot.isEnum(v)) != null); } - + public static function isEnumValue( v : Dynamic ) : Bool { return v != null && v.__enum__ != null; } diff --git a/std/js/_std/Std.hx b/std/js/_std/Std.hx index cbbd27bd324346affa8fa10fd6ee0353b33d013b..81c72f12a4e53461baafbd1af05d218799cc0535 100644 --- a/std/js/_std/Std.hx +++ b/std/js/_std/Std.hx @@ -28,12 +28,16 @@ import js.Boot; return untyped js.Boot.__instanceof(v,t); } + public static inline function instance( value : T, c : Class ) : S { + return untyped __instanceof__(value, c) ? cast value : null; + } + public static function string( s : Dynamic ) : String { return untyped js.Boot.__string_rec(s,""); } public static inline function int( x : Float ) : Int { - return cast(x) | 0; + return (cast x) | 0; } public static function parseInt( x : String ) : Null { @@ -46,7 +50,7 @@ import js.Boot; return cast v; } - public static function parseFloat( x : String ) : Float { + public static inline function parseFloat( x : String ) : Float { return untyped __js__("parseFloat")(x); } @@ -57,7 +61,7 @@ import js.Boot; static function __init__() : Void untyped { __feature__("js.Boot.getClass",String.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["String"] = String,String)); __feature__("js.Boot.isClass",String.__name__ = __feature__("Type.getClassName",["String"],true)); - __feature__("js.Boot.getClass",Array.prototype.__class__ = __feature__("Type.resolveClass",$hxClasses["Array"] = Array,Array)); + __feature__("Type.resolveClass",$hxClasses["Array"] = Array); __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'))); @@ -86,6 +90,8 @@ import js.Boot; __feature__("Void.*",{ var Void = __feature__("Type.resolveEnum", $hxClasses["Void"] = { __ename__ : ["Void"] }, { __ename__ : ["Void"] }); }); + +#if !js_es5 __feature__("Array.map", if( Array.prototype.map == null ) Array.prototype.map = function(f) { @@ -106,6 +112,7 @@ import js.Boot; return a; } ); +#end } } diff --git a/std/js/_std/Type.hx b/std/js/_std/Type.hx old mode 100644 new mode 100755 index 55a21bb43b4f91f418a21218597d754ed98836f9..f2949eb499b1b8a997fdeff67d01caf7d5a343be --- a/std/js/_std/Type.hx +++ b/std/js/_std/Type.hx @@ -33,10 +33,8 @@ enum ValueType { @:coreApi class Type { - public static function getClass( o : T ) : Class untyped { - if( o == null ) - return null; - return js.Boot.getClass(o); + public static inline function getClass( o : T ) : Class { + return if (o == null) null else @:privateAccess js.Boot.getClass(o); } public static function getEnum( o : EnumValue ) : Enum untyped { @@ -52,6 +50,8 @@ enum ValueType { public static function getClassName( c : Class ) : String { var a : Array = untyped c.__name__; + if (a == null) + return null; return a.join("."); } @@ -108,7 +108,7 @@ enum ValueType { } public static function createEnum( e : Enum, constr : String, ?params : Array ) : T { - var f = Reflect.field(e,constr); + var f:Dynamic = Reflect.field(e,constr); if( f == null ) throw "No such constructor "+constr; if( Reflect.isFunction(f) ) { if( params == null ) throw "Constructor "+constr+" need parameters"; @@ -139,6 +139,7 @@ enum ValueType { a.remove("__interfaces__"); a.remove("__properties__"); a.remove("__super__"); + a.remove("__meta__"); a.remove("prototype"); return a; } @@ -209,14 +210,7 @@ enum ValueType { } public static function allEnums( e : Enum ) : Array { - var all = []; - var cst : Array = untyped e.__constructs__; - for( c in cst ) { - var v = Reflect.field(e,c); - if( !Reflect.isFunction(v) ) - all.push(v); - } - return all; + return untyped e.__empty_constructs__; } } diff --git a/std/js/_std/Xml.hx b/std/js/_std/Xml.hx deleted file mode 100644 index 1d6b87894d66e9752795655891dd24ab9580a6d7..0000000000000000000000000000000000000000 --- a/std/js/_std/Xml.hx +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C)2005-2012 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. - */ -enum XmlType { -} - -@:coreApi class Xml { - - public static var Element(default,null) : XmlType; - public static var PCData(default,null) : XmlType; - public static var CData(default,null) : XmlType; - public static var Comment(default,null) : XmlType; - public static var DocType(default,null) : XmlType; - public static var ProcessingInstruction(default,null) : XmlType; - public static var Document(default,null) : XmlType; - - public var nodeType(default,null) : XmlType; - public var nodeName(get,set) : String; - public var nodeValue(get,set) : String; - public var parent(get,null) : Xml; - - var _nodeName : String; - var _nodeValue : String; - var _attributes : haxe.ds.StringMap; - var _children : Array; - var _parent : Xml; - - public static function parse( str : String ) : Xml { - return haxe.xml.Parser.parse(str); - } - - private function new() : Void { - } - - public static function createElement( name : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Element; - r._children = new Array(); - r._attributes = new haxe.ds.StringMap(); - r.set_nodeName( name ); - return r; - } - - public static function createPCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.PCData; - r.set_nodeValue( data ); - return r; - } - - public static function createCData( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.CData; - r.set_nodeValue( data ); - return r; - } - - public static function createComment( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.Comment; - r.set_nodeValue( data ); - return r; - } - - public static function createDocType( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.DocType; - r.set_nodeValue( data ); - return r; - } - - public static function createProcessingInstruction( data : String ) : Xml { - var r = new Xml(); - r.nodeType = Xml.ProcessingInstruction; - r.set_nodeValue( data ); - return r; - } - - public static function createDocument() : Xml { - var r = new Xml(); - r.nodeType = Xml.Document; - r._children = new Array(); - return r; - } - - private function get_nodeName() : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName; - } - - private function set_nodeName( n : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _nodeName = n; - } - - private function get_nodeValue() : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue; - } - - private function set_nodeValue( v : String ) : String { - if( nodeType == Xml.Element || nodeType == Xml.Document ) - throw "bad nodeType"; - return _nodeValue = v; - } - - private function get_parent() : Xml { - return _parent; - } - - public function get( att : String ) : String { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.get( att ); - } - - public function set( att : String, value : String ) : Void { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.set( att, value ); - } - - public function remove( att : String ) : Void{ - if( nodeType != Xml.Element ) - throw "bad nodeType"; - _attributes.remove( att ); - } - - public function exists( att : String ) : Bool { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.exists( att ); - } - - public function attributes() : Iterator { - if( nodeType != Xml.Element ) - throw "bad nodeType"; - return _attributes.keys(); - } - - public function iterator() : Iterator { - if( _children == null ) throw "bad nodetype"; - return untyped { - cur: 0, - x: this._children, - hasNext : function(){ - return __this__.cur < __this__.x.length; - }, - next : function(){ - return __this__.x[__this__.cur++]; - } - } - } - - public function elements() : Iterator { - if( _children == null ) throw "bad nodetype"; - return untyped { - cur: 0, - x: this._children, - hasNext : function() { - var k = __this__.cur; - var l = __this__.x.length; - while( k < l ) { - if( __this__.x[k].nodeType == Xml.Element ) - break; - k += 1; - } - __this__.cur = k; - return k < l; - }, - next : function() { - var k = __this__.cur; - var l = __this__.x.length; - while( k < l ) { - var n = __this__.x[k]; - k += 1; - if( n.nodeType == Xml.Element ) { - __this__.cur = k; - return n; - } - } - return null; - } - } - } - - public function elementsNamed( name : String ) : Iterator { - if( _children == null ) throw "bad nodetype"; - return untyped { - cur: 0, - x: this._children, - hasNext : function() { - var k = __this__.cur; - var l = __this__.x.length; - while( k < l ) { - var n = __this__.x[k]; - if( n.nodeType == Xml.Element && n._nodeName == name ) - break; - k++; - } - __this__.cur = k; - return k < l; - }, - next : function() { - var k = __this__.cur; - var l = __this__.x.length; - while( k < l ) { - var n = __this__.x[k]; - k++; - if( n.nodeType == Xml.Element && n._nodeName == name ) { - __this__.cur = k; - return n; - } - } - return null; - } - } - } - - public function firstChild() : Xml { - if( _children == null ) throw "bad nodetype"; - return _children[0]; - } - - public function firstElement() : Xml { - if( _children == null ) throw "bad nodetype"; - var cur = 0; - var l = _children.length; - while( cur < l ) { - var n = _children[cur]; - if( n.nodeType == Xml.Element ) - return n; - cur++; - } - return null; - } - - public function addChild( x : Xml ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.push( x ); - } - - public function removeChild( x : Xml ) : Bool { - if( _children == null ) throw "bad nodetype"; - var b = _children.remove( x ); - if( b ) - x._parent = null; - return b; - } - - public function insertChild( x : Xml, pos : Int ) : Void { - if( _children == null ) throw "bad nodetype"; - if( x._parent != null ) x._parent._children.remove(x); - x._parent = this; - _children.insert( pos, x ); - } - - public function toString() : String { - if( nodeType == Xml.PCData ) - return StringTools.htmlEscape(_nodeValue); - if( nodeType == Xml.CData ) - return ""; - if( nodeType == Xml.Comment ) - return ""; - if( nodeType == Xml.DocType ) - return ""; - if( nodeType == Xml.ProcessingInstruction ) - return ""; - var s = new StringBuf(); - - if( nodeType == Xml.Element ) { - s.add("<"); - s.add(_nodeName); - for( k in _attributes.keys() ){ - s.add(" "); - s.add(k); - s.add("=\""); - s.add(_attributes.get(k)); - s.add("\""); - } - if( _children.length == 0 ) { - s.add("/>"); - return s.toString(); - } - s.add(">"); - } - - for( x in iterator() ) - s.add(x.toString()); - - if( nodeType == Xml.Element ) { - s.add(""); - } - return s.toString(); - } - - static function __init__() : Void untyped { - Xml.Element = "element"; - Xml.PCData = "pcdata"; - Xml.CData = "cdata"; - Xml.Comment = "comment"; - Xml.DocType = "doctype"; - Xml.ProcessingInstruction = "processingInstruction"; - Xml.Document = "document"; - } - -} diff --git a/std/js/_std/haxe/Json.hx b/std/js/_std/haxe/Json.hx new file mode 100644 index 0000000000000000000000000000000000000000..0d2bd41230a12259dcf96efe4b0f81efccb4fb42 --- /dev/null +++ b/std/js/_std/haxe/Json.hx @@ -0,0 +1,47 @@ +/* + * Copyright (C)2005-2012 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 +#if (!haxeJSON && !old_browser) +@:native("JSON") extern +#end +class Json { + + #if haxeJSON inline #end + public static function parse( text : String ) : Dynamic { + return haxe.format.JsonParser.parse(text); + } + + #if haxeJSON inline #end + public static function stringify( value : Dynamic, ?replacer:Dynamic -> Dynamic -> Dynamic, ?space:String ) : String { + return haxe.format.JsonPrinter.print(value, replacer, space); + } + + #if (!haxeJSON && old_browser) + static function __init__():Void untyped { + if( __js__('typeof(JSON)') != 'undefined' ) + Json = __js__('JSON'); + } + #end + +} diff --git a/std/js/_std/haxe/ds/IntMap.hx b/std/js/_std/haxe/ds/IntMap.hx index 013dda02a8d06eec26f83725e8b8a59731f702bf..6f9fd0e812da0f880ebdf50e3082c5f0f8a7e174 100644 --- a/std/js/_std/haxe/ds/IntMap.hx +++ b/std/js/_std/haxe/ds/IntMap.hx @@ -21,23 +21,23 @@ */ package haxe.ds; -@:coreApi class IntMap implements Map.IMap { +@:coreApi class IntMap implements haxe.Constraints.IMap { private var h : Dynamic; - public function new() : Void { + public inline function new() : Void { h = {}; } - public function set( key : Int, value : T ) : Void { + public inline function set( key : Int, value : T ) : Void { untyped h[key] = value; } - public function get( key : Int ) : Null { + public inline function get( key : Int ) : Null { return untyped h[key]; } - public function exists( key : Int ) : Bool { + public inline function exists( key : Int ) : Bool { return untyped h.hasOwnProperty(key); } diff --git a/std/js/_std/haxe/ds/ObjectMap.hx b/std/js/_std/haxe/ds/ObjectMap.hx index 57b651e28d5003aaec770be2215fbcfc75a4c994..155fded55dbb647cc63635dcb6f9a44fbc89d4d4 100644 --- a/std/js/_std/haxe/ds/ObjectMap.hx +++ b/std/js/_std/haxe/ds/ObjectMap.hx @@ -1,101 +1,101 @@ -/* - * Copyright (C)2005-2013 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of h 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 h 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 ObjectMap implements Map.IMap { - - static var count = 0; - - static inline function assignId(obj: { } ):Int { - return untyped obj.__id__ = ++count; - } - - static inline function getId(obj: { } ):Int { - return untyped obj.__id__; - } - - var h : { }; - - public function new() : Void { - h = { }; - untyped h.__keys__ = { }; - } - - public function set(key:K, value:V):Void untyped { - var id = key.__id__ != null ? key.__id__ : assignId(key); - h[id] = value; - h.__keys__[id] = key; - } - - public inline function get(key:K):Null { - return untyped h[getId(key)]; - } - - public inline function exists(key:K):Bool { - return untyped h.hasOwnProperty(getId(key)); - } - - public function remove( key : K ) : Bool { - var id = getId(key); - if ( untyped !h.hasOwnProperty(id) ) return false; - untyped __js__("delete")(h[id]); - untyped __js__("delete")(h.__keys__[id]); - return true; - } - - public function keys() : Iterator { - var a = []; - untyped { - __js__("for( var key in this.h.__keys__ ) {"); - if( h.hasOwnProperty(key) ) - a.push(h.__keys__[key]); - __js__("}"); - } - return a.iterator(); - } - - 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[getId(i)]; } - }; - } - - public function toString() : String { - var s = new StringBuf(); - s.add("{"); - var it = keys(); - for( i in it ) { - s.add(Std.string(i)); - s.add(" => "); - s.add(Std.string(get(i))); - if( it.hasNext() ) - s.add(", "); - } - s.add("}"); - return s.toString(); - } +/* + * Copyright (C)2005-2013 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of h 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 h 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 ObjectMap implements haxe.Constraints.IMap { + + static var count = 0; + + static inline function assignId(obj: { } ):Int { + return untyped obj.__id__ = ++count; + } + + static inline function getId(obj: { } ):Int { + return untyped obj.__id__; + } + + var h : { }; + + public function new() : Void { + h = { }; + untyped h.__keys__ = { }; + } + + public function set(key:K, value:V):Void untyped { + var id : Int = untyped key.__id__ || assignId(key); + h[id] = value; + h.__keys__[id] = key; + } + + public inline function get(key:K):Null { + return untyped h[getId(key)]; + } + + public inline function exists(key:K):Bool { + return untyped h.__keys__[getId(key)] != null; + } + + public function remove( key : K ) : Bool { + var id = getId(key); + if ( untyped h.__keys__[id] == null ) return false; + untyped __js__("delete")(h[id]); + untyped __js__("delete")(h.__keys__[id]); + return true; + } + + public function keys() : Iterator { + var a = []; + untyped { + __js__("for( var key in this.h.__keys__ ) {"); + if( h.hasOwnProperty(key) ) + a.push(h.__keys__[key]); + __js__("}"); + } + return a.iterator(); + } + + 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[getId(i)]; } + }; + } + + public function toString() : String { + var s = new StringBuf(); + s.add("{"); + var it = keys(); + for( i in it ) { + s.add(Std.string(i)); + s.add(" => "); + s.add(Std.string(get(i))); + if( it.hasNext() ) + s.add(", "); + } + s.add("}"); + return s.toString(); + } } \ No newline at end of file diff --git a/std/js/_std/haxe/ds/StringMap.hx b/std/js/_std/haxe/ds/StringMap.hx index d8174acf59dade28327ab3725a98776d289483ab..cce32827396fd18ea0490ec7cf6063eb936ec9e1 100644 --- a/std/js/_std/haxe/ds/StringMap.hx +++ b/std/js/_std/haxe/ds/StringMap.hx @@ -21,66 +21,128 @@ */ package haxe.ds; -@:coreApi class StringMap implements Map.IMap { +private class StringMapIterator { + var map : StringMap; + var keys : Array; + var index : Int; + var count : Int; + public inline function new(map:StringMap, keys:Array) { + this.map = map; + this.keys = keys; + this.index = 0; + this.count = keys.length; + } + public inline function hasNext() { + return index < count; + } + public inline function next() { + return map.get(keys[index++]); + } +} + +@:coreApi class StringMap implements haxe.Constraints.IMap { private var h : Dynamic; + private var rh : Dynamic; - public function new() : Void { + public inline function new() : Void { h = {}; } - public function set( key : String, value : T ) : Void { - untyped h["$"+key] = value; + inline function isReserved(key:String) : Bool { + return untyped __js__("__map_reserved")[key] != null; } - public function get( key : String ) : Null { - return untyped h["$"+key]; + public inline function set( key : String, value : T ) : Void { + if( isReserved(key) ) + setReserved(key, value); + else + h[cast key] = value; } - public function exists( key : String ) : Bool { - return untyped h.hasOwnProperty("$"+key); + public inline function get( key : String ) : Null { + if( isReserved(key) ) + return getReserved(key); + return h[cast key]; + } + + public inline function exists( key : String ) : Bool { + if( isReserved(key) ) + return existsReserved(key); + return h.hasOwnProperty(key); + } + + function setReserved( key : String, value : T ) : Void { + if( rh == null ) rh = {}; + rh[cast "$"+key] = value; + } + + function getReserved( key : String ) : Null { + return rh == null ? null : rh[cast "$"+key]; + } + + function existsReserved( key : String ) : Bool { + if( rh == null ) return false; + return untyped rh.hasOwnProperty("$"+key); } public function remove( key : String ) : Bool { - key = "$"+key; - if( untyped !h.hasOwnProperty(key) ) return false; - untyped __js__("delete")(h[key]); - return true; + if( isReserved(key) ) { + key = "$" + key; + if( rh == null || !rh.hasOwnProperty(key) ) return false; + untyped __js__("delete")(rh[key]); + return true; + } else { + if( !h.hasOwnProperty(key) ) + return false; + untyped __js__("delete")(h[key]); + return true; + } } public function keys() : Iterator { - var a = []; + return arrayKeys().iterator(); + } + + function arrayKeys() : Array { + var out = []; untyped { __js__("for( var key in this.h ) {"); if( h.hasOwnProperty(key) ) - a.push(key.substr(1)); + out.push(key); __js__("}"); } - return a.iterator(); + if( rh != null ) untyped { + __js__("for( var key in this.rh ) {"); + if( key.charCodeAt(0) == "$".code ) + out.push(key.substr(1)); + __js__("}"); + } + return out; } - 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]; } - }; + public inline function iterator() : Iterator { + return new StringMapIterator(this, arrayKeys()); } public function toString() : String { var s = new StringBuf(); s.add("{"); - var it = keys(); - for( i in it ) { - s.add(i); + var keys = arrayKeys(); + for( i in 0...keys.length ) { + var k = keys[i]; + s.add(k); s.add(" => "); - s.add(Std.string(get(i))); - if( it.hasNext() ) + s.add(Std.string(get(k))); + if( i < keys.length ) s.add(", "); } s.add("}"); return s.toString(); } + static function __init__() : Void { + untyped __js__("var __map_reserved = {}"); + } + } diff --git a/std/js/_std/haxe/io/ArrayBufferView.hx b/std/js/_std/haxe/io/ArrayBufferView.hx new file mode 100644 index 0000000000000000000000000000000000000000..a983272e7c6a66b719a50642782dae89de7a6acc --- /dev/null +++ b/std/js/_std/haxe/io/ArrayBufferView.hx @@ -0,0 +1,42 @@ +package haxe.io; + +typedef ArrayBufferViewData = js.html.ArrayBufferView; + +abstract ArrayBufferView(ArrayBufferViewData) { + + public static var EMULATED(get,never) : Bool; + static function get_EMULATED() { + return (cast js.html.ArrayBuffer) == js.html.compat.ArrayBuffer; + } + + public var buffer(get,never) : haxe.io.Bytes; + public var byteOffset(get, never) : Int; + public var byteLength(get, never) : Int; + + public inline function new( size : Int ) { + this = new js.html.Uint8Array(size); + } + + inline function get_byteOffset() return this.byteOffset; + inline function get_byteLength() return this.byteLength; + function get_buffer() : haxe.io.Bytes { + return haxe.io.Bytes.ofData(this.buffer); + } + + public inline function sub( begin : Int, ?length : Int ) { + #if js + return fromData(new js.html.Uint8Array(this.buffer.slice(begin, length == null ? null : begin+length))); + #else + return fromData(this.sub(begin,length)); + #end + } + + public inline function getData() : ArrayBufferViewData { + return this; + } + + public static inline function fromData( a : ArrayBufferViewData ) : ArrayBufferView { + return cast a; + } + +} \ No newline at end of file diff --git a/std/js/_std/haxe/io/Bytes.hx b/std/js/_std/haxe/io/Bytes.hx new file mode 100644 index 0000000000000000000000000000000000000000..d2eea72f8b7ac8121e46404e185d56657d691f5a --- /dev/null +++ b/std/js/_std/haxe/io/Bytes.hx @@ -0,0 +1,233 @@ +/* + * Copyright (C)2005-2014 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; +import js.html.compat.Uint8Array; +import js.html.compat.DataView; + +@:coreApi +class Bytes { + + public var length(default,null) : Int; + var b : js.html.Uint8Array; + var data : js.html.DataView; + + function new(data:BytesData) { + this.length = data.byteLength; + this.b = new js.html.Uint8Array(data); + untyped { + b.bufferValue = data; // some impl does not return the same instance in .buffer + data.hxBytes = this; + data.bytes = this.b; + } + } + + public inline function get( pos : Int ) : Int { + return b[pos]; + } + + public inline function set( pos : Int, v : Int ) : Void { + b[pos] = v & 0xFF; // the &0xFF is necessary for js.html.compat support + } + + public function blit( pos : Int, src : Bytes, srcpos : Int, len : Int ) : Void { + if( pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length ) throw Error.OutsideBounds; + if( srcpos == 0 && len == src.length ) + b.set(src.b,pos); + else + b.set(src.b.subarray(srcpos,srcpos+len),pos); + } + + public function fill( pos : Int, len : Int, value : Int ) : Void { + for( i in 0...len ) + set(pos++, value); + } + + public function sub( pos : Int, len : Int ) : Bytes { + if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds; + return new Bytes(b.buffer.slice(pos+b.byteOffset,pos+b.byteOffset+len)); + } + + public function compare( other : Bytes ) : Int { + var b1 = b; + var b2 = other.b; + var len = (length < other.length) ? length : other.length; + for( i in 0...len ) + if( b1[i] != b2[i] ) + return b1[i] - b2[i]; + return length - other.length; + } + + inline function initData() : Void { + if( data == null ) data = new js.html.DataView(b.buffer, b.byteOffset, b.byteLength); + } + + public function getDouble( pos : Int ) : Float { + initData(); + return data.getFloat64(pos, true); + } + + public function getFloat( pos : Int ) : Float { + initData(); + return data.getFloat32(pos, true); + } + + public function setDouble( pos : Int, v : Float ) : Void { + initData(); + data.setFloat64(pos, v, true); + } + + public function setFloat( pos : Int, v : Float ) : Void { + initData(); + data.setFloat32(pos, v, true); + } + + public function getUInt16( pos : Int ) : Int { + initData(); + return data.getUint16(pos, true); + } + + public function setUInt16( pos : Int, v : Int ) : Void { + initData(); + data.setUint16(pos, v, true); + } + + public function getInt32( pos : Int ) : Int { + initData(); + return data.getInt32(pos, true); + } + + public function setInt32( pos : Int, v : Int ) : Void { + initData(); + data.setInt32(pos, v, true); + } + + public function getInt64( pos : Int ) : haxe.Int64 { + return Int64.make(getInt32(pos + 4),getInt32(pos)); + } + + public function setInt64( pos : Int, v : haxe.Int64 ) : Void { + setInt32(pos, v.low); + setInt32(pos + 4, v.high); + } + + public function getString( pos : Int, len : Int ) : String { + if( pos < 0 || len < 0 || pos + len > length ) throw Error.OutsideBounds; + var s = ""; + var b = b; + var fcc = String.fromCharCode; + var i = pos; + var max = pos+len; + // utf8-decode and utf16-encode + while( i < max ) { + var c = b[i++]; + if( c < 0x80 ) { + if( c == 0 ) break; + s += fcc(c); + } else if( c < 0xE0 ) + s += fcc( ((c & 0x3F) << 6) | (b[i++] & 0x7F) ); + else if( c < 0xF0 ) { + var c2 = b[i++]; + s += fcc( ((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | (b[i++] & 0x7F) ); + } else { + var c2 = b[i++]; + var c3 = b[i++]; + var u = ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | (b[i++] & 0x7F); + // surrogate pair + s += fcc( (u >> 10) + 0xD7C0 ); + s += fcc( (u & 0x3FF) | 0xDC00 ); + } + } + return s; + } + + @:deprecated("readString is deprecated, use getString instead") + @:noCompletion + public inline function readString(pos:Int, len:Int):String { + return getString(pos, len); + } + + public function toString() : String { + return getString(0,length); + } + + public function toHex() : String { + var s = new StringBuf(); + var chars = []; + var str = "0123456789abcdef"; + for( i in 0...str.length ) + chars.push(str.charCodeAt(i)); + for( i in 0...length ) { + var c = get(i); + s.addChar(chars[c >> 4]); + s.addChar(chars[c & 15]); + } + return s.toString(); + } + + public inline function getData() : BytesData { + return untyped b.bufferValue; + } + + public static function alloc( length : Int ) : Bytes { + return new Bytes(new BytesData(length)); + } + + public static function ofString( s : String ) : Bytes { + var a = new Array(); + // utf16-decode and utf8-encode + var i = 0; + while( i < s.length ) { + var c : Int = StringTools.fastCodeAt(s,i++); + // surrogate pair + if( 0xD800 <= c && c <= 0xDBFF ) + c = (c - 0xD7C0 << 10) | (StringTools.fastCodeAt(s,i++) & 0x3FF); + if( c <= 0x7F ) + a.push(c); + else if( c <= 0x7FF ) { + a.push( 0xC0 | (c >> 6) ); + a.push( 0x80 | (c & 63) ); + } else if( c <= 0xFFFF ) { + a.push( 0xE0 | (c >> 12) ); + a.push( 0x80 | ((c >> 6) & 63) ); + a.push( 0x80 | (c & 63) ); + } else { + a.push( 0xF0 | (c >> 18) ); + a.push( 0x80 | ((c >> 12) & 63) ); + a.push( 0x80 | ((c >> 6) & 63) ); + a.push( 0x80 | (c & 63) ); + } + } + return new Bytes(new js.html.Uint8Array(a).buffer); + } + + public static function ofData( b : BytesData ) : Bytes { + var hb = untyped b.hxBytes; + if( hb != null ) return hb; + return new Bytes(b); + } + + public inline static function fastGet( b : BytesData, pos : Int ) : Int { + // this requires that we have wrapped it with haxe.io.Bytes beforehand + return untyped b.bytes[pos]; + } + +} diff --git a/std/js/_std/haxe/io/Float32Array.hx b/std/js/_std/haxe/io/Float32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..aaf256bb87c8426e6816cd733cb499ca0c220b54 --- /dev/null +++ b/std/js/_std/haxe/io/Float32Array.hx @@ -0,0 +1,87 @@ +/* + * Copyright (C)2005-2015 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; + +import js.html.compat.Float32Array; + +typedef Float32ArrayData = js.html.Float32Array; + +@:coreApi +abstract Float32Array(Float32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) : Void { + this = new Float32ArrayData(elements); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Float { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : Float ) : Float { + return this[index] = value; + } + + public inline function sub( begin : Int, ?length : Int ) : Float32Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Float32Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : Float32ArrayData { + return this; + } + + public static function fromData( d : Float32ArrayData ) : Float32Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : Float32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new Float32ArrayData(a)); + var i = new Float32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : Float32Array { + if( length == null ) length = (bytes.length - bytePos) >> 2; + return fromData(new Float32ArrayData(bytes.getData(), bytePos, length)); + } +} + diff --git a/std/js/_std/haxe/io/Float64Array.hx b/std/js/_std/haxe/io/Float64Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..a4a8c1a0c24c5993de0ea13555643c6733142c29 --- /dev/null +++ b/std/js/_std/haxe/io/Float64Array.hx @@ -0,0 +1,87 @@ +/* + * Copyright (C)2005-2015 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; + +import js.html.compat.Float64Array; + +typedef Float64ArrayData = js.html.Float64Array; + +@:coreApi +abstract Float64Array(Float64ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) : Void { + this = new Float64ArrayData(elements); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Float { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : Float ) : Float { + return this[index] = value; + } + + public inline function sub( begin : Int, ?length : Int ) : Float64Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Float64Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : Float64ArrayData { + return this; + } + + public static function fromData( d : Float64ArrayData ) : Float64Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : Float64Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new Float64ArrayData(a)); + var i = new Float64Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : Float64Array { + if( length == null ) length = (bytes.length - bytePos) >> 3; + return fromData(new Float64ArrayData(bytes.getData(), bytePos, length)); + } +} + diff --git a/std/js/_std/haxe/io/Int32Array.hx b/std/js/_std/haxe/io/Int32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..a705bdd84295cad5728195e4d67e66c9557548a2 --- /dev/null +++ b/std/js/_std/haxe/io/Int32Array.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2015 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; + +typedef Int32ArrayData = js.html.Int32Array; + +@:coreApi +abstract Int32Array(Int32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 1; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new Int32ArrayData(elements * BYTES_PER_ELEMENT); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Int { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + return this[index] = value | 0; // necessary for html compat + } + + public inline function sub( begin : Int, ?length : Int ) : Int32Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : Int32Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : Int32ArrayData { + return this; + } + + public static function fromData( d : Int32ArrayData ) : Int32Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : Int32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new Int32ArrayData(a)); + var i = new Int32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : Int32Array { + if( length == null ) length = (bytes.length - bytePos) >> 2; + return fromData(new Int32ArrayData(bytes.getData(), bytePos, length)); + } + +} + diff --git a/std/js/_std/haxe/io/UInt16Array.hx b/std/js/_std/haxe/io/UInt16Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..a85c44e4984724bb94e7fe43988872e220437caa --- /dev/null +++ b/std/js/_std/haxe/io/UInt16Array.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt16ArrayData = js.html.Uint16Array; + +@:coreApi +abstract UInt16Array(UInt16ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 2; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new UInt16ArrayData(elements); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Int { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + return this[index] = value & 0xFFFF; // &0xFFFF necessary for html compat + } + + public inline function sub( begin : Int, ?length : Int ) : UInt16Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt16Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : UInt16ArrayData { + return this; + } + + public static function fromData( d : UInt16ArrayData ) : UInt16Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : UInt16Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new UInt16ArrayData(a)); + var i = new UInt16Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : UInt16Array { + if( length == null ) length = (bytes.length - bytePos) >> 1; + return fromData(new UInt16ArrayData(bytes.getData(), bytePos, length)); + } + +} + diff --git a/std/js/_std/haxe/io/UInt32Array.hx b/std/js/_std/haxe/io/UInt32Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..70099a580586d6580d6d4ee301f00be85b8cae1a --- /dev/null +++ b/std/js/_std/haxe/io/UInt32Array.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt32ArrayData = js.html.Uint32Array; + +@:coreApi +abstract UInt32Array(UInt32ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 4; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new UInt32ArrayData(elements); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : UInt { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : UInt ) : UInt { + return this[index] = value | 0; // necessary for html compat + } + + public inline function sub( begin : Int, ?length : Int ) : UInt32Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt32Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : UInt32ArrayData { + return this; + } + + public static function fromData( d : UInt32ArrayData ) : UInt32Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : UInt32Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new UInt32ArrayData(a)); + var i = new UInt32Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : UInt32Array { + if( length == null ) length = (bytes.length - bytePos) >> 2; + return fromData(new UInt32ArrayData(bytes.getData(), bytePos, length)); + } + +} + diff --git a/std/js/_std/haxe/io/UInt8Array.hx b/std/js/_std/haxe/io/UInt8Array.hx new file mode 100644 index 0000000000000000000000000000000000000000..93df4a360cbfe4a03cff4aaa69a1e627eb29deaa --- /dev/null +++ b/std/js/_std/haxe/io/UInt8Array.hx @@ -0,0 +1,86 @@ +/* + * Copyright (C)2005-2015 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; + +typedef UInt8ArrayData = js.html.Uint8Array; + +@:coreApi +abstract UInt8Array(UInt8ArrayData) { + + public static inline var BYTES_PER_ELEMENT = 1; + public var length(get,never) : Int; + public var view(get,never) : ArrayBufferView; + + public inline function new( elements : Int ) { + this = new UInt8ArrayData(elements); + } + + inline function get_length() : Int { + return this.length; + } + + public inline function get_view() : ArrayBufferView { + return ArrayBufferView.fromData(this); + } + + @:arrayAccess public inline function get( index : Int ) : Int { + return this[index]; + } + + @:arrayAccess public inline function set( index : Int, value : Int ) : Int { + return this[index] = value & 0xFF; // &0xFF necessary for html compat + } + + public inline function sub( begin : Int, ?length : Int ) : UInt8Array { + return fromData(this.subarray(begin, length == null ? this.length : begin+length)); + } + + public inline function subarray( ?begin : Int, ?end : Int ) : UInt8Array { + return fromData(this.subarray(begin, end)); + } + + public inline function getData() : UInt8ArrayData { + return this; + } + + public static function fromData( d : UInt8ArrayData ) : UInt8Array { + return cast d; + } + + public static function fromArray( a : Array, pos : Int = 0, ?length : Int ) : UInt8Array { + if( length == null ) length = a.length - pos; + if( pos < 0 || length < 0 || pos + length > a.length ) throw Error.OutsideBounds; + if( pos == 0 && length == a.length ) + return fromData(new UInt8ArrayData(a)); + var i = new UInt8Array(a.length); + for( idx in 0...length ) + i[idx] = a[idx + pos]; + return i; + } + + public static function fromBytes( bytes : haxe.io.Bytes, bytePos : Int = 0, ?length : Int ) : UInt8Array { + if( length == null ) length = bytes.length - bytePos; + return fromData(new UInt8ArrayData(bytes.getData(), bytePos, length)); + } + +} + diff --git a/std/js/html/AlignSetting.hx b/std/js/html/AlignSetting.hx new file mode 100644 index 0000000000000000000000000000000000000000..896e410b316d36ca2b194da32a1bac49eec19806 --- /dev/null +++ b/std/js/html/AlignSetting.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/VTTCue.webidl line 12:0. Do not edit! + +package js.html; + +@:enum abstract AlignSetting(String) +{ + var START = "start"; + var MIDDLE = "middle"; + var END = "end"; + var LEFT = "left"; + var RIGHT = "right"; +} \ No newline at end of file diff --git a/std/js/html/AnchorElement.hx b/std/js/html/AnchorElement.hx index 48213f929f564aee11618b60294d928e48194412..10b1c91fd9a7a3b4098aad1e98bc2df3831d86e9 100644 --- a/std/js/html/AnchorElement.hx +++ b/std/js/html/AnchorElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,104 +20,37 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLAnchorElement.webidl line 15:0. Do not edit! + package js.html; -/** DOM anchor elements expose the HTMLAnchorElement (or HTML 4 HTMLAnchorElement) interface, which provides special properties and methods (beyond the regular element object interface they also have available to them by inheritance) for manipulating the layout and presentation of hyperlink elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLAnchorElement") extern class AnchorElement extends Element { - /** The character encoding of the linked resource. - -Obsolete in -HTML5 */ - var charset : String; - - /** Comma-separated list of coordinates. - -Obsolete in -HTML5 */ - var coords : String; - + var target : String; var download : String; - - /** The fragment identifier (including the leading hash mark (#)), if any, in the referenced URL. */ - var hash : String; - - /** The hostname and port (if it's not the default port) in the referenced URL. */ - var host : String; - - /** The hostname in the referenced URL. */ - var hostname : String; - - /** Reflects the - -href - HTML attribute, containing a valid URL of a linked resource. */ - var href : String; - - /** Reflects the - -hreflang - HTML attribute, indicating the language of the linked resource. */ + var ping : String; + var rel : String; + var relList(default,null) : DOMTokenList; var hreflang : String; - - /** Anchor name. - -Obsolete in -HTML5 */ + var type : String; + var text : String; + var coords : String; + var charset : String; var name : String; - + var rev : String; + var shape : String; + var href : String; var origin(default,null) : String; - - /** The path name component, if any, of the referenced URL. */ - var pathname : String; - - var ping : String; - - /** The port component, if any, of the referenced URL. */ - var port : String; - - /** The protocol component (including trailing colon (:)), of the referenced URL. */ var protocol : String; - - /** Reflects the - -rel - HTML attribute, specifying the relationship of the target object to the link object. */ - var rel : String; - - /** Reverse link type. - -Obsolete in -HTML5 */ - var rev : String; - - /** The search element (including leading question mark (?)), if any, of the referenced URL */ + var username : String; + var password : String; + var host : String; + var hostname : String; + var port : String; + var pathname : String; var search : String; - - /** The shape of the active area. - -Obsolete in -HTML5 */ - var shape : String; - - /** Reflectst the - -target - HTML attribute, indicating where to display the linked resource. */ - var target : String; - - /** Same as the textContent property. */ - var text(default,null) : String; - - /** Reflects the - -type - HTML attribute, indicating the MIME type of the linked resource. */ - var type : String; - - function toString() : String; - -} + var hash : String; + var searchParams : URLSearchParams; + +} \ No newline at end of file diff --git a/std/js/html/Animation.hx b/std/js/html/Animation.hx index 4fa2a9e64585c0ffa3cb6f8a1a72afc7d2b838eb..bb4d871986f51da52c09bcae63cc598e7a558cb5 100644 --- a/std/js/html/Animation.hx +++ b/std/js/html/Animation.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,49 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Animation.webidl line 14:0. Do not edit! + package js.html; -/**

CSS animations make it possible to animate transitions from one CSS style configuration to another. Animations consist of two components: A style describing the animation and a set of keyframes that indicate the start and end states of the animation's CSS style, as well as possible intermediate waypoints along the way.

-

There are three key advantages to CSS animations over traditional script-driven animation techniques:

-
  1. They're easy to use for simple animations; you can create them without even having to know JavaScript.
  2. The animations run well, even under moderate system load. Simple animations can often perform poorly in JavaScript (unless they're well made). The rendering engine can use frame-skipping and other techniques to keep the performance as smooth as possible.
  3. Letting the browser control the animation sequence lets the browser optimize performance and efficiency by, for example, reducing the update frequency of animations running in tabs that aren't currently visible.
  4. -


-Documentation for this class was provided by MDN. */ @:native("Animation") extern class Animation { - static inline var DIRECTION_ALTERNATE : Int = 1; - - static inline var DIRECTION_NORMAL : Int = 0; - - static inline var FILL_BACKWARDS : Int = 1; - - static inline var FILL_BOTH : Int = 3; - - static inline var FILL_FORWARDS : Int = 2; - - static inline var FILL_NONE : Int = 0; - - var delay(default,null) : Float; - - var direction(default,null) : Int; - - var duration(default,null) : Float; - - var elapsedTime : Float; - - var ended(default,null) : Bool; - - var fillMode(default,null) : Int; - - var iterationCount(default,null) : Int; - - var name(default,null) : String; - - var paused(default,null) : Bool; - - function pause() : Void; - - function play() : Void; - -} + var effect(default,null) : AnimationEffect; + var target(default,null) : Element; + +} \ No newline at end of file diff --git a/std/js/html/SharedWorkerContext.hx b/std/js/html/AnimationEffect.hx similarity index 84% rename from std/js/html/SharedWorkerContext.hx rename to std/js/html/AnimationEffect.hx index 0cddb3041f0e284e901f16a591396e491d84d2ea..ea84d01eeb955a9236aaf75d14c70694d7b00473 100644 --- a/std/js/html/SharedWorkerContext.hx +++ b/std/js/html/AnimationEffect.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/AnimationEffect.webidl line 14:0. Do not edit! + package js.html; -@:native("SharedWorkerContext") -extern class SharedWorkerContext extends WorkerContext +@:native("AnimationEffect") +extern class AnimationEffect { var name(default,null) : String; - - var onconnect : EventListener; - -} + +} \ No newline at end of file diff --git a/std/js/html/AnimationEvent.hx b/std/js/html/AnimationEvent.hx index 45347541e9bdee1741619bb66aa618a7fe3b60b8..769fbcbe7d202cfa7475f584e0cc1e244c8ab724 100644 --- a/std/js/html/AnimationEvent.hx +++ b/std/js/html/AnimationEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,20 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/AnimationEvent.webidl line 15:0. Do not edit! + package js.html; -/** AnimationEvent objects provide information about events that occur related to CSS animations.

-Documentation for this class was provided by MDN. */ @:native("AnimationEvent") extern class AnimationEvent extends Event { - /** The name of the animation on which the animation event occurred. */ var animationName(default,null) : String; - - /** The amount of time, in seconds, the animation had been running at the time the event occurred. */ var elapsedTime(default,null) : Float; - - function new(type : String, canBubble : Bool = true, cancelable : Bool = true) : Void; - -} + var pseudoElement(default,null) : String; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : AnimationEventInit ) : Void; +} \ No newline at end of file diff --git a/std/js/html/AnimationEventInit.hx b/std/js/html/AnimationEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..0414fd91e4b3e2ecef8a28bc423b18efb45cdbec --- /dev/null +++ b/std/js/html/AnimationEventInit.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AnimationEvent.webidl line 21:0. Do not edit! + +package js.html; + +typedef AnimationEventInit = +{ + > EventInit, + @:optional var animationName : String; + @:optional var elapsedTime : Float; + @:optional var pseudoElement : String; +} \ No newline at end of file diff --git a/std/js/html/AnimationPlayState.hx b/std/js/html/AnimationPlayState.hx new file mode 100644 index 0000000000000000000000000000000000000000..cf2b46056cdc40d9e42e44cbf01ace9e6bbc5848 --- /dev/null +++ b/std/js/html/AnimationPlayState.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AnimationPlayer.webidl line 13:0. Do not edit! + +package js.html; + +@:enum abstract AnimationPlayState(String) +{ + var IDLE = "idle"; + var PENDING = "pending"; + var RUNNING = "running"; + var PAUSED = "paused"; + var FINISHED = "finished"; +} \ No newline at end of file diff --git a/std/js/html/AnimationPlayer.hx b/std/js/html/AnimationPlayer.hx new file mode 100644 index 0000000000000000000000000000000000000000..6874ba8dee1eb9d87709ae0c2ac96aaf36188a5b --- /dev/null +++ b/std/js/html/AnimationPlayer.hx @@ -0,0 +1,38 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AnimationPlayer.webidl line 16:0. Do not edit! + +package js.html; + +@:native("AnimationPlayer") +extern class AnimationPlayer +{ + var source(default,null) : Animation; + var timeline(default,null) : AnimationTimeline; + var startTime(default,null) : Float; + var currentTime(default,null) : Float; + var playState(default,null) : AnimationPlayState; + + function play() : Void; + function pause() : Void; +} \ No newline at end of file diff --git a/std/js/html/AnimationTimeline.hx b/std/js/html/AnimationTimeline.hx new file mode 100644 index 0000000000000000000000000000000000000000..a9cfdb9f16c1e207917ea0f99caf745fb94d9cc7 --- /dev/null +++ b/std/js/html/AnimationTimeline.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AnimationTimeline.webidl line 14:0. Do not edit! + +package js.html; + +@:native("AnimationTimeline") +extern class AnimationTimeline +{ + var currentTime(default,null) : Float; + +} \ No newline at end of file diff --git a/std/js/html/AppletElement.hx b/std/js/html/AppletElement.hx index 5396a2bffcdab17df79feeff2945a733cc1d8ce7..7cb9fa3d82b2d8fab174403ef22ad69d2a8293e4 100644 --- a/std/js/html/AppletElement.hx +++ b/std/js/html/AppletElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,44 +20,23 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLAppletElement.webidl line 16:0. Do not edit! + package js.html; -/** Obsolete

-Documentation for this class was provided by MDN. */ @:native("HTMLAppletElement") extern class AppletElement extends Element { - /** This attribute is used to position the applet on the page relative to content that might flow around it. The HTML 4.01 specification defines values of bottom, left, middle, right, and top, whereas Microsoft and Netscape also might support absbottom, absmiddle, baseline, center, and texttop. */ var align : String; - - /** This attribute causes a descriptive text alternate to be displayed on browsers that do not support Java. Page designers should also remember that content enclosed within the <applet> element may also be rendered as alternative text. */ var alt : String; - - /** This attribute refers to an archived or compressed version of the applet and its associated class files, which might help reduce download time. */ var archive : String; - - /** This attribute specifies the URL of the applet's class file to be loaded and executed. Applet filenames are identified by a .class filename extension. The URL specified by code might be relative to the codebase attribute. */ var code : String; - var codeBase : String; - - /** This attribute specifies the height, in pixels, that the applet needs. */ var height : String; - - /** This attribute specifies additional horizontal space, in pixels, to be reserved on either side of the applet. */ - var hspace : String; - - /** This attribute assigns a name to the applet so that it can be identified by other resources; particularly scripts. */ + var hspace : Int; var name : String; - - /** This attribute specifies the URL of a serialized representation of an applet. */ var object : String; - - /** This attribute specifies additional vertical space, in pixels, to be reserved above and below the applet. */ - var vspace : String; - - /** This attribute specifies in pixels the width that the applet needs. */ + var vspace : Int; var width : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/BaseFontElement.hx b/std/js/html/ApplicationCache.hx similarity index 52% rename from std/js/html/BaseFontElement.hx rename to std/js/html/ApplicationCache.hx index fe1feadd1b3652360d54303bc628a1eaa2f13040..716bda8854c807aa151047fa3c679fe2591de9f0 100644 --- a/std/js/html/BaseFontElement.hx +++ b/std/js/html/ApplicationCache.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,21 +20,32 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/OfflineResourceList.webidl line 5:0. Do not edit! + package js.html; -/** Obsolete

-Documentation for this class was provided by MDN. */ -@:native("HTMLBaseFontElement") -extern class BaseFontElement extends Element +@:native("ApplicationCache") +extern class ApplicationCache extends EventTarget implements ArrayAccess { - /** This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. */ - var color : String; - - /** This attribute contains a list of one or more font names. The document text in the default style is rendered in the first font face that the client's browser supports. If no font listed is installed on the local system, the browser typically defaults to the proportional or fixed-width font for that system. */ - var face : String; - - /** This attribute specifies the font size as either a numeric or relative value. Numeric values range from 1 to 7 with 1 being the smallest and 3 the default. */ - var size : Int; - -} + static inline var UNCACHED : Int = 0; + static inline var IDLE : Int = 1; + static inline var CHECKING : Int = 2; + static inline var DOWNLOADING : Int = 3; + static inline var UPDATEREADY : Int = 4; + static inline var OBSOLETE : Int = 5; + + var status(default,null) : Int; + var onchecking : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + var onnoupdate : haxe.Constraints.Function; + var ondownloading : haxe.Constraints.Function; + var onprogress : haxe.Constraints.Function; + var onupdateready : haxe.Constraints.Function; + var oncached : haxe.Constraints.Function; + var onobsolete : haxe.Constraints.Function; + + /** @throws DOMError */ + function update() : Void; + /** @throws DOMError */ + function swapCache() : Void; +} \ No newline at end of file diff --git a/std/js/html/AreaElement.hx b/std/js/html/AreaElement.hx index 6ef2d6e2410e8a299e0b85ef1d34b4b78ce71a08..b4998412c527d79150f44c27acd8b1877fc2db72 100644 --- a/std/js/html/AreaElement.hx +++ b/std/js/html/AreaElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,72 +20,33 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLAreaElement.webidl line 16:0. Do not edit! + package js.html; -/** DOM area objects expose the HTMLAreaElement (or -HTML 4 HTMLAreaElement) interface, which provides special properties and methods (beyond the regular element object interface they also have available to them by inheritance) for manipulating the layout and presentation of area elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLAreaElement") extern class AreaElement extends Element { - /** Reflects the - -alt - HTML attribute, containing alternative text for the element. */ var alt : String; - - /** Reflects the - -coords - HTML attribute, containing coordinates to define the hot-spot region. */ var coords : String; - - /** The fragment identifier (including the leading hash mark (#)), if any, in the referenced URL. */ - var hash(default,null) : String; - - /** The hostname and port (if it's not the default port) in the referenced URL. */ - var host(default,null) : String; - - /** The hostname in the referenced URL. */ - var hostname(default,null) : String; - - /** Reflects the - -href - HTML attribute, containing a valid URL of a linked resource. */ - var href : String; - - /** Indicates that this area is inactive. - -Obsolete in -HTML5 */ - var noHref : Bool; - - /** The path name component, if any, of the referenced URL. */ - var pathname(default,null) : String; - - var ping : String; - - /** The port component, if any, of the referenced URL. */ - var port(default,null) : String; - - /** The protocol component (including trailing colon (:)), of the referenced URL. */ - var protocol(default,null) : String; - - /** The search element (including leading question mark (?)), if any, of the referenced URL */ - var search(default,null) : String; - - /** Reflects the - -shape - HTML attribute, indicating the shape of the hot-spot, limited to known values. */ var shape : String; - - /** Reflects the - -target - HTML attribute, indicating the browsing context in which to open the linked resource. */ var target : String; - -} + var download : String; + var ping : String; + var rel : String; + var relList(default,null) : DOMTokenList; + var noHref : Bool; + var href : String; + var origin(default,null) : String; + var protocol : String; + var username : String; + var password : String; + var host : String; + var hostname : String; + var port : String; + var pathname : String; + var search : String; + var hash : String; + var searchParams : URLSearchParams; + +} \ No newline at end of file diff --git a/std/js/html/ArrayBuffer.hx b/std/js/html/ArrayBuffer.hx index b6c6c13bc5c3645fa8a666a6a5d2348c2b7eed15..cb507e8bfbce1da8734096e87f2b5c3b8b190d81 100644 --- a/std/js/html/ArrayBuffer.hx +++ b/std/js/html/ArrayBuffer.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,19 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from typedarray.webidl line 12:0. Do not edit! + package js.html; -/** The ArrayBuffer is a data type that is used to represent a generic, fixed-length binary data buffer. You can't directly manipulate the contents of an ArrayBuffer; instead, you create an ArrayBufferView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.

-Documentation for this class was provided by MDN. */ @:native("ArrayBuffer") extern class ArrayBuffer { - /** The size, in bytes, of the array. This is established when the array is constructed and cannot be changed. Read only. */ + static function isView( value : Dynamic ) : Bool; var byteLength(default,null) : Int; - - function new(?arg0 : Dynamic) : Void; - + + /** @throws DOMError */ + function new( length : Int ) : Void; function slice( begin : Int, ?end : Int ) : ArrayBuffer; - -} +} \ No newline at end of file diff --git a/std/js/html/ArrayBufferView.hx b/std/js/html/ArrayBufferView.hx index f1e37a0ff67608ceec954543d17046439d4e5e13..99ddaa8f1c0580fbeeb76491a66a8acedefebac8 100644 --- a/std/js/html/ArrayBufferView.hx +++ b/std/js/html/ArrayBufferView.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from typedarray.webidl line 21:0. Do not edit! + package js.html; -/**

The ArrayBufferView type describes a particular view on the contents of an ArrayBuffer's data.

-

Of note is that you may create multiple views into the same buffer, each looking at the buffer's contents starting at a particular offset. This makes it possible to set up views of different data types to read the contents of a buffer based on the types of data at specific offsets into the buffer.

-
Note: Typically, you'll instantiate one of the subclasses of this object instead of this base class. Those provide access to the data formatted using specific data types.


-Documentation for this class was provided by MDN. */ @:native("ArrayBufferView") extern class ArrayBufferView { - /** The buffer this view references. Read only. */ var buffer(default,null) : ArrayBuffer; - - /** The length, in bytes, of the view. Read only. */ - var byteLength(default,null) : Int; - - /** The offset, in bytes, to the first byte of the view within the ArrayBuffer. */ var byteOffset(default,null) : Int; - -} + var byteLength(default,null) : Int; + +} \ No newline at end of file diff --git a/std/js/html/Attr.hx b/std/js/html/Attr.hx index b13756d714908c12e9913cd98031c7093d514f37..1fe07a1c95d6813449811bdc205b60ce13eb8a82 100644 --- a/std/js/html/Attr.hx +++ b/std/js/html/Attr.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,33 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Attr.webidl line 13:0. Do not edit! + package js.html; -/**

This type represents a DOM element's attribute as an object. In most DOM methods, you will probably directly retrieve the attribute as a string (e.g., Element.getAttribute() -, but certain functions (e.g., Element.getAttributeNode() -) or means of iterating give Attr types.

-
Warning: In DOM Core 1, 2 and 3, Attr inherited from Node. This is no longer the case in DOM4. In order to bring the implementation of Attr up to specification, work is underway to change it to no longer inherit from Node -. You should not be using any Node - properties or methods on Attr objects. Starting in Gecko 7.0 (Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4) -, the ones that are going to be removed output warning messages to the console. You should revise your code accordingly. See Deprecated properties and methods for a complete list.


-Documentation for this class was provided by MDN. */ @:native("Attr") extern class Attr extends Node { - /** Indicates whether the attribute is an "ID attribute". An "ID attribute" being an attribute which value is expected to be unique across a DOM Document. In HTML DOM, "id" is the only ID attribute, but XML documents could define others. Whether or not an attribute is unique is often determined by a DTD or other schema description. */ - var isId(default,null) : Bool; - - /** The attribute's name. */ + var value : String; var name(default,null) : String; - - /** This property has been deprecated and will be removed in the future. Since you can only get Attr objects from elements, you should already know th */ - var ownerElement(default,null) : Element; - - /** This property has been deprecated and will be removed in the future; it now always returns true. */ var specified(default,null) : Bool; - - /** The attribute's value. Setter throws DOMException. */ - var value : String; - -} + var ownerElement(default,null) : Element; + +} \ No newline at end of file diff --git a/std/js/html/Audio.hx b/std/js/html/Audio.hx index 09d372529c3e9814327232c090fe4e51dfe0fe5d..f2477243ebff3d3ff9ed4a973c9c52a0b14a8716 100644 --- a/std/js/html/Audio.hx +++ b/std/js/html/Audio.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from namedConstructors.webidl line 2:0. Do not edit! + package js.html; @:native("Audio") extern class Audio extends AudioElement { - function new() : Void; - -} + /** @throws DOMError */ + function new( ?src : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/AudioChannel.hx b/std/js/html/AudioChannel.hx new file mode 100644 index 0000000000000000000000000000000000000000..263535269d7c29fda6a64e0bf107dfb96ffec6f1 --- /dev/null +++ b/std/js/html/AudioChannel.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AudioChannel.webidl line 41:0. Do not edit! + +package js.html; + +@:enum abstract AudioChannel(String) +{ + var NORMAL = "normal"; + var CONTENT = "content"; + var NOTIFICATION = "notification"; + var ALARM = "alarm"; + var TELEPHONY = "telephony"; + var RINGER = "ringer"; + var PUBLICNOTIFICATION = "publicnotification"; +} \ No newline at end of file diff --git a/std/js/html/AudioElement.hx b/std/js/html/AudioElement.hx index b6cf227fdaff0a7bcd2adbf9f318cc23f5e2374d..b07e1bc037cc10175418df6d2529e01f5c90b480 100644 --- a/std/js/html/AudioElement.hx +++ b/std/js/html/AudioElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,17 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLAudioElement.webidl line 15:0. Do not edit! + package js.html; -/**

The HTMLAudioElement interface provides access to the properties of <audio> - elements, as well as methods to manipulate them. It's derived from the HTMLMediaElement interface; it's implemented by nsIDOMHTMLMediaElement -.

-

For details on how to use the audio streaming features exposed by this interface, please see Introducing the Audio API Extension.



-Documentation for this class was provided by MDN. */ @:native("HTMLAudioElement") extern class AudioElement extends MediaElement { - function new() : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/AudioStreamTrack.hx b/std/js/html/AudioStreamTrack.hx new file mode 100644 index 0000000000000000000000000000000000000000..623ac47fe7d6c7b6c362039d25e6dc5d417f9d76 --- /dev/null +++ b/std/js/html/AudioStreamTrack.hx @@ -0,0 +1,30 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AudioStreamTrack.webidl line 14:0. Do not edit! + +package js.html; + +@:native("AudioStreamTrack") +extern class AudioStreamTrack extends MediaStreamTrack +{ +} \ No newline at end of file diff --git a/std/js/html/DataTransferItem.hx b/std/js/html/AudioTrack.hx similarity index 78% rename from std/js/html/DataTransferItem.hx rename to std/js/html/AudioTrack.hx index f5598a2f7597de9ea51dffd5825573712ae81790..8f078f1e8a4a78c2fc30ce62f33ac2efb6bbca16 100644 --- a/std/js/html/DataTransferItem.hx +++ b/std/js/html/AudioTrack.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,20 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/AudioTrack.webidl line 11:0. Do not edit! + package js.html; -@:native("DataTransferItem") -extern class DataTransferItem +@:native("AudioTrack") +extern class AudioTrack { + var id(default,null) : String; var kind(default,null) : String; - - var type(default,null) : String; - - function getAsEntry() : js.html.fs.Entry; - - function getAsFile() : Blob; - - function getAsString( callback_ : StringCallback ) : Void; - -} + var label(default,null) : String; + var language(default,null) : String; + var enabled : Bool; + +} \ No newline at end of file diff --git a/std/js/html/AudioTrackList.hx b/std/js/html/AudioTrackList.hx new file mode 100644 index 0000000000000000000000000000000000000000..8e8baa1ae33419ddba5fcf18b71a779dccad9fd3 --- /dev/null +++ b/std/js/html/AudioTrackList.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/AudioTrackList.webidl line 11:0. Do not edit! + +package js.html; + +@:native("AudioTrackList") +extern class AudioTrackList extends EventTarget implements ArrayAccess +{ + var length(default,null) : Int; + var onchange : haxe.Constraints.Function; + var onaddtrack : haxe.Constraints.Function; + var onremovetrack : haxe.Constraints.Function; + + function getTrackById( id : String ) : AudioTrack; +} \ No newline at end of file diff --git a/std/js/html/BRElement.hx b/std/js/html/BRElement.hx index 67d61cc42e6f0695fa13c535059140ddbcf33160..789fe051dd291b5c35ba0cfe9c72a8ba8294b87e 100644 --- a/std/js/html/BRElement.hx +++ b/std/js/html/BRElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,17 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLBRElement.webidl line 16:0. Do not edit! + package js.html; -/** DOM break elements expose the HTMLBRElement (or HTML 4 HTMLBRElement) interface which inherits from HTMLElement, but defines no additional members in -HTML5. The introduced additional property is also deprecated in -HTML 4.01.

-Documentation for this class was provided by MDN. */ @:native("HTMLBRElement") extern class BRElement extends Element { - /** Indicates flow of text around floating objects. */ var clear : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/BarInfo.hx b/std/js/html/BarInfo.hx index c8763de93a27343194c6d3a94ec474e60ddfe642..7dbef5e22715a8fae05a9b6b98b029754df9c38a 100644 --- a/std/js/html/BarInfo.hx +++ b/std/js/html/BarInfo.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("BarInfo") -extern class BarInfo -{ - var visible(default,null) : Bool; - -} +/** @deprecated Use BarProp instead. */ +@:deprecated("BarInfo is deprecated, use BarProp instead") +typedef BarInfo = BarProp; diff --git a/std/js/html/PositionErrorCallback.hx b/std/js/html/BarProp.hx similarity index 85% rename from std/js/html/PositionErrorCallback.hx rename to std/js/html/BarProp.hx index 869281cd1fb18846ccffa8dcdedea19062c7ee54..d51794715464ab060dd65c6d5212095be03f09ec 100644 --- a/std/js/html/PositionErrorCallback.hx +++ b/std/js/html/BarProp.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,7 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/BarProp.webidl line 7:0. Do not edit! + package js.html; -typedef PositionErrorCallback = PositionError -> Bool; \ No newline at end of file +@:native("BarProp") +extern class BarProp +{ + var visible : Bool; + +} \ No newline at end of file diff --git a/std/js/html/BaseElement.hx b/std/js/html/BaseElement.hx index 8120ce3a18f1c4c1c97fefa0a72f16d6f57aba67..1f213ac43444a86f1f7b06fa43bef096900291f2 100644 --- a/std/js/html/BaseElement.hx +++ b/std/js/html/BaseElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,25 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLBaseElement.webidl line 15:0. Do not edit! + package js.html; -/** The base object exposes the HTMLBaseElement (or -HTML 4 HTMLBaseElement) interface which contains the base URI for a document.  This object inherits all of the properties and methods as described in the element section.

-Documentation for this class was provided by MDN. */ @:native("HTMLBaseElement") extern class BaseElement extends Element { - /** Reflects the - -href - HTML attribute, containing a base URL for relative URLs in the document. */ var href : String; - - /** Reflects the - -target - HTML attribute, containing a default target browsing context or frame for elements that do not have a target reference specified. */ var target : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/BatteryManager.hx b/std/js/html/BatteryManager.hx index 055f1b71f3d0297f7d85a79a7ed8186723f0ad00..5bf79204eaf77e7a3577c91c20610cf488fb8074 100644 --- a/std/js/html/BatteryManager.hx +++ b/std/js/html/BatteryManager.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,26 +20,20 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/BatteryManager.webidl line 13:0. Do not edit! + package js.html; @:native("BatteryManager") extern class BatteryManager extends EventTarget { var charging(default,null) : Bool; - var chargingTime(default,null) : Float; - var dischargingTime(default,null) : Float; - var level(default,null) : Float; - - var onchargingchange : EventListener; - - var onchargingtimechange : EventListener; - - var ondischargingtimechange : EventListener; - - var onlevelchange : EventListener; - -} + var onchargingchange : haxe.Constraints.Function; + var onchargingtimechange : haxe.Constraints.Function; + var ondischargingtimechange : haxe.Constraints.Function; + var onlevelchange : haxe.Constraints.Function; + +} \ No newline at end of file diff --git a/std/js/html/BeforeUnloadEvent.hx b/std/js/html/BeforeUnloadEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..2581bc8d09a7afef9a7e3116613dfd2c84294385 --- /dev/null +++ b/std/js/html/BeforeUnloadEvent.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/BeforeUnloadEvent.webidl line 10:0. Do not edit! + +package js.html; + +@:native("BeforeUnloadEvent") +extern class BeforeUnloadEvent extends Event +{ + var returnValue : String; + +} \ No newline at end of file diff --git a/std/js/html/BinaryType.hx b/std/js/html/BinaryType.hx new file mode 100644 index 0000000000000000000000000000000000000000..73ac085ca8291a87fb0262bbae483614be094518 --- /dev/null +++ b/std/js/html/BinaryType.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/WebSocket.webidl line 13:0. Do not edit! + +package js.html; + +@:enum abstract BinaryType(String) +{ + var BLOB = "blob"; + var ARRAYBUFFER = "arraybuffer"; +} \ No newline at end of file diff --git a/std/js/html/Blob.hx b/std/js/html/Blob.hx index 0872d78104b1fbf5c1c5a4c07560f513677f9d86..b513adccaf7df54261fc9ed4ce2f3f8619d1506d 100644 --- a/std/js/html/Blob.hx +++ b/std/js/html/Blob.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,28 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Blob.webidl line 16:0. Do not edit! + package js.html; -/**

This is an experimental feature
Because this feature is still in development in some browsers, check the compatibility table for the proper prefixes to use in various browsers.

-

-

A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File - interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system.

-

An easy way to construct a Blob is by using the BlobBuilder - interface, which lets you iteratively append data to a blob, then retrieve the completed blob when you're ready to use it for something. Another way is to use the slice() method to create a blob that contains a subset of another blob's data.

-
Note: The slice() method has vendor prefixes: blob.mozSlice() for Firefox and blob.webkitSlice() for Chrome. An old version of the slice() method, without vendor prefixes, had different semantics, as described below.


-Documentation for this class was provided by MDN. */ @:native("Blob") extern class Blob { - /** The size, in bytes, of the data contained in the Blob object. Read only. */ var size(default,null) : Int; - - /** An ASCII-encoded string, in all lower case, indicating the MIME type of the data contained in the Blob. If the type is unknown, this string is empty. Read only. */ var type(default,null) : String; - - function new(?arg0 : Dynamic, ?arg1 : Dynamic) : Void; - - function slice( ?start : Int, ?end : Int, ?contentType : String ) : Blob; - -} + + /** @throws DOMError */ + @:overload( function() : Void {} ) + function new( blobParts : Array>>>, ?options : BlobPropertyBag ) : Void; + /** @throws DOMError */ + function slice( ?start : Int, ?end : Int, ?contentType : String = "" ) : Blob; +} \ No newline at end of file diff --git a/std/js/html/BlobPropertyBag.hx b/std/js/html/BlobPropertyBag.hx new file mode 100644 index 0000000000000000000000000000000000000000..ae55ce7e9b946bd63bbb080bd9566c9fad0a8438 --- /dev/null +++ b/std/js/html/BlobPropertyBag.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Blob.webidl line 37:0. Do not edit! + +package js.html; + +typedef BlobPropertyBag = +{ + @:optional var endings : Dynamic/*MISSING EndingTypes*/; + @:optional var type : String; +} \ No newline at end of file diff --git a/std/js/html/BodyElement.hx b/std/js/html/BodyElement.hx index 4ee438b9456c87c47f81e6d75c9578d1601deb58..4aa1d1d3260a53b3621c21ea96ac6a39570b48d0 100644 --- a/std/js/html/BodyElement.hx +++ b/std/js/html/BodyElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,87 +20,31 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLBodyElement.webidl line 14:0. Do not edit! + package js.html; -/** DOM body elements expose the HTMLBodyElement (or -HTML 4 HTMLBodyElement) interface, which provides special properties (beyond the regular element - object interface they also have available to them by inheritance) for manipulating body elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLBodyElement") extern class BodyElement extends Element { - /** Color of active hyperlinks. */ - var aLink : String; - - /**

URI for a background image resource.

Note: Starting in Gecko 7.0 (Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4) -, this value is no longer resolved as a URI; instead, it's treated as a simple string.
*/ - var background : String; - - /** Background color for the document. */ - var bgColor : String; - - /** Color of unvisited links. */ - var link : String; - - /** Reflects the - -onbeforeunload - HTML attribute value for a function to call when the document is about to be unloaded. */ - var onbeforeunload : EventListener; - - /** Reflects the - -onhashchange - HTML attribute value for a function to call when the fragment identifier in the address of the document changes. */ - var onhashchange : EventListener; - - /** Reflects the - -onmessage - HTML attribute value for a function to call when the document receives a message. */ - var onmessage : EventListener; - - /** Reflects the - -onoffline - HTML attribute value for a function to call when network communication fails. */ - var onoffline : EventListener; - - /** Reflects the - -ononline - HTML attribute value for a function to call when network communication is restored. */ - var ononline : EventListener; - - /** Reflects the - -onpopstate - HTML attribute value for a function to call when the user has navigated session history. */ - var onpopstate : EventListener; - - /** Reflects the - -onresize - HTML attribute value for a function to call when the document has been resized. */ - var onresize : EventListener; - - /** Reflects the - -onpopstate - HTML attribute value for a function to call when the storage area has changed. */ - var onstorage : EventListener; - - /** Reflects the - -onunload - HTML attribute value for a function to call when when the document is going away. */ - var onunload : EventListener; - - /** Foreground color of text. */ var text : String; - - /** Color of visited links. */ + var link : String; var vLink : String; - -} + var aLink : String; + var bgColor : String; + var background : String; + var onafterprint : haxe.Constraints.Function; + var onbeforeprint : haxe.Constraints.Function; + var onbeforeunload : Event -> String; + var onhashchange : haxe.Constraints.Function; + var onlanguagechange : haxe.Constraints.Function; + var onmessage : haxe.Constraints.Function; + var onoffline : haxe.Constraints.Function; + var ononline : haxe.Constraints.Function; + var onpagehide : haxe.Constraints.Function; + var onpageshow : haxe.Constraints.Function; + var onpopstate : haxe.Constraints.Function; + var onresize : haxe.Constraints.Function; + var onunload : haxe.Constraints.Function; + +} \ No newline at end of file diff --git a/std/js/html/ButtonElement.hx b/std/js/html/ButtonElement.hx index 918b48f41149e314883c36cc41ec5afa69527399..a2ebe8efe7ec5ec7a2edcbc169f17cde2e34283c 100644 --- a/std/js/html/ButtonElement.hx +++ b/std/js/html/ButtonElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,83 +20,28 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLButtonElement.webidl line 14:0. Do not edit! + package js.html; -/** DOM Button objects expose the HTMLButtonElement -HTML5 (or HTMLButtonElement -HTML 4) interface, which provides properties and methods (beyond the element object interface they also have available to them by inheritance) for manipulating the layout and presentation of button elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLButtonElement") extern class ButtonElement extends Element { - /** The control should have input focus when the page loads, unless the user overrides it, for example by typing in a different control. Only one form-associated element in a document can have this attribute specified. */ var autofocus : Bool; - - /** The control is disabled, meaning that it does not accept any clicks. */ var disabled : Bool; - - /**

The form that this button is associated with. If the button is a descendant of a form element, then this attribute is the ID of that form element.

If the button is not a descendant of a form element, then:

  • -HTML5 The attribute can be the ID of any form element in the same document.
  • -HTML 4 The attribute is null.
*/ var form(default,null) : FormElement; - - /** The URI of a program that processes information submitted by the button. If specified, this attribute overrides the - -action - attribute of the <form> - element that owns this element. */ var formAction : String; - var formEnctype : String; - - /** The HTTP method that the browser uses to submit the form. If specified, this attribute overrides the - -method - attribute of the <form> - element that owns this element. */ var formMethod : String; - - /** Indicates that the form is not to be validated when it is submitted. If specified, this attribute overrides the - -enctype - attribute of the <form> - element that owns this element. */ var formNoValidate : Bool; - - /** A name or keyword indicating where to display the response that is received after submitting the form. If specified, this attribute overrides the - -target - attribute of the <form> - element that owns this element. */ var formTarget : String; - - /** A list of <label> - elements that are labels for this button. */ - var labels(default,null) : NodeList; - - /** The name of the object when submitted with a form. -HTML5 If specified, it must not be the empty string. */ var name : String; - - /**

Indicates the behavior of the button. This is an enumerated attribute with the following possible values:

  • submit: The button submits the form. This is the default value if the attribute is not specified, -HTML5 or if it is dynamically changed to an empty or invalid value.
  • reset: The button resets the form.
  • button: The button does nothing.
*/ var type : String; - - /** A localized message that describes the validation constraints that the control does not satisfy (if any). This attribute is the empty string if the control is not a candidate for constraint validation (willValidate is false), or it satisfies its constraints. */ - var validationMessage(default,null) : String; - - /** The validity states that this button is in. */ - var validity(default,null) : ValidityState; - - /** The current form control value of the button.  */ var value : String; - - /** Indicates whether the button is a candidate for constraint validation. It is false if any conditions bar it from constraint validation. */ var willValidate(default,null) : Bool; - + var validity(default,null) : ValidityState; + var validationMessage(default,null) : String; + function checkValidity() : Bool; - function setCustomValidity( error : String ) : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/CDATASection.hx b/std/js/html/CDATASection.hx index d4f6a589989c7a2de02f13ab388a33f0b7c6f1b8..8696d2c609185d862a3d85c48437b16138a517df 100644 --- a/std/js/html/CDATASection.hx +++ b/std/js/html/CDATASection.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CDATASection.webidl line 7:0. Do not edit! + package js.html; -/**

A CDATA Section can be used within XML to include extended portions of unescaped text, such that the symbols < and & do not need escaping as they normally do within XML when used as text.

-

It takes the form:

-
<![CDATA[  ... ]]>
-
-

For example:

-
<foo>Here is a CDATA section: <![CDATA[  < > & ]]> with all kinds of unescaped text. </foo>
-
-

The only sequence which is not allowed within a CDATA section is the closing sequence of a CDATA section itself:

-
<![CDATA[  ]]> will cause an error   ]]>
-
-

Note that CDATA sections should not be used (without hiding) within HTML.

-

As a CDATASection has no properties or methods unique to itself and only directly implements the Text interface, one can refer to Text to find its properties and methods.



-Documentation for this class was provided by MDN. */ @:native("CDATASection") extern class CDATASection extends Text { -} +} \ No newline at end of file diff --git a/std/js/html/CSS.hx b/std/js/html/CSS.hx new file mode 100644 index 0000000000000000000000000000000000000000..d637fda60588c702642d87671c74e479d46702f1 --- /dev/null +++ b/std/js/html/CSS.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CSS.webidl line 13:0. Do not edit! + +package js.html; + +@:native("CSS") +extern class CSS +{ + /** @throws DOMError */ + @:overload( function( property : String, value : String ) : Bool {} ) + static function supports( conditionText : String ) : Bool; + /** @throws DOMError */ + static function escape( ident : String ) : String; +} \ No newline at end of file diff --git a/std/js/html/CSSCharsetRule.hx b/std/js/html/CSSCharsetRule.hx index f09ff3f19c38819ae6a40fb1772d687828f2f6bf..6dc0d137bb6fb3a0c40674a0ab5882b1e95b1088 100644 --- a/std/js/html/CSSCharsetRule.hx +++ b/std/js/html/CSSCharsetRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,13 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 62:2. Do not edit! + package js.html; @:native("CSSCharsetRule") extern class CSSCharsetRule extends CSSRule { - /** Setter throws DOMException. */ var encoding : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSFontFaceRule.hx b/std/js/html/CSSFontFaceRule.hx index 29e4fca0889855a2a5ccac5ca117191639d1e27f..1e0389ec29bce873d40f2e0cd08b1b564406e876 100644 --- a/std/js/html/CSSFontFaceRule.hx +++ b/std/js/html/CSSFontFaceRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 42:2. Do not edit! + package js.html; @:native("CSSFontFaceRule") extern class CSSFontFaceRule extends CSSRule { var style(default,null) : CSSStyleDeclaration; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSImportRule.hx b/std/js/html/CSSImportRule.hx index d63b96788530c0ad2675f606a71d7f157bc99f42..3be02ce6b1f99e70cac08f7a2f18727c306d16f8 100644 --- a/std/js/html/CSSImportRule.hx +++ b/std/js/html/CSSImportRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 55:2. Do not edit! + package js.html; @:native("CSSImportRule") extern class CSSImportRule extends CSSRule { var href(default,null) : String; - var media(default,null) : MediaList; - var styleSheet(default,null) : CSSStyleSheet; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSMatrix.hx b/std/js/html/CSSMatrix.hx index e22e4d1207e57c3d1bda427e0fad4273f4fd799d..c1add5cab67848a1b207bb8879c936c86a7bfaa8 100644 --- a/std/js/html/CSSMatrix.hx +++ b/std/js/html/CSSMatrix.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,76 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("CSSMatrix") -extern class CSSMatrix -{ - var a : Float; - - var b : Float; - - var c : Float; - - var d : Float; - - var e : Float; - - var f : Float; - - var m11 : Float; - - var m12 : Float; - - var m13 : Float; - - var m14 : Float; - - var m21 : Float; - - var m22 : Float; - - var m23 : Float; - - var m24 : Float; - - var m31 : Float; - - var m32 : Float; - - var m33 : Float; - - var m34 : Float; - - var m41 : Float; - - var m42 : Float; - - var m43 : Float; - - var m44 : Float; - - function new() : Void; - - function inverse() : CSSMatrix; - - function multiply( secondMatrix : CSSMatrix ) : CSSMatrix; - - function rotate( rotX : Float, rotY : Float, rotZ : Float ) : CSSMatrix; - - function rotateAxisAngle( x : Float, y : Float, z : Float, angle : Float ) : CSSMatrix; - - function scale( scaleX : Float, scaleY : Float, scaleZ : Float ) : CSSMatrix; - - function setMatrixValue( string : String ) : Void; - - function skewX( angle : Float ) : CSSMatrix; - - function skewY( angle : Float ) : CSSMatrix; - - function toString() : String; - - function translate( x : Float, y : Float, z : Float ) : CSSMatrix; - -} +/** @deprecated Use DOMMatrix instead. */ +@:deprecated("CSSMatrix is deprecated, use DOMMatrix instead") +typedef CSSMatrix = DOMMatrix; diff --git a/std/js/html/CSSMediaRule.hx b/std/js/html/CSSMediaRule.hx index 1105c8dbce3dd15fac37466d878e56bd83870a66..50c8a06bf50dc5ffda491ec72d8270ab0719f9ee 100644 --- a/std/js/html/CSSMediaRule.hx +++ b/std/js/html/CSSMediaRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,22 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 31:2. Do not edit! + package js.html; -/** An object representing a single CSS media rule. CSSMediaRule implements the CSSRule interface.

-Documentation for this class was provided by MDN. */ @:native("CSSMediaRule") extern class CSSMediaRule extends CSSRule { - /** Returns a CSSRuleList of the CSS rules in the media rule. */ - var cssRules(default,null) : CSSRuleList; - - /** Specifies the intended destination medium for style information. */ var media(default,null) : MediaList; - - function deleteRule( index : Int ) : Void; - + var cssRules(default,null) : CSSRuleList; + function insertRule( rule : String, index : Int ) : Int; - -} + function deleteRule( index : Int ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CSSPageRule.hx b/std/js/html/CSSPageRule.hx index 7340fb748cb67fb1efe5cba3439168d7edcb86ac..55570be6b73d98ea6142c5713d60cafd3ec7ede1 100644 --- a/std/js/html/CSSPageRule.hx +++ b/std/js/html/CSSPageRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 47:2. Do not edit! + package js.html; @:native("CSSPageRule") extern class CSSPageRule extends CSSRule { var selectorText : String; - var style(default,null) : CSSStyleDeclaration; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSPrimitiveValue.hx b/std/js/html/CSSPrimitiveValue.hx index e32dbe8f4b171a99a4ea03ba96aa2b0fa1827f82..595ec2b81f09e12a4508c78308803e09f7bb8c52 100644 --- a/std/js/html/CSSPrimitiveValue.hx +++ b/std/js/html/CSSPrimitiveValue.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,84 +20,54 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSPrimitiveValue.webidl line 9:0. Do not edit! + package js.html; @:native("CSSPrimitiveValue") extern class CSSPrimitiveValue extends CSSValue { - static inline var CSS_ATTR : Int = 22; - - static inline var CSS_CM : Int = 6; - - static inline var CSS_COUNTER : Int = 23; - - static inline var CSS_DEG : Int = 11; - - static inline var CSS_DIMENSION : Int = 18; - + static inline var CSS_UNKNOWN : Int = 0; + static inline var CSS_NUMBER : Int = 1; + static inline var CSS_PERCENTAGE : Int = 2; static inline var CSS_EMS : Int = 3; - static inline var CSS_EXS : Int = 4; - - static inline var CSS_GRAD : Int = 13; - - static inline var CSS_HZ : Int = 16; - - static inline var CSS_IDENT : Int = 21; - - static inline var CSS_IN : Int = 8; - - static inline var CSS_KHZ : Int = 17; - + static inline var CSS_PX : Int = 5; + static inline var CSS_CM : Int = 6; static inline var CSS_MM : Int = 7; - - static inline var CSS_MS : Int = 14; - - static inline var CSS_NUMBER : Int = 1; - - static inline var CSS_PC : Int = 10; - - static inline var CSS_PERCENTAGE : Int = 2; - + static inline var CSS_IN : Int = 8; static inline var CSS_PT : Int = 9; - - static inline var CSS_PX : Int = 5; - + static inline var CSS_PC : Int = 10; + static inline var CSS_DEG : Int = 11; static inline var CSS_RAD : Int = 12; - - static inline var CSS_RECT : Int = 24; - - static inline var CSS_RGBCOLOR : Int = 25; - + static inline var CSS_GRAD : Int = 13; + static inline var CSS_MS : Int = 14; static inline var CSS_S : Int = 15; - + static inline var CSS_HZ : Int = 16; + static inline var CSS_KHZ : Int = 17; + static inline var CSS_DIMENSION : Int = 18; static inline var CSS_STRING : Int = 19; - - static inline var CSS_UNKNOWN : Int = 0; - static inline var CSS_URI : Int = 20; - - static inline var CSS_VH : Int = 27; - - static inline var CSS_VMIN : Int = 28; - - static inline var CSS_VW : Int = 26; - + static inline var CSS_IDENT : Int = 21; + static inline var CSS_ATTR : Int = 22; + static inline var CSS_COUNTER : Int = 23; + static inline var CSS_RECT : Int = 24; + static inline var CSS_RGBCOLOR : Int = 25; + var primitiveType(default,null) : Int; - - function getCounterValue() : Counter; - - function getFloatValue( unitType : Int ) : Float; - - function getRGBColorValue() : RGBColor; - - function getRectValue() : Rect; - - function getStringValue() : String; - + + /** @throws DOMError */ function setFloatValue( unitType : Int, floatValue : Float ) : Void; - + /** @throws DOMError */ + function getFloatValue( unitType : Int ) : Float; + /** @throws DOMError */ function setStringValue( stringType : Int, stringValue : String ) : Void; - -} + /** @throws DOMError */ + function getStringValue() : String; + /** @throws DOMError */ + function getCounterValue() : Dynamic/*MISSING Counter*/; + /** @throws DOMError */ + function getRectValue() : Rect; + /** @throws DOMError */ + function getRGBColorValue() : RGBColor; +} \ No newline at end of file diff --git a/std/js/html/CSSRule.hx b/std/js/html/CSSRule.hx index 0652ae11f60b8b18634c6224035323f3588cbf81..ab83fcc07d1eafcb4e889140bd9852784ce7e410 100644 --- a/std/js/html/CSSRule.hx +++ b/std/js/html/CSSRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,43 +20,24 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 3:2. Do not edit! + package js.html; -/**

An object implementing the CSSRule DOM interface represents a single CSS rule. References to a CSSRule-implementing object may be obtained by looking at a CSS style sheet's cssRules list.

-

There are several kinds of rules. The CSSRule interface specifies the properties common to all rules, while properties unique to specific rule types are specified in the more specialized interfaces for those rules' respective types.



-Documentation for this class was provided by MDN. */ @:native("CSSRule") extern class CSSRule { + static inline var UNKNOWN_RULE : Int = 0; + static inline var STYLE_RULE : Int = 1; static inline var CHARSET_RULE : Int = 2; - - static inline var FONT_FACE_RULE : Int = 5; - static inline var IMPORT_RULE : Int = 3; - - static inline var KEYFRAMES_RULE : Int = 7; - - static inline var KEYFRAME_RULE : Int = 8; - static inline var MEDIA_RULE : Int = 4; - + static inline var FONT_FACE_RULE : Int = 5; static inline var PAGE_RULE : Int = 6; - - static inline var STYLE_RULE : Int = 1; - - static inline var UNKNOWN_RULE : Int = 0; - - /** Returns the textual representation of the rule, e.g. "h1,h2 { font-size: 16pt }" Setter throws DOMException. */ + + var type(default,null) : Int; var cssText : String; - - /** Returns the containing rule, otherwise null. E.g. if this rule is a style rule inside an @media block, the parent rule would be that CSSMediaRule. */ - var parentRule(default,null) : CSSRule; - - /** Returns the CSSStyleSheet object for the style sheet that contains this rule */ var parentStyleSheet(default,null) : CSSStyleSheet; - - /** One of the Type constants indicating the type of CSS rule. */ - var type(default,null) : Int; - -} + var parentRule(default,null) : CSSRule; + +} \ No newline at end of file diff --git a/std/js/html/CSSRuleList.hx b/std/js/html/CSSRuleList.hx index 93cf30971f1d0c0392faf74c4c833e66987fde3a..5c7af25079f857955744808a000401975b7f86ee 100644 --- a/std/js/html/CSSRuleList.hx +++ b/std/js/html/CSSRuleList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSRuleList.webidl line 7:0. Do not edit! + package js.html; -/** A CSSRuleList is an array-like object containing an ordered collection of CSSRule objects.

-Documentation for this class was provided by MDN. */ @:native("CSSRuleList") extern class CSSRuleList implements ArrayAccess { var length(default,null) : Int; - + function item( index : Int ) : CSSRule; - -} +} \ No newline at end of file diff --git a/std/js/html/CSSStyleDeclaration.hx b/std/js/html/CSSStyleDeclaration.hx index 1494ba128ca505e216d58fcbf14ff9a7ffe7adbf..745865864ea677e2e04453b85d2fed497ab9e9db 100644 --- a/std/js/html/CSSStyleDeclaration.hx +++ b/std/js/html/CSSStyleDeclaration.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,612 +20,696 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSStyleDeclaration.webidl line 12:0. Do not edit! + package js.html; -/**

A CSSStyleDeclaration is an interface to the declaration block returned by the style property of a cssRule in a stylesheet, when the rule is a CSSStyleRule.

-

CSSStyleDeclaration is also a read-only interface to the result of getComputedStyle.



-Documentation for this class was provided by MDN. */ @:native("CSSStyleDeclaration") extern class CSSStyleDeclaration implements ArrayAccess { - /** Textual representation of the declaration block. Setting this attribute changes the style. Setter throws DOMException. */ var cssText : String; - - /** The number of properties. See the item method below. */ var length(default,null) : Int; - - /** The containing cssRule. */ var parentRule(default,null) : CSSRule; - - /** The animation CSS property is a shorthand property for animation-name -, animation-duration -, animation-timing-function -, animation-delay -, animation-iteration-count - and animation-direction -. */ - var animation : String; - - /** The animation-delay CSS property specifies when the animation should start. This lets the animation sequence begin some time after it's applied to an element. */ - var animationDelay : String; - - /** The animation-direction CSS property indicates whether the animation should play in reverse on alternate cycles. */ - var animationDirection : String; - - /** The animation-duration CSS property specifies the length of time that an animation should take to complete one cycle. */ - var animationDuration : String; - - /** The animation-iteration-count CSS property defines the number of times an animation cycle should be played before stopping. */ - var animationIterationCount : String; - - /** The animation-name CSS property specifies a list of animations that should be applied to the selected element. Each name indicates a @keyframes - at-rule that defines the property values for the animation sequence. */ - var animationName : String; - - /** The animation-play-state CSS property determines whether an animation is running or paused. You can query this property's value to determine whether or not the animation is currently running; in addition, you can set its value to pause and resume playback of an animation. */ - var animationPlayState : String; - - /** The animation-timing-function CSS property specifies how a CSS animation should progress over the duration of each cycle. The possible values are one or several <timing-function> - . */ - var animationTimingFunction : String; - - /** In combination with elevation, azimuth enables different audio sources to be positioned spatially for aural presentation. This is important in that it provides a natural way to tell several voices apart, as each can be positioned to originate at a different location on the sound stage. Stereo output produce a lateral sound stage, while binaural headphones and multi-speaker setups allow for a fully three-dimensional stage. */ - var azimuth : String; - - /** The backface-visibility CSS property determines whether or not the back face of the element is visible when facing the user. The back face of an element always is a transparent background, letting, when visible, a mirror image of the front face be displayed. */ - var backfaceVisibility : String; - - /** The background CSS property is a shorthand for setting the individual background values in a single place in the style sheet. background can be used to set the values for one or more of: background-color -, background-image -, background-position -, background-repeat -, background-size -, and background-attachment -. */ - var background : String; - - /** If a background-image - is specified, the background-attachment CSS property determines whether that image's position is fixed within the viewport, or scrolls along with its containing block. */ - var backgroundAttachment : String; - - /** The background-clip CSS property specifies whether an element's background, either the color or image, extends underneath its border. */ - var backgroundClip : String; - - /** The background-color CSS property sets the background color of an element, either through a color value or the keyword transparent. */ - var backgroundColor : String; - - /** The background-image CSS property sets the background images for an element. The images are drawn on successive stacking context layers, with the first specified being drawn as if it is the closest to the user. The borders of the element are then drawn on top of them, and the background-color - is drawn beneath them. */ - var backgroundImage : String; - - /** The background-origin CSS property determines the background positioning area, that is the position of the origin of an image specified using the background-image - CSS property. */ - var backgroundOrigin : String; - - /** The background-position CSS property sets the initial position, relative to the background position layer defined by background-origin - for each defined background image. */ - var backgroundPosition : String; - - /** The background-repeat CSS property defines how background images are repeated. A background image can be repeated along the horizontal axis, the vertical axis, both, or not repeated at all. When the repetition of the image tiles doesn't let them exactly cover the background, the way adjustments are done can be controlled by the author: by default, the last image is clipped, but the different tiles can instead be re-sized, or space can be inserted between the tiles. */ - var backgroundRepeat : String; - - /** The background-size CSS property specifies the size of the background images. */ - var backgroundSize : String; - - /** This property specifies the extent of the page bleed area outside the page box. This property only has effect if crop marks are enabled. */ - var bleed : String; - - /** The border CSS property is a shorthand property for setting the individual border property values in a single place in the style sheet. border can be used to set the values for one or more of: border-width -, border-style -, border-color -. */ - var border : String; - - /** The border-bottom CSS property is a shorthand that sets the values of border-bottom-color -, border-bottom-style -, and border-bottom-width -. These properties describe the bottom border of elements. */ - var borderBottom : String; - - /** The border-bottom-color CSS property sets the color of the bottom border of an element. Note that in many cases the shorthand CSS properties  border-color - or border-bottom - are more convenient and preferable. */ - var borderBottomColor : String; - - /** The border-bottom-left-radius CSS property sets the rounding of the bottom-left corner of the element. The rounding can be a circle or an ellipse, or if one of the value is 0 no rounding is done and the corner is square. */ - var borderBottomLeftRadius : String; - - /** The border-bottom-right-radius CSS property sets the rounding of the bottom-right corner of the element. The rounding can be a circle or an ellipse, or if one of the value is 0 no rounding is done and the corner is square. */ - var borderBottomRightRadius : String; - - /** The border-bottom-style CSS property sets the line style of the bottom border of a box. */ - var borderBottomStyle : String; - - /** The border-bottom-width CSS property sets the width of the bottom border of a box. */ - var borderBottomWidth : String; - - /** The border-collapse CSS property selects a table's border model. This has a big influence on the look and style of the table cells. */ - var borderCollapse : String; - - /** The border-color CSS property is a shorthand for setting the color of the four sides of an element's border: border-top-color -, border-right-color -, border-bottom-color -, border-left-color */ - var borderColor : String; - - /** The border-image CSS property allows drawing an image on the borders of elements. This makes drawing complex looking widgets much simpler than it has been and removes the need for nine boxes in some cases. */ - var borderImage : String; - - /** The border-image-outset property describes, by which amount border image area extends beyond the border box. */ - var borderImageOutset : String; - - /** The border-image-repeat CSS property defines how the middle part of a border image is handled to match the size of the border. It has a one-value syntax which describes the behavior for all sides, and a two-value syntax that sets a different value for the horizontal and vertical behavior. */ - var borderImageRepeat : String; - - /** The border-image-source CSS property defines the <image> - to use instead of the style of the border. If this property is set to none, the style defined by border-style - is used instead. */ - var borderImageSource : String; - - /** The border-image-width CSS property defines the offset to use for dividing the border image in nine parts, the top-left corner, central top edge, top-right-corner, central right edge, bottom-right corner, central bottom edge, bottom-left corner, and central right edge. They represent inward distance from the top, right, bottom and right edges. */ - var borderImageWidth : String; - - /** The border-left CSS property is a shorthand that sets the values of border-left-color -, border-left-style -, and border-left-width -. These properties describe the left border of elements. */ - var borderLeft : String; - - /** The border-left-color CSS property sets the color of the bottom border of an element. Note that in many cases the shorthand CSS properties  border-color - or border-left - are more convenient and preferable. */ - var borderLeftColor : String; - - /** The border-left-style CSS property sets the line style of the left border of a box. */ - var borderLeftStyle : String; - - /** The border-left-width CSS property sets the width of the left border of a box. */ - var borderLeftWidth : String; - - /** The border-radius CSS property allows Web authors to define how rounded border corners are. The curve of each corner is defined using one or two radii, defining its shape: circle or ellipse. */ - var borderRadius : String; - - /** The border-right CSS property is a shorthand that sets the values of border-right-color -, border-right-style -, and border-right-width -. These properties describe the right border of elements. */ - var borderRight : String; - - /** The border-right-color CSS property sets the color of the bottom border of an element. Note that in many cases the shorthand CSS properties  border-color - or border-right - are more convenient and preferable. */ - var borderRightColor : String; - - /** The border-right-style CSS property sets the line style of the right border of a box. */ - var borderRightStyle : String; - - /** The border-right-width CSS property sets the width of the right border of a box. */ - var borderRightWidth : String; - - /** The border-spacing CSS property specifies the distance between the borders of adjacent cells (only for the separated borders model). This is equivalent to the cellspacing attribute in presentational HTML, but an optional second value can be used to set different horizontal and vertical spacing. */ - var borderSpacing : String; - - /** The border-style CSS property is a shorthand property for setting the line style for all four sides of the elements border. */ - var borderStyle : String; - - /** The border-top CSS property is a shorthand that sets the values of border-top-color -, border-top-style -, and border-top-width -. These properties describe the top border of elements. */ - var borderTop : String; - - /** The border-top-color CSS property sets the color of the top border of an element. Note that in many cases the shorthand CSS properties  border-color - or border-top - are more convenient and preferable. */ - var borderTopColor : String; - - /** The border-top-left-radius CSS property sets the rounding of the top-left corner of the element. The rounding can be a circle or an ellipse, or if one of the value is 0 no rounding is done and the corner is square. */ - var borderTopLeftRadius : String; - - /** The border-top-right-radius CSS property sets the rounding of the top-right corner of the element. The rounding can be a circle or an ellipse, or if one of the value is 0 no rounding is done and the corner is square. */ - var borderTopRightRadius : String; - - /** The border-top-style CSS property sets the line style of the top border of a box. */ - var borderTopStyle : String; - - /** The border-top-width CSS property sets the width of the top border of a box. */ - var borderTopWidth : String; - - /** The border-width CSS property sets the width of the border of a box. Using the shorthand property border - is often more convenient. */ - var borderWidth : String; - - /** The bottom CSS property participates in specifying the position of positioned elements. */ - var bottom : String; - - /** The box-shadow CSS property accepts one or more shadow effects as a comma-separated list. It allows casting a drop shadow from the frame of almost any element. If a border-radius - is specified on the element with a box shadow, the box shadow takes on the same rounded corners. The z-ordering of multiple box shadows is the same as multiple text shadows (the first specified shadow is on top). */ - var boxShadow : String; - - /** The box-sizing CSS property is used to alter the default CSS box model used to calculate widths and heights of elements. It is possible to use this property to emulate the behavior of browsers that do not correctly support the CSS box model specification. */ - var boxSizing : String; - - /** The caption-side CSS property positions the content of a table's <caption> - on the specified side. */ - var captionSide : String; - - /** The clear CSS property specifies whether an element can be next to floating elements that precede it or must be moved down (cleared) below them. */ - var clear : String; - - /** The clip CSS property defines what portion of an element is visible. The clip property applies only to elements with position:absolute -. */ - var clip : String; - - /** The color CSS property sets the foreground color of an element's text content */ - var color : String; - - /** The column-count CSS property describes the number of columns of the element. */ - var columnCount : String; - - /** The column-fill CSS property controls how contents are partitioned into columns. Contents are either balanced, which means that contents in all columns will have the same height or, when using auto, just take up the room the content needs. */ - var columnFill : String; - - /** The column-gap CSS property sets the size of the gap between columns for elements which are specified to display as a multi-column element. */ - var columnGap : String; - - /** In multi-column layouts, the column-rule CSS property specifies a straight line, or "rule", to be drawn between each column. It is a convenient shorthand to avoid setting each of the individual column-rule-* properties separately : column-rule-width -, column-rule-style - and column-rule-color -. */ - var columnRule : String; - - /** The column-rule-color CSS property lets you set the color of the rule drawn between columns in multi-column layouts. */ - var columnRuleColor : String; - - /** The column-rule-style CSS property lets you set the style of the rule drawn between columns in multi-column layouts. */ - var columnRuleStyle : String; - - /** The column-rule-width CSS property lets you set the width of the rule drawn between columns in multi-column layouts. */ - var columnRuleWidth : String; - - /** The column-span CSS property makes it possible for an element to span across all columns when its value is set to all. An element that spans more than one column is called a spanning element. */ - var columnSpan : String; - - /** The column-width CSS property suggests an optimal column width. This is not a absolute value but a mere hint. Browser will adjust the width of the column around that suggested value, allowing to achieve scalable designs that fit different screen size. Especially in presence of the column-count - CSS property which has precedence, to set an exact column width, all length values must be specified. In horizontal text these are width -, column-width -, column-gap -, and column-rule-width -. */ - var columnWidth : String; - - /** The columns CSS property is a shorthand property allowing to set both the column-width - and the column-count - properties at the same time. */ - var columns : String; - - /** The content CSS property is used with the :before - and :after - pseudo-elements to generate content in an element. */ - var content : String; - - /** The counter-increment CSS property is used to increase the value of CSS Counters by a given value. The counter's value can be reset using the counter-reset - CSS property. */ - var counterIncrement : String; - - /** The counter-reset CSS property is used to reset CSS Counters to a given value. */ - var counterReset : String; - - /** The cursor CSS property specifies the mouse cursor displayed when the mouse pointer is over an element. */ - var cursor : String; - - /** The direction CSS property should be set to match the direction of the text: rtl for Hebrew or Arabic text and ltr for other scripts. This should normally be done as part of the document (e.g., using the dir attribute in HTML) rather than through direct use of CSS. */ - var direction : String; - - /** The display CSS property specifies the type of rendering box used for an element. In HTML, default display property values are taken from behaviors described in the HTML specifications or from the browser/user default stylesheet. The default value in XML is inline. */ - var display : String; - - /** The empty-cells CSS property specifies how user agent should render borders and backgrounds around cells that have no visible content. */ - var emptyCells : String; - - /** The float CSS property specifies that an element should be taken from the normal flow and placed along the left or right side of its container, where text and inline elements will wrap around it. */ - var float : String; - - /** The font CSS property is either a shorthand property for setting font-style -, font-variant -, font-weight -, font-size -, line-height - and font-family -, or a way to set the element's font to a system font, using specific keywords. */ - var font : String; - - /** The font-family CSS property allows for a prioritized list of font family names and/or generic family names to be specified for the selected element. Unlike most other CSS properties, values are separated by a comma to indicate that they are alternatives. The browser will select the first font on the list that is installed on the computer, or that can be downloaded using the information provided by a @font-face - at-rule. */ - var fontFamily : String; - - /** The font-size CSS property specifies the size of the font. The font size may, in turn, change the size of other items, since it is used to compute the value of em and ex length units. */ - var fontSize : String; - - /** The font-size-adjust CSS property specifies that font size should be chosen based on the height of lowercase letters rather than the height of capital letters. */ - var fontSizeAdjust : String; - - /** The font-stretch CSS property selects a normal, condensed, or extended face from a font family. */ - var fontStretch : String; - - /** The font-style CSS property allows italic or oblique faces to be selected within a font-family -.
*/ - var fontStyle : String; - - /** The font-variant CSS property selects a normal, or small-caps face from a font family. Setting font-variant is also possible by using the font - shorthand. */ - var fontVariant : String; - - /** The font-weight - CSS property specifies the weight or boldness of the font. However, some fonts are not available in all weights; some are available only on normal and bold. */ - var fontWeight : String; - - /** The height CSS property specifies the height of the content area of an element. The content area is inside the padding, border, and margin of the element. */ - var height : String; - - /** The hyphens CSS property tells the browser how to go about splitting words to improve the layout of text when line-wrapping. */ - var hyphens : String; - - /** The image-rendering CSS property provides a hint to the user agent about how to handle its image rendering.
image-rendering applies to scaled images (and other elements, see below). For example, if the natural size of the image is 100×100px but the page author specifies the dimensions to 200×200px (or50×50px), then the image will be upscaled (or downscaled) to the new dimensions using the specified algorithm. Scaling may also apply due to user interaction (zooming). */ - var imageRendering : String; - - /** The left CSS property specifies part of the position of positioned elements. */ - var left : String; - - /** The letter-spacing CSS property specifies spacing behavior between text characters. */ - var letterSpacing : String; - - /** On inline elements, the line-height CSS property specifies the height that is used in the calculation of the line box height.
-On block level elements, line-height specifies the minimal height of line boxes within the element. */ - var lineHeight : String; - - /** The list-style CSS property is a shorthand property for setting list-style-type -, list-style-image - and list-style-position -. */ - var listStyle : String; - - /** The list-style-image CSS property sets the image that will be used as the list item marker. It is often more convenient to use the shortcut list-style -. */ - var listStyleImage : String; - - /** The list-style-position CSS property specifies the position of the marker box in the principal block box. It is often more convenient to use the shortcut list-style -. */ - var listStylePosition : String; - - /** The list-style-type CSS property specifies appearance of a list item element. As it is the only one who defaults to display:list-item, this is usually a <li> - element, but can be any element with this display - value. */ - var listStyleType : String; - - /** The margin CSS property sets the margin for all four sides. It is a shorthand to avoid setting each side separately with the other margin properties:
-margin-top -, margin-right -, margin-bottom - and margin-left -.
-Negative value are also allowed. */ - var margin : String; - - /** The margin-bottom CSS property of an element sets the margin space required on the bottom of an element. A negative value is also allowed. */ - var marginBottom : String; - - /** The margin-left CSS property of an element sets the margin space required on the left side of an element. A negative value is also allowed. */ - var marginLeft : String; - - /** The margin-right CSS property of an element sets the margin space required on the right side of an element. A negative value is also allowed. */ - var marginRight : String; - - /** The margin-top CSS property of an element sets the margin space required on the top of an element. A negative value is also allowed. */ - var marginTop : String; - - /**   */ - var markerOffset : String; - - /** The marks CSS property adds crop and/or cross marks to the presentation of the document. Crop marks indicate where the page should be cut. Cross marks are used to align sheets. */ - var marks : String; - - /** The max-height CSS property is used to set the maximum height of a given element. It prevents the used value of the height - property from becoming larger than the value specified for max-height. */ - var maxHeight : String; - - /** The max-width CSS property is used to set the maximum width of a given element. It prevents the used value of the width - property from becoming larger than the value specified for max-width. */ - var maxWidth : String; - - /** The min-height CSS property is used to set the minimum height of a given element. It prevents the used value of the height - property from becoming smaller than the value specified for min-height. */ - var minHeight : String; - - /** The min-width CSS property is used to set the minimum width of a given element. It prevents the used value of the width - property from becoming smaller than the value specified for min-width. */ - var minWidth : String; - - /** The opacity CSS property specifies the transparency of an element, that is, the degree to which the background behind the element is overlaid. */ - var opacity : String; - - /** The orphans CSS property refers to the minimum number of lines in a block container that must be left at the bottom of the page.  This property is normally used to control how page breaks occur. */ - var orphans : String; - - /** The outline CSS property is a shorthand property for setting one or more of the individual outline properties outline-style -, outline-width - and outline-color - in a single rule. In most cases the use of this shortcut is preferable and more convenient. */ - var outline : String; - - /** The outline-color CSS property sets the color of the outline of an element. An outline is a line that is drawn around elements, outside the border edge, to make the element stand out. */ - var outlineColor : String; - - /** The outline-offset CSS property is used to set space between an outline - and the edge or border of an element. An outline is a line that is drawn around elements, outside the border edge. */ - var outlineOffset : String; - - /** The outline-style CSS property is used to set the style of the outline of an element. An outline is a line that is drawn around elements, outside the border edge, to make the element stand out. */ - var outlineStyle : String; - - /** The outline-width CSS property is used to set the width of the outline of an element. An outline is a line that is drawn around elements, outside the border edge, to make the element stand out: */ - var outlineWidth : String; - - /** The overflow CSS property specifies whether to clip content, render scroll bars or display overflow content of a block-level element. */ - var overflow : String; - - /** The overflow-x CSS property specifies whether to clip content, render a scroll bar or display overflow content of a block-level element, when it overflows at the left and right edges. */ - var overflowX : String; - - /** The padding CSS property sets the required padding space on all sides of an element. The padding area is the space between the content of the element and its border. Negative values are not allowed. */ - var padding : String; - - /** The padding-bottom CSS property of an element sets the padding space required on the bottom of an element. The padding area is the space between the content of the element and it's border. A negative value is not allowed. */ - var paddingBottom : String; - - /** The padding-left CSS property of an element sets the padding space required on the left side of an element. The padding area is the space between the content of the element and it's border. A negative value is not allowed. */ - var paddingLeft : String; - - /** The padding-right CSS property of an element sets the padding space required on the right side of an element. The padding area is the space between the content of the element and its border. Negative values are not allowed. */ - var paddingRight : String; - - /** The padding-top CSS property of an element sets the padding space required on the top of an element. The padding area is the space between the content of the element and it's border. A negative values is not allowed. */ - var paddingTop : String; - - /** The page-break-after CSS property adjusts page breaks after the current element. */ - var pageBreakAfter : String; - - /** The page-break-before CSS property adjusts page breaks before the current element. */ - var pageBreakBefore : String; - - /** The page-break-inside CSS property adjusts page breaks inside the current element. */ - var pageBreakInside : String; - - /** The perspective CSS property determines the distance between the z=0 plane and the user in order to give to the 3D-positioned element some perspective. Each 3D element that is placed between the z=0 and the user is enlarged, each 3D-element with z<0 is shrinked. How much deformation is defined by the value of this property. */ - var perspective : String; - - /** The perspective-origin CSS property determines the position the viewer is looking at. It is used as the vanishing point by the perspective - property. */ - var perspectiveOrigin : String; - - /** The position CSS property chooses alternative rules for positioning elements, designed to be useful for scripted animation effects. */ - var position : String; - - /** The quotes CSS property indicates how user agents should render quotation marks. */ - var quotes : String; - - /** The resize CSS property lets you control the resizability of an element. */ - var resize : String; - - /** The right CSS property specifies part of the position of positioned elements. */ - var right : String; - - /** The tab-size CSS property is used to customize the width of a tab (U+0009) character. */ - var tabSize : String; - - /** The table-layout CSS property defines the algorithm to be used to layout the table cells, rows, and columns. */ - var tableLayout : String; - - /** The text-align CSS property describes how inline content like text is aligned in its parent block element. text-align does not control the alignment of block elements itself, only their inline content. */ - var textAlign : String; - - /** The text-align-last CSS property describes how the last line of a block or a line right before a forced line break is aligned. */ - var textAlignLast : String; - - /** The text-decoration CSS property is used to set the text formattings underline, overline, line-through and blink. */ - var textDecoration : String; - - /** The text-decoration-color CSS property sets the color used when drawing underlines, overlines, or strike-throughs specified by text-decoration-line -. This is the preferred way to color these text decorations, rather than using combinations of other HTML elements. */ - var textDecorationColor : String; - - /** The text-decoration-line CSS property sets what kind of line decorations are added to an element. */ - var textDecorationLine : String; - - /** The text-decoration-style CSS property defines the style of the lines specified by text-decoration-line -. The style applies to all lines, there is no way to define different style for each of the line defined by text-decoration-line. */ - var textDecorationStyle : String; - - /** The text-indent CSS property specifies how much horizontal space should be left before beginning of the first line of the text content of an element. Horizontal spacing is with respect to the left (or right, for right-to-left layout) edge of the containing block element's box. */ - var textIndent : String; - - /** The text-shadow CSS property adds shadows to text. It accepts a comma-separated list of shadows to be applied to the text and text-decorations - of the element. */ - var textShadow : String; - - /** The text-transform CSS property specifies how to capitalize an element's text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized. */ - var textTransform : String; - - /** The top CSS property specifies part of the position of positioned elements. It has no effect on non-positioned elements. */ - var top : String; - - /** The transform CSS property lets you modify the coordinate space of the CSS visual formatting model. Using it, elements can be translated, rotated, scaled, and skewed according to the values set. */ - var transform : String; - - /** The transform-origin CSS property lets you modify the origin for transformations of an element. For example, the transform-origin of the rotate() function is the centre of rotation. (This property is applied by first translating the element by the negated value of the property, then applying the element's transform, then translating by the property value.) */ - var transformOrigin : String; - - /** The transform-style CSS property determines if the children of the element are positioned in the 3D-space or are flattened in the plane of the element. */ - var transformStyle : String; - - /** The transition CSS property is a shorthand property for transition-property -, transition-duration -, transition-timing-function -, and transition-delay -. */ - var transition : String; - - /** The transition-delay CSS property specifies the amount of time to wait between a change being requested to a property that is to be transitioned and the start of the transition effect. */ - var transitionDelay : String; - - /** The transition-duration CSS property specifies the number of seconds or milliseconds a transition animation should take to complete. By default, the value is 0s, meaning that no animation will occur. */ - var transitionDuration : String; - - /** The transition-property CSS property is used to specify the names of CSS properties to which a transition effect should be applied. */ - var transitionProperty : String; - - /** The transition-timing-function CSS property is used to describe how the intermediate values of the CSS properties being affected by a transition effect are calculated. This in essence lets you establish an acceleration curve, so that the speed of the transition can vary over its duration. */ - var transitionTimingFunction : String; - - /** The vertical-align CSS property specifies the vertical alignment of an inline or table-cell element. */ - var verticalAlign : String; - - /** The visibility CSS property is used for two things: */ - var visibility : String; - - /** The white-space CSS property is used to to describe how whitespace inside the element is handled. */ - var whiteSpace : String; - - /** where: */ - var widows : String; - - /** The width CSS property specifies the width of the content area of an element. The content area is inside the padding, border, and margin of the element. */ - var width : String; - - /** The word-spacing CSS property specifies spacing behavior between tags and words. */ - var wordSpacing : String; - - /** The word-wrap CSS property is used to to specify whether or not the browser is allowed to break lines within words in order to prevent overflow when an otherwise unbreakable string is too long to fit. */ - var wordWrap : String; - - /** The z-index CSS property specifies the z-order of an element and its descendants. When elements overlap, z-order determines which one covers the other. An element with a larger z-index generally covers an element with a lower one. */ - var zIndex : String; - - function getPropertyCSSValue( propertyName : String ) : CSSValue; - - function getPropertyPriority( propertyName : String ) : String; - - function getPropertyShorthand( propertyName : String ) : String; - - function getPropertyValue( propertyName : String ) : String; - - function isPropertyImplicit( propertyName : String ) : Bool; - + + /** Shorthand for the "align-content" CSS property. */ + var alignContent :String; + /** Shorthand for the "align-items" CSS property. */ + var alignItems :String; + /** Shorthand for the "align-self" CSS property. */ + var alignSelf :String; + /** Shorthand for the "alignment-adjust" CSS property. */ + var alignmentAdjust :String; + /** Shorthand for the "alignment-baseline" CSS property. */ + var alignmentBaseline :String; + /** Shorthand for the "all" CSS property. */ + var all :String; + /** Shorthand for the "anchor-point" CSS property. */ + var anchorPoint :String; + /** Shorthand for the "animation" CSS property. */ + var animation :String; + /** Shorthand for the "animation-delay" CSS property. */ + var animationDelay :String; + /** Shorthand for the "animation-direction" CSS property. */ + var animationDirection :String; + /** Shorthand for the "animation-duration" CSS property. */ + var animationDuration :String; + /** Shorthand for the "animation-fill-mode" CSS property. */ + var animationFillMode :String; + /** Shorthand for the "animation-iteration-count" CSS property. */ + var animationIterationCount :String; + /** Shorthand for the "animation-name" CSS property. */ + var animationName :String; + /** Shorthand for the "animation-play-state" CSS property. */ + var animationPlayState :String; + /** Shorthand for the "animation-timing-function" CSS property. */ + var animationTimingFunction :String; + /** Shorthand for the "azimuth" CSS property. */ + var azimuth :String; + /** Shorthand for the "backface-visibility" CSS property. */ + var backfaceVisibility :String; + /** Shorthand for the "background" CSS property. */ + var background :String; + /** Shorthand for the "background-attachment" CSS property. */ + var backgroundAttachment :String; + /** Shorthand for the "background-clip" CSS property. */ + var backgroundClip :String; + /** Shorthand for the "background-color" CSS property. */ + var backgroundColor :String; + /** Shorthand for the "background-image" CSS property. */ + var backgroundImage :String; + /** Shorthand for the "background-origin" CSS property. */ + var backgroundOrigin :String; + /** Shorthand for the "background-position" CSS property. */ + var backgroundPosition :String; + /** Shorthand for the "background-repeat" CSS property. */ + var backgroundRepeat :String; + /** Shorthand for the "background-size" CSS property. */ + var backgroundSize :String; + /** Shorthand for the "baseline-shift" CSS property. */ + var baselineShift :String; + /** Shorthand for the "binding" CSS property. */ + var binding :String; + /** Shorthand for the "bleed" CSS property. */ + var bleed :String; + /** Shorthand for the "bookmark-label" CSS property. */ + var bookmarkLabel :String; + /** Shorthand for the "bookmark-level" CSS property. */ + var bookmarkLevel :String; + /** Shorthand for the "bookmark-state" CSS property. */ + var bookmarkState :String; + /** Shorthand for the "border" CSS property. */ + var border :String; + /** Shorthand for the "border-bottom" CSS property. */ + var borderBottom :String; + /** Shorthand for the "border-bottom-color" CSS property. */ + var borderBottomColor :String; + /** Shorthand for the "border-bottom-left-radius" CSS property. */ + var borderBottomLeftRadius :String; + /** Shorthand for the "border-bottom-right-radius" CSS property. */ + var borderBottomRightRadius :String; + /** Shorthand for the "border-bottom-style" CSS property. */ + var borderBottomStyle :String; + /** Shorthand for the "border-bottom-width" CSS property. */ + var borderBottomWidth :String; + /** Shorthand for the "border-collapse" CSS property. */ + var borderCollapse :String; + /** Shorthand for the "border-color" CSS property. */ + var borderColor :String; + /** Shorthand for the "border-image" CSS property. */ + var borderImage :String; + /** Shorthand for the "border-image-outset" CSS property. */ + var borderImageOutset :String; + /** Shorthand for the "border-image-repeat" CSS property. */ + var borderImageRepeat :String; + /** Shorthand for the "border-image-slice" CSS property. */ + var borderImageSlice :String; + /** Shorthand for the "border-image-source" CSS property. */ + var borderImageSource :String; + /** Shorthand for the "border-image-width" CSS property. */ + var borderImageWidth :String; + /** Shorthand for the "border-left" CSS property. */ + var borderLeft :String; + /** Shorthand for the "border-left-color" CSS property. */ + var borderLeftColor :String; + /** Shorthand for the "border-left-style" CSS property. */ + var borderLeftStyle :String; + /** Shorthand for the "border-left-width" CSS property. */ + var borderLeftWidth :String; + /** Shorthand for the "border-radius" CSS property. */ + var borderRadius :String; + /** Shorthand for the "border-right" CSS property. */ + var borderRight :String; + /** Shorthand for the "border-right-color" CSS property. */ + var borderRightColor :String; + /** Shorthand for the "border-right-style" CSS property. */ + var borderRightStyle :String; + /** Shorthand for the "border-right-width" CSS property. */ + var borderRightWidth :String; + /** Shorthand for the "border-spacing" CSS property. */ + var borderSpacing :String; + /** Shorthand for the "border-style" CSS property. */ + var borderStyle :String; + /** Shorthand for the "border-top" CSS property. */ + var borderTop :String; + /** Shorthand for the "border-top-color" CSS property. */ + var borderTopColor :String; + /** Shorthand for the "border-top-left-radius" CSS property. */ + var borderTopLeftRadius :String; + /** Shorthand for the "border-top-right-radius" CSS property. */ + var borderTopRightRadius :String; + /** Shorthand for the "border-top-style" CSS property. */ + var borderTopStyle :String; + /** Shorthand for the "border-top-width" CSS property. */ + var borderTopWidth :String; + /** Shorthand for the "border-width" CSS property. */ + var borderWidth :String; + /** Shorthand for the "bottom" CSS property. */ + var bottom :String; + /** Shorthand for the "box-decoration-break" CSS property. */ + var boxDecorationBreak :String; + /** Shorthand for the "box-shadow" CSS property. */ + var boxShadow :String; + /** Shorthand for the "box-sizing" CSS property. */ + var boxSizing :String; + /** Shorthand for the "box-snap" CSS property. */ + var boxSnap :String; + /** Shorthand for the "box-suppress" CSS property. */ + var boxSuppress :String; + /** Shorthand for the "break-after" CSS property. */ + var breakAfter :String; + /** Shorthand for the "break-before" CSS property. */ + var breakBefore :String; + /** Shorthand for the "break-inside" CSS property. */ + var breakInside :String; + /** Shorthand for the "caption-side" CSS property. */ + var captionSide :String; + /** Shorthand for the "chains" CSS property. */ + var chains :String; + /** Shorthand for the "clear" CSS property. */ + var clear :String; + /** Shorthand for the "clip" CSS property. */ + var clip :String; + /** Shorthand for the "clip-path" CSS property. */ + var clipPath :String; + /** Shorthand for the "clip-rule" CSS property. */ + var clipRule :String; + /** Shorthand for the "color" CSS property. */ + var color :String; + /** Shorthand for the "color-interpolation-filters" CSS property. */ + var colorInterpolationFilters :String; + /** Shorthand for the "column-count" CSS property. */ + var columnCount :String; + /** Shorthand for the "column-fill" CSS property. */ + var columnFill :String; + /** Shorthand for the "column-gap" CSS property. */ + var columnGap :String; + /** Shorthand for the "column-rule" CSS property. */ + var columnRule :String; + /** Shorthand for the "column-rule-color" CSS property. */ + var columnRuleColor :String; + /** Shorthand for the "column-rule-style" CSS property. */ + var columnRuleStyle :String; + /** Shorthand for the "column-rule-width" CSS property. */ + var columnRuleWidth :String; + /** Shorthand for the "column-span" CSS property. */ + var columnSpan :String; + /** Shorthand for the "column-width" CSS property. */ + var columnWidth :String; + /** Shorthand for the "columns" CSS property. */ + var columns :String; + /** Shorthand for the "contain" CSS property. */ + var contain :String; + /** Shorthand for the "content" CSS property. */ + var content :String; + /** Shorthand for the "counter-increment" CSS property. */ + var counterIncrement :String; + /** Shorthand for the "counter-reset" CSS property. */ + var counterReset :String; + /** Shorthand for the "counter-set" CSS property. */ + var counterSet :String; + /** Shorthand for the "crop" CSS property. */ + var crop :String; + /** Shorthand for the "cue" CSS property. */ + var cue :String; + /** Shorthand for the "cue-after" CSS property. */ + var cueAfter :String; + /** Shorthand for the "cue-before" CSS property. */ + var cueBefore :String; + /** Shorthand for the "cursor" CSS property. */ + var cursor :String; + /** Shorthand for the "direction" CSS property. */ + var direction :String; + /** Shorthand for the "display" CSS property. */ + var display :String; + /** Shorthand for the "display-inside" CSS property. */ + var displayInside :String; + /** Shorthand for the "display-list" CSS property. */ + var displayList :String; + /** Shorthand for the "display-outside" CSS property. */ + var displayOutside :String; + /** Shorthand for the "dominant-baseline" CSS property. */ + var dominantBaseline :String; + /** Shorthand for the "elevation" CSS property. */ + var elevation :String; + /** Shorthand for the "empty-cells" CSS property. */ + var emptyCells :String; + /** Shorthand for the "filter" CSS property. */ + var filter :String; + /** Shorthand for the "flex" CSS property. */ + var flex :String; + /** Shorthand for the "flex-basis" CSS property. */ + var flexBasis :String; + /** Shorthand for the "flex-direction" CSS property. */ + var flexDirection :String; + /** Shorthand for the "flex-flow" CSS property. */ + var flexFlow :String; + /** Shorthand for the "flex-grow" CSS property. */ + var flexGrow :String; + /** Shorthand for the "flex-shrink" CSS property. */ + var flexShrink :String; + /** Shorthand for the "flex-wrap" CSS property. */ + var flexWrap :String; + /** Shorthand for the "float" CSS property. */ + var float :String; + /** Shorthand for the "float-offset" CSS property. */ + var floatOffset :String; + /** Shorthand for the "flood-color" CSS property. */ + var floodColor :String; + /** Shorthand for the "flood-opacity" CSS property. */ + var floodOpacity :String; + /** Shorthand for the "flow-from" CSS property. */ + var flowFrom :String; + /** Shorthand for the "flow-into" CSS property. */ + var flowInto :String; + /** Shorthand for the "font" CSS property. */ + var font :String; + /** Shorthand for the "font-family" CSS property. */ + var fontFamily :String; + /** Shorthand for the "font-feature-settings" CSS property. */ + var fontFeatureSettings :String; + /** Shorthand for the "font-kerning" CSS property. */ + var fontKerning :String; + /** Shorthand for the "font-language-override" CSS property. */ + var fontLanguageOverride :String; + /** Shorthand for the "font-size" CSS property. */ + var fontSize :String; + /** Shorthand for the "font-size-adjust" CSS property. */ + var fontSizeAdjust :String; + /** Shorthand for the "font-stretch" CSS property. */ + var fontStretch :String; + /** Shorthand for the "font-style" CSS property. */ + var fontStyle :String; + /** Shorthand for the "font-synthesis" CSS property. */ + var fontSynthesis :String; + /** Shorthand for the "font-variant" CSS property. */ + var fontVariant :String; + /** Shorthand for the "font-variant-alternates" CSS property. */ + var fontVariantAlternates :String; + /** Shorthand for the "font-variant-caps" CSS property. */ + var fontVariantCaps :String; + /** Shorthand for the "font-variant-east-asian" CSS property. */ + var fontVariantEastAsian :String; + /** Shorthand for the "font-variant-ligatures" CSS property. */ + var fontVariantLigatures :String; + /** Shorthand for the "font-variant-numeric" CSS property. */ + var fontVariantNumeric :String; + /** Shorthand for the "font-variant-position" CSS property. */ + var fontVariantPosition :String; + /** Shorthand for the "font-weight" CSS property. */ + var fontWeight :String; + /** Shorthand for the "grid" CSS property. */ + var grid :String; + /** Shorthand for the "grid-area" CSS property. */ + var gridArea :String; + /** Shorthand for the "grid-auto-columns" CSS property. */ + var gridAutoColumns :String; + /** Shorthand for the "grid-auto-flow" CSS property. */ + var gridAutoFlow :String; + /** Shorthand for the "grid-auto-rows" CSS property. */ + var gridAutoRows :String; + /** Shorthand for the "grid-column" CSS property. */ + var gridColumn :String; + /** Shorthand for the "grid-column-end" CSS property. */ + var gridColumnEnd :String; + /** Shorthand for the "grid-column-start" CSS property. */ + var gridColumnStart :String; + /** Shorthand for the "grid-row" CSS property. */ + var gridRow :String; + /** Shorthand for the "grid-row-end" CSS property. */ + var gridRowEnd :String; + /** Shorthand for the "grid-row-start" CSS property. */ + var gridRowStart :String; + /** Shorthand for the "grid-template" CSS property. */ + var gridTemplate :String; + /** Shorthand for the "grid-template-areas" CSS property. */ + var gridTemplateAreas :String; + /** Shorthand for the "grid-template-columns" CSS property. */ + var gridTemplateColumns :String; + /** Shorthand for the "grid-template-rows" CSS property. */ + var gridTemplateRows :String; + /** Shorthand for the "hanging-punctuation" CSS property. */ + var hangingPunctuation :String; + /** Shorthand for the "height" CSS property. */ + var height :String; + /** Shorthand for the "hyphens" CSS property. */ + var hyphens :String; + /** Shorthand for the "icon" CSS property. */ + var icon :String; + /** Shorthand for the "image-orientation" CSS property. */ + var imageOrientation :String; + /** Shorthand for the "image-resolution" CSS property. */ + var imageResolution :String; + /** Shorthand for the "ime-mode" CSS property. */ + var imeMode :String; + /** Shorthand for the "initial-letters" CSS property. */ + var initialLetters :String; + /** Shorthand for the "inline-box-align" CSS property. */ + var inlineBoxAlign :String; + /** Shorthand for the "justify-content" CSS property. */ + var justifyContent :String; + /** Shorthand for the "justify-items" CSS property. */ + var justifyItems :String; + /** Shorthand for the "justify-self" CSS property. */ + var justifySelf :String; + /** Shorthand for the "left" CSS property. */ + var left :String; + /** Shorthand for the "letter-spacing" CSS property. */ + var letterSpacing :String; + /** Shorthand for the "lighting-color" CSS property. */ + var lightingColor :String; + /** Shorthand for the "line-box-contain" CSS property. */ + var lineBoxContain :String; + /** Shorthand for the "line-break" CSS property. */ + var lineBreak :String; + /** Shorthand for the "line-grid" CSS property. */ + var lineGrid :String; + /** Shorthand for the "line-height" CSS property. */ + var lineHeight :String; + /** Shorthand for the "line-snap" CSS property. */ + var lineSnap :String; + /** Shorthand for the "line-stacking" CSS property. */ + var lineStacking :String; + /** Shorthand for the "line-stacking-ruby" CSS property. */ + var lineStackingRuby :String; + /** Shorthand for the "line-stacking-shift" CSS property. */ + var lineStackingShift :String; + /** Shorthand for the "line-stacking-strategy" CSS property. */ + var lineStackingStrategy :String; + /** Shorthand for the "list-style" CSS property. */ + var listStyle :String; + /** Shorthand for the "list-style-image" CSS property. */ + var listStyleImage :String; + /** Shorthand for the "list-style-position" CSS property. */ + var listStylePosition :String; + /** Shorthand for the "list-style-type" CSS property. */ + var listStyleType :String; + /** Shorthand for the "margin" CSS property. */ + var margin :String; + /** Shorthand for the "margin-bottom" CSS property. */ + var marginBottom :String; + /** Shorthand for the "margin-left" CSS property. */ + var marginLeft :String; + /** Shorthand for the "margin-right" CSS property. */ + var marginRight :String; + /** Shorthand for the "margin-top" CSS property. */ + var marginTop :String; + /** Shorthand for the "marker-offset" CSS property. */ + var markerOffset :String; + /** Shorthand for the "marker-side" CSS property. */ + var markerSide :String; + /** Shorthand for the "marks" CSS property. */ + var marks :String; + /** Shorthand for the "mask" CSS property. */ + var mask :String; + /** Shorthand for the "mask-box" CSS property. */ + var maskBox :String; + /** Shorthand for the "mask-box-outset" CSS property. */ + var maskBoxOutset :String; + /** Shorthand for the "mask-box-repeat" CSS property. */ + var maskBoxRepeat :String; + /** Shorthand for the "mask-box-slice" CSS property. */ + var maskBoxSlice :String; + /** Shorthand for the "mask-box-source" CSS property. */ + var maskBoxSource :String; + /** Shorthand for the "mask-box-width" CSS property. */ + var maskBoxWidth :String; + /** Shorthand for the "mask-clip" CSS property. */ + var maskClip :String; + /** Shorthand for the "mask-image" CSS property. */ + var maskImage :String; + /** Shorthand for the "mask-origin" CSS property. */ + var maskOrigin :String; + /** Shorthand for the "mask-position" CSS property. */ + var maskPosition :String; + /** Shorthand for the "mask-repeat" CSS property. */ + var maskRepeat :String; + /** Shorthand for the "mask-size" CSS property. */ + var maskSize :String; + /** Shorthand for the "mask-source-type" CSS property. */ + var maskSourceType :String; + /** Shorthand for the "mask-type" CSS property. */ + var maskType :String; + /** Shorthand for the "max-height" CSS property. */ + var maxHeight :String; + /** Shorthand for the "max-lines" CSS property. */ + var maxLines :String; + /** Shorthand for the "max-width" CSS property. */ + var maxWidth :String; + /** Shorthand for the "min-height" CSS property. */ + var minHeight :String; + /** Shorthand for the "min-width" CSS property. */ + var minWidth :String; + /** Shorthand for the "move-to" CSS property. */ + var moveTo :String; + /** Shorthand for the "nav-down" CSS property. */ + var navDown :String; + /** Shorthand for the "nav-index" CSS property. */ + var navIndex :String; + /** Shorthand for the "nav-left" CSS property. */ + var navLeft :String; + /** Shorthand for the "nav-right" CSS property. */ + var navRight :String; + /** Shorthand for the "nav-up" CSS property. */ + var navUp :String; + /** Shorthand for the "object-fit" CSS property. */ + var objectFit :String; + /** Shorthand for the "object-position" CSS property. */ + var objectPosition :String; + /** Shorthand for the "opacity" CSS property. */ + var opacity :String; + /** Shorthand for the "order" CSS property. */ + var order :String; + /** Shorthand for the "orphans" CSS property. */ + var orphans :String; + /** Shorthand for the "outline" CSS property. */ + var outline :String; + /** Shorthand for the "outline-color" CSS property. */ + var outlineColor :String; + /** Shorthand for the "outline-offset" CSS property. */ + var outlineOffset :String; + /** Shorthand for the "outline-style" CSS property. */ + var outlineStyle :String; + /** Shorthand for the "outline-width" CSS property. */ + var outlineWidth :String; + /** Shorthand for the "overflow" CSS property. */ + var overflow :String; + /** Shorthand for the "overflow-wrap" CSS property. */ + var overflowWrap :String; + /** Shorthand for the "overflow-x" CSS property. */ + var overflowX :String; + /** Shorthand for the "overflow-y" CSS property. */ + var overflowY :String; + /** Shorthand for the "padding" CSS property. */ + var padding :String; + /** Shorthand for the "padding-bottom" CSS property. */ + var paddingBottom :String; + /** Shorthand for the "padding-left" CSS property. */ + var paddingLeft :String; + /** Shorthand for the "padding-right" CSS property. */ + var paddingRight :String; + /** Shorthand for the "padding-top" CSS property. */ + var paddingTop :String; + /** Shorthand for the "page" CSS property. */ + var page :String; + /** Shorthand for the "page-break-after" CSS property. */ + var pageBreakAfter :String; + /** Shorthand for the "page-break-before" CSS property. */ + var pageBreakBefore :String; + /** Shorthand for the "page-break-inside" CSS property. */ + var pageBreakInside :String; + /** Shorthand for the "page-policy" CSS property. */ + var pagePolicy :String; + /** Shorthand for the "pause" CSS property. */ + var pause :String; + /** Shorthand for the "pause-after" CSS property. */ + var pauseAfter :String; + /** Shorthand for the "pause-before" CSS property. */ + var pauseBefore :String; + /** Shorthand for the "perspective" CSS property. */ + var perspective :String; + /** Shorthand for the "perspective-origin" CSS property. */ + var perspectiveOrigin :String; + /** Shorthand for the "pitch" CSS property. */ + var pitch :String; + /** Shorthand for the "pitch-range" CSS property. */ + var pitchRange :String; + /** Shorthand for the "play-during" CSS property. */ + var playDuring :String; + /** Shorthand for the "position" CSS property. */ + var position :String; + /** Shorthand for the "presentation-level" CSS property. */ + var presentationLevel :String; + /** Shorthand for the "quotes" CSS property. */ + var quotes :String; + /** Shorthand for the "region-fragment" CSS property. */ + var regionFragment :String; + /** Shorthand for the "resize" CSS property. */ + var resize :String; + /** Shorthand for the "rest" CSS property. */ + var rest :String; + /** Shorthand for the "rest-after" CSS property. */ + var restAfter :String; + /** Shorthand for the "rest-before" CSS property. */ + var restBefore :String; + /** Shorthand for the "richness" CSS property. */ + var richness :String; + /** Shorthand for the "right" CSS property. */ + var right :String; + /** Shorthand for the "rotation" CSS property. */ + var rotation :String; + /** Shorthand for the "rotation-point" CSS property. */ + var rotationPoint :String; + /** Shorthand for the "ruby-align" CSS property. */ + var rubyAlign :String; + /** Shorthand for the "ruby-merge" CSS property. */ + var rubyMerge :String; + /** Shorthand for the "ruby-position" CSS property. */ + var rubyPosition :String; + /** Shorthand for the "shape-image-threshold" CSS property. */ + var shapeImageThreshold :String; + /** Shorthand for the "shape-outside" CSS property. */ + var shapeOutside :String; + /** Shorthand for the "shape-margin" CSS property. */ + var shapeMargin :String; + /** Shorthand for the "size" CSS property. */ + var size :String; + /** Shorthand for the "speak" CSS property. */ + var speak :String; + /** Shorthand for the "speak-as" CSS property. */ + var speakAs :String; + /** Shorthand for the "speak-header" CSS property. */ + var speakHeader :String; + /** Shorthand for the "speak-numeral" CSS property. */ + var speakNumeral :String; + /** Shorthand for the "speak-punctuation" CSS property. */ + var speakPunctuation :String; + /** Shorthand for the "speech-rate" CSS property. */ + var speechRate :String; + /** Shorthand for the "stress" CSS property. */ + var stress :String; + /** Shorthand for the "string-set" CSS property. */ + var stringSet :String; + /** Shorthand for the "tab-size" CSS property. */ + var tabSize :String; + /** Shorthand for the "table-layout" CSS property. */ + var tableLayout :String; + /** Shorthand for the "text-align" CSS property. */ + var textAlign :String; + /** Shorthand for the "text-align-last" CSS property. */ + var textAlignLast :String; + /** Shorthand for the "text-combine-upright" CSS property. */ + var textCombineUpright :String; + /** Shorthand for the "text-decoration" CSS property. */ + var textDecoration :String; + /** Shorthand for the "text-decoration-color" CSS property. */ + var textDecorationColor :String; + /** Shorthand for the "text-decoration-line" CSS property. */ + var textDecorationLine :String; + /** Shorthand for the "text-decoration-skip" CSS property. */ + var textDecorationSkip :String; + /** Shorthand for the "text-decoration-style" CSS property. */ + var textDecorationStyle :String; + /** Shorthand for the "text-emphasis" CSS property. */ + var textEmphasis :String; + /** Shorthand for the "text-emphasis-color" CSS property. */ + var textEmphasisColor :String; + /** Shorthand for the "text-emphasis-position" CSS property. */ + var textEmphasisPosition :String; + /** Shorthand for the "text-emphasis-style" CSS property. */ + var textEmphasisStyle :String; + /** Shorthand for the "text-height" CSS property. */ + var textHeight :String; + /** Shorthand for the "text-indent" CSS property. */ + var textIndent :String; + /** Shorthand for the "text-justify" CSS property. */ + var textJustify :String; + /** Shorthand for the "text-orientation" CSS property. */ + var textOrientation :String; + /** Shorthand for the "text-overflow" CSS property. */ + var textOverflow :String; + /** Shorthand for the "text-shadow" CSS property. */ + var textShadow :String; + /** Shorthand for the "text-space-collapse" CSS property. */ + var textSpaceCollapse :String; + /** Shorthand for the "text-transform" CSS property. */ + var textTransform :String; + /** Shorthand for the "text-underline-position" CSS property. */ + var textUnderlinePosition :String; + /** Shorthand for the "text-wrap" CSS property. */ + var textWrap :String; + /** Shorthand for the "top" CSS property. */ + var top :String; + /** Shorthand for the "transform" CSS property. */ + var transform :String; + /** Shorthand for the "transform-origin" CSS property. */ + var transformOrigin :String; + /** Shorthand for the "transform-style" CSS property. */ + var transformStyle :String; + /** Shorthand for the "transition" CSS property. */ + var transition :String; + /** Shorthand for the "transition-delay" CSS property. */ + var transitionDelay :String; + /** Shorthand for the "transition-duration" CSS property. */ + var transitionDuration :String; + /** Shorthand for the "transition-property" CSS property. */ + var transitionProperty :String; + /** Shorthand for the "transition-timing-function" CSS property. */ + var transitionTimingFunction :String; + /** Shorthand for the "unicode-bidi" CSS property. */ + var unicodeBidi :String; + /** Shorthand for the "vertical-align" CSS property. */ + var verticalAlign :String; + /** Shorthand for the "visibility" CSS property. */ + var visibility :String; + /** Shorthand for the "voice-balance" CSS property. */ + var voiceBalance :String; + /** Shorthand for the "voice-duration" CSS property. */ + var voiceDuration :String; + /** Shorthand for the "voice-family" CSS property. */ + var voiceFamily :String; + /** Shorthand for the "voice-pitch" CSS property. */ + var voicePitch :String; + /** Shorthand for the "voice-range" CSS property. */ + var voiceRange :String; + /** Shorthand for the "voice-rate" CSS property. */ + var voiceRate :String; + /** Shorthand for the "voice-stress" CSS property. */ + var voiceStress :String; + /** Shorthand for the "voice-volume" CSS property. */ + var voiceVolume :String; + /** Shorthand for the "volume" CSS property. */ + var volume :String; + /** Shorthand for the "white-space" CSS property. */ + var whiteSpace :String; + /** Shorthand for the "widows" CSS property. */ + var widows :String; + /** Shorthand for the "width" CSS property. */ + var width :String; + /** Shorthand for the "will-change" CSS property. */ + var willChange :String; + /** Shorthand for the "word-break" CSS property. */ + var wordBreak :String; + /** Shorthand for the "word-spacing" CSS property. */ + var wordSpacing :String; + /** Shorthand for the "word-wrap" CSS property. */ + var wordWrap :String; + /** Shorthand for the "wrap-flow" CSS property. */ + var wrapFlow :String; + /** Shorthand for the "wrap-through" CSS property. */ + var wrapThrough :String; + /** Shorthand for the "writing-mode" CSS property. */ + var writingMode :String; + /** Shorthand for the "z-index" CSS property. */ + var zIndex :String; + function item( index : Int ) : String; - - function removeProperty( propertyName : String ) : String; - - function setProperty( propertyName : String, ?value : String, priority : String ) : Void; - -} + /** @throws DOMError */ + function getPropertyValue( property : String ) : String; + /** @throws DOMError */ + function getPropertyCSSValue( property : String ) : CSSValue; + function getPropertyPriority( property : String ) : String; + /** @throws DOMError */ + function setProperty( property : String, value : String, ?priority : String = "" ) : Void; + /** @throws DOMError */ + function removeProperty( property : String ) : String; +} \ No newline at end of file diff --git a/std/js/html/CSSStyleRule.hx b/std/js/html/CSSStyleRule.hx index 2662d6f1135f8352b49cc1c4d8481f02a5093a2f..afa1765ff68af4e884e53f71bafb551e5a63f29e 100644 --- a/std/js/html/CSSStyleRule.hx +++ b/std/js/html/CSSStyleRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,19 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 23:2. Do not edit! + package js.html; -/** An object representing a single CSS style rule. CSSStyleRule implements the CSSRule - interface.

-Documentation for this class was provided by MDN. */ @:native("CSSStyleRule") extern class CSSStyleRule extends CSSRule { - /** Gets/sets the textual representation of the selector for this rule, e.g. "h1,h2". */ var selectorText : String; - - /** Returns the CSSStyleDeclaration object for the rule. Read only. */ var style(default,null) : CSSStyleDeclaration; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSStyleSheet.hx b/std/js/html/CSSStyleSheet.hx index c880691235e69e680ab574f65e1fda3fa3125d31..4779d2259eb62e95350ef12248c2ea626e29845c 100644 --- a/std/js/html/CSSStyleSheet.hx +++ b/std/js/html/CSSStyleSheet.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,30 +20,18 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSStyleSheet.webidl line 12:0. Do not edit! + package js.html; -/**

An object implementing the CSSStyleSheet interface represents a single CSS style sheet.

-

A CSS style sheet consists of CSS rules, each of which can be manipulated through an object that corresponds to that rule and that implements the CSSRule interface. The CSSStyleSheet itself lets you examine and modify its corresponding style sheet, including its list of rules.

-

In practice, every CSSStyleSheet also implements the more generic StyleSheet interface. A list of CSSStyleSheet-implementing objects corresponding to the style sheets for a given document can be reached by the document.styleSheets property, if the document is styled by an external CSS style sheet or an inline style element.



-Documentation for this class was provided by MDN. */ @:native("CSSStyleSheet") extern class CSSStyleSheet extends StyleSheet { - /** Returns a CSSRuleList of the CSS rules in the style sheet. */ - var cssRules(default,null) : CSSRuleList; - - /** If this style sheet is imported into the document using an @import rule, the ownerRule property will return that CSSImportRule, otherwise it returns null. */ var ownerRule(default,null) : CSSRule; - - var rules(default,null) : CSSRuleList; - - function addRule( selector : String, style : String, ?index : Int ) : Int; - - function deleteRule( index : Int ) : Void; - + var cssRules(default,null) : CSSRuleList; + + /** @throws DOMError */ function insertRule( rule : String, index : Int ) : Int; - - function removeRule( index : Int ) : Void; - -} + /** @throws DOMError */ + function deleteRule( index : Int ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CSSTransformValue.hx b/std/js/html/CSSTransformValue.hx deleted file mode 100644 index b6acd666cfad18cc67b891d90c657844394f2174..0000000000000000000000000000000000000000 --- a/std/js/html/CSSTransformValue.hx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C)2005-2013 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. - */ - -// This file is generated, do not edit! -package js.html; - -@:native("CSSTransformValue") -extern class CSSTransformValue extends CSSValueList -{ - static inline var CSS_MATRIX : Int = 11; - - static inline var CSS_MATRIX3D : Int = 21; - - static inline var CSS_PERSPECTIVE : Int = 20; - - static inline var CSS_ROTATE : Int = 4; - - static inline var CSS_ROTATE3D : Int = 17; - - static inline var CSS_ROTATEX : Int = 14; - - static inline var CSS_ROTATEY : Int = 15; - - static inline var CSS_ROTATEZ : Int = 16; - - static inline var CSS_SCALE : Int = 5; - - static inline var CSS_SCALE3D : Int = 19; - - static inline var CSS_SCALEX : Int = 6; - - static inline var CSS_SCALEY : Int = 7; - - static inline var CSS_SCALEZ : Int = 18; - - static inline var CSS_SKEW : Int = 8; - - static inline var CSS_SKEWX : Int = 9; - - static inline var CSS_SKEWY : Int = 10; - - static inline var CSS_TRANSLATE : Int = 1; - - static inline var CSS_TRANSLATE3D : Int = 13; - - static inline var CSS_TRANSLATEX : Int = 2; - - static inline var CSS_TRANSLATEY : Int = 3; - - static inline var CSS_TRANSLATEZ : Int = 12; - - var operationType(default,null) : Int; - -} diff --git a/std/js/html/CSSUnknownRule.hx b/std/js/html/CSSUnknownRule.hx index 5ac67966a3a4fea9373ba62023a70fea8d49dfb3..5a50d326791980ad613b694c4614748dbf1b0a6b 100644 --- a/std/js/html/CSSUnknownRule.hx +++ b/std/js/html/CSSUnknownRule.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,10 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from cssrule.webidl line 69:2. Do not edit! + package js.html; @:native("CSSUnknownRule") extern class CSSUnknownRule extends CSSRule { -} +} \ No newline at end of file diff --git a/std/js/html/CSSValue.hx b/std/js/html/CSSValue.hx index 45a80fc54ce6dc8480d602a17edd19ac7985fba4..825b8acd7d5e18c55d6966f2b00ded33ad7c9ce3 100644 --- a/std/js/html/CSSValue.hx +++ b/std/js/html/CSSValue.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSValue.webidl line 7:0. Do not edit! + package js.html; @:native("CSSValue") extern class CSSValue { - static inline var CSS_CUSTOM : Int = 3; - static inline var CSS_INHERIT : Int = 0; - static inline var CSS_PRIMITIVE_VALUE : Int = 1; - static inline var CSS_VALUE_LIST : Int = 2; - - /** Setter throws DOMException. */ + static inline var CSS_CUSTOM : Int = 3; + var cssText : String; - var cssValueType(default,null) : Int; - -} + +} \ No newline at end of file diff --git a/std/js/html/CSSValueList.hx b/std/js/html/CSSValueList.hx index c4db9c0b6a33172691717200df9ecf58b176e47e..b8f771f2ae8673018de6154b96bcf670832622f7 100644 --- a/std/js/html/CSSValueList.hx +++ b/std/js/html/CSSValueList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CSSValueList.webidl line 7:0. Do not edit! + package js.html; @:native("CSSValueList") extern class CSSValueList extends CSSValue implements ArrayAccess { var length(default,null) : Int; - + function item( index : Int ) : CSSValue; - -} +} \ No newline at end of file diff --git a/std/js/html/CanvasElement.hx b/std/js/html/CanvasElement.hx index a72faf70f1f0cbb30ba6ef89f8a173223e5a32c4..d67528a71c30a78adf9d5fb98dbeca78dffc5d0d 100644 --- a/std/js/html/CanvasElement.hx +++ b/std/js/html/CanvasElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,45 +20,39 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLCanvasElement.webidl line 17:0. Do not edit! + package js.html; -/** DOM canvas elements expose the HTMLCanvasElement interface, which provides properties and methods for manipulating the layout and presentation of canvas elements. The HTMLCanvasElement interface inherits the properties and methods of the element - object interface.

-Documentation for this class was provided by MDN. */ @:native("HTMLCanvasElement") extern class CanvasElement extends Element { - /** Reflects the - -height - HTML attribute, specifying the height of the coordinate space in CSS pixels. */ - var height : Int; - - /** Reflects the - -width - HTML attribute, specifying the width of the coordinate space in CSS pixels. */ var width : Int; - - function getContext( contextId : String ) : Dynamic; - - function toDataURL( ?type : String ) : String; - - /** A typed shortcut for getContext("2d"). */ - public inline function getContext2d() : CanvasRenderingContext2D { return cast getContext("2d"); } - - public inline function getContextWebGL( ?attribs :js.html.webgl.ContextAttributes ) :js.html.webgl.RenderingContext { + var height : Int; + + /** @throws DOMError */ + function getContext( contextId : String, ?contextOptions : Dynamic ) : Dynamic/*MISSING nsISupports*/; + /** @throws DOMError */ + function toDataURL( ?type : String = "", ?encoderOptions : Dynamic ) : String; + /** @throws DOMError */ + function toBlob( callback : Blob -> Void, ?type : String = "", ?encoderOptions : Dynamic ) : Void; + + /** Shorthand for getting a CanvasRenderingContext2D. */ + inline function getContext2d( ?attribs : {} ) : CanvasRenderingContext2D { + return cast getContext("2d", attribs); + } + /** Shorthand for getting a js.html.webgl.RenderingContext. */ + inline function getContextWebGL( ?attribs : js.html.webgl.ContextAttributes ) : js.html.webgl.RenderingContext { return CanvasUtil.getContextWebGL(this, attribs); } } private class CanvasUtil { - public static function getContextWebGL( canvas :CanvasElement, attribs :Dynamic ) { + public static function getContextWebGL( canvas :CanvasElement, attribs :{} ) { for (name in ["webgl", "experimental-webgl"]) { - var ctx = (untyped canvas).getContext(name, attribs); + var ctx = canvas.getContext(name, attribs); if (ctx != null) return ctx; } return null; } -} \ No newline at end of file +} diff --git a/std/js/html/CanvasGradient.hx b/std/js/html/CanvasGradient.hx index c711da3da6e04f5fa2d12f91e956a085da3d2788..29d1232211d96e7c44d19428de65daa08cd64c38 100644 --- a/std/js/html/CanvasGradient.hx +++ b/std/js/html/CanvasGradient.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CanvasRenderingContext2D.webidl line 285:0. Do not edit! + package js.html; -/** This is an opaque object representing a gradient and returned by CanvasRenderingContext2D's createLinearGradient or createRadialGradient methods.

-Documentation for this class was provided by MDN. */ @:native("CanvasGradient") extern class CanvasGradient { + /** @throws DOMError */ function addColorStop( offset : Float, color : String ) : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/CanvasPattern.hx b/std/js/html/CanvasPattern.hx index 8ef063b3cce24a39e3cf3e5f7513122f6f50ed5a..553446d23f54f0f0816876d77ce4539960791259 100644 --- a/std/js/html/CanvasPattern.hx +++ b/std/js/html/CanvasPattern.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,12 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CanvasRenderingContext2D.webidl line 292:0. Do not edit! + package js.html; -/** This is an opaque object created by CanvasRenderingContext2D's createPattern method (whether based on a image, canvas, or video).

-Documentation for this class was provided by MDN. */ @:native("CanvasPattern") extern class CanvasPattern { -} + function setTransform( matrix : js.html.svg.Matrix ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CanvasRenderingContext2D.hx b/std/js/html/CanvasRenderingContext2D.hx index ad7f5b6ddf51d0742e9a1b0ca147fb777bc232c4..fbfc6ebc5216387abd4148d622dca1818a2da977 100644 --- a/std/js/html/CanvasRenderingContext2D.hx +++ b/std/js/html/CanvasRenderingContext2D.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,225 +20,100 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CanvasRenderingContext2D.webidl line 28:0. Do not edit! + package js.html; -/** The bulk of the operations available at present with <canvas> - are available through this interface, returned by a call to getContext() on the <canvas> - element, with "2d" as its argument.

-Documentation for this class was provided by MDN. */ @:native("CanvasRenderingContext2D") -extern class CanvasRenderingContext2D extends CanvasRenderingContext +extern class CanvasRenderingContext2D { - var backingStorePixelRatio(default,null) : Float; - - /** Color or style to use inside shapes. Default #000 (black). */ - var fillStyle : Dynamic; - - /** Default value 10px sans-serif. */ - var font : String; - - /** Alpha value that is applied to shapes and images before they are composited onto the canvas. Default 1.0 (opaque). */ + var canvas(default,null) : CanvasElement; var globalAlpha : Float; - - /** With globalAplpha applied this sets how shapes and images are drawn onto the existing bitmap. Possible values:
  • source-atop
  • source-in
  • source-out
  • source-over (default)
  • destination-atop
  • destination-in
  • destination-out
  • destination-over
  • lighter
  • xor
*/ var globalCompositeOperation : String; - + var strokeStyle : haxe.extern.EitherType>; + var fillStyle : haxe.extern.EitherType>; + var shadowOffsetX : Float; + var shadowOffsetY : Float; + var shadowBlur : Float; + var shadowColor : String; + var filter : String; var imageSmoothingEnabled : Bool; - - /** Type of endings on the end of lines. Possible values: butt (default), round, square */ + var lineWidth : Float; var lineCap : String; - - var lineDash : Array; - - var lineDashOffset : Float; - - /** Defines the type of corners where two lines meet. Possible values: round, bevel, miter (default) */ var lineJoin : String; - - /** Width of lines. Default 1.0 */ - var lineWidth : Float; - - /** Default 10. */ var miterLimit : Float; - - /** Specifies the blurring effect. Default 0 */ - var shadowBlur : Float; - - /** Color of the shadow. Default fully-transparent black. */ - var shadowColor : String; - - /** Horizontal distance the shadow will be offset. Default 0. */ - var shadowOffsetX : Float; - - /** Vertical distance the shadow will be offset. Default 0. */ - var shadowOffsetY : Float; - - /** Color or style to use for the lines around shapes. Default #000 (black). */ - var strokeStyle : Dynamic; - - /** Possible values: start (default), end, left, right or center. */ + var lineDashOffset : Float; + var font : String; var textAlign : String; - var textBaseline : String; - - function arc( x : Float, y : Float, radius : Float, startAngle : Float, endAngle : Float, anticlockwise : Bool ) : Void; - - function arcTo( x1 : Float, y1 : Float, x2 : Float, y2 : Float, radius : Float ) : Void; - - function beginPath() : Void; - - function bezierCurveTo( cp1x : Float, cp1y : Float, cp2x : Float, cp2y : Float, x : Float, y : Float ) : Void; - - function clearRect( x : Float, y : Float, width : Float, height : Float ) : Void; - - function clearShadow() : Void; - - function clip() : Void; - - function closePath() : Void; - - /** Throws DOMException. */ - @:overload( function( imagedata : ImageData ) :ImageData {} ) - function createImageData( sw : Float, sh : Float ) : ImageData; - + + function save() : Void; + function restore() : Void; + /** @throws DOMError */ + function scale( x : Float, y : Float ) : Void; + /** @throws DOMError */ + function rotate( angle : Float ) : Void; + /** @throws DOMError */ + function translate( x : Float, y : Float ) : Void; + /** @throws DOMError */ + function transform( a : Float, b : Float, c : Float, d : Float, e : Float, f : Float ) : Void; + /** @throws DOMError */ + function setTransform( a : Float, b : Float, c : Float, d : Float, e : Float, f : Float ) : Void; + /** @throws DOMError */ + function resetTransform() : Void; function createLinearGradient( x0 : Float, y0 : Float, x1 : Float, y1 : Float ) : CanvasGradient; - - /**
Parameters
-
image
A DOM element - to use as the source image for the pattern. This can be any element, although typically you'll use an Image - or <canvas> -.
repetition
?
-
-
Return value
-

A new DOM canvas pattern object for use in pattern-based operations.

-
Exceptions thrown
-
NS_ERROR_DOM_INVALID_STATE_ERR -Requires Gecko 10.0 -
The specified <canvas> - element for the image parameter is zero-sized (that is, one or both of its dimensions are 0 pixels).
-
-
Throws DOMException. */ - @:overload( function( canvas : CanvasElement, repetitionType : String ) :CanvasPattern {} ) - function createPattern( image : ImageElement, repetitionType : String ) : CanvasPattern; - + /** @throws DOMError */ function createRadialGradient( x0 : Float, y0 : Float, r0 : Float, x1 : Float, y1 : Float, r1 : Float ) : CanvasGradient; - - /**

Draws the specified image. This method is available in multiple formats, providing a great deal of flexibility in its use.

- -
Parameters
-
image
An element to draw into the context; the specification permits any image element (that is, <img> -, <canvas> -, and <video> -). Some browsers, including Firefox, let you use any arbitrary element.
dx
The X coordinate in the destination canvas at which to place the top-left corner of the source image.
dy
The Y coordinate in the destination canvas at which to place the top-left corner of the source image.
dw
The width to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in width when drawn.
dh
The height to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not scaled in height when drawn.
sx
The X coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sy
The Y coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sw
The width of the sub-rectangle of the source image to draw into the destination context. If not specified, the entire rectangle from the coordinates specified by sx and sy to the bottom-right corner of the image is used. If you specify a negative value, the image is flipped horizontally when drawn.
sh
The height of the sub-rectangle of the source image to draw into the destination context. If you specify a negative value, the image is flipped vertically when drawn.
-
-

The diagram below illustrates the meanings of the various parameters.

-

drawImage.png

-
Exceptions thrown
-
INDEX_SIZE_ERR
If the canvas or source rectangle width or height is zero.
INVALID_STATE_ERR
The image has no image data.
TYPE_MISMATCH_ERR
The specified source element isn't supported. This is not thrown by Firefox, since any element may be used as a source image.
-
-
Compatibility notes
-
  • Prior to Gecko 7.0 (Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4) -, Firefox threw an exception if any of the coordinate values was non-finite or zero. As per the specification, this no longer happens.
  • Support for flipping the image by using negative values for sw and sh was added in Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) -.
  • Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) - now correctly supports CORS for drawing images across domains without tainting the canvas.
  • -
-
Throws DOMException. */ - @:overload( function( image : ImageElement, x : Float, y : Float ) :Void {} ) - @:overload( function( image : ImageElement, x : Float, y : Float, width : Float, height : Float ) :Void {} ) - @:overload( function( image : ImageElement, sx : Float, sy : Float, sw : Float, sh : Float, dx : Float, dy : Float, dw : Float, dh : Float ) :Void {} ) - @:overload( function( canvas : CanvasElement, x : Float, y : Float ) :Void {} ) - @:overload( function( canvas : CanvasElement, x : Float, y : Float, width : Float, height : Float ) :Void {} ) - @:overload( function( canvas : CanvasElement, sx : Float, sy : Float, sw : Float, sh : Float, dx : Float, dy : Float, dw : Float, dh : Float ) :Void {} ) - @:overload( function( video : VideoElement, x : Float, y : Float ) :Void {} ) - @:overload( function( video : VideoElement, x : Float, y : Float, width : Float, height : Float ) :Void {} ) - function drawImage( video : VideoElement, sx : Float, sy : Float, sw : Float, sh : Float, dx : Float, dy : Float, dw : Float, dh : Float ) : Void; - - function drawImageFromRect( image : ImageElement, ?sx : Float, ?sy : Float, ?sw : Float, ?sh : Float, ?dx : Float, ?dy : Float, ?dw : Float, ?dh : Float, ?compositeOperation : String ) : Void; - - function fill() : Void; - - function fillRect( x : Float, y : Float, width : Float, height : Float ) : Void; - + /** @throws DOMError */ + function createPattern( image : haxe.extern.EitherType>, repetition : String ) : CanvasPattern; + function clearRect( x : Float, y : Float, w : Float, h : Float ) : Void; + function fillRect( x : Float, y : Float, w : Float, h : Float ) : Void; + function strokeRect( x : Float, y : Float, w : Float, h : Float ) : Void; + function beginPath() : Void; + @:overload( function( ?winding : CanvasWindingRule = "nonzero" ) : Void {} ) + function fill( path : Path2D, ?winding : CanvasWindingRule = "nonzero" ) : Void; + @:overload( function() : Void {} ) + function stroke( path : Path2D ) : Void; + function drawFocusIfNeeded( element : Element ) : Void; + function drawCustomFocusRing( element : Element ) : Bool; + @:overload( function( ?winding : CanvasWindingRule = "nonzero" ) : Void {} ) + function clip( path : Path2D, ?winding : CanvasWindingRule = "nonzero" ) : Void; + @:overload( function( x : Float, y : Float, ?winding : CanvasWindingRule = "nonzero" ) : Bool {} ) + function isPointInPath( path : Path2D, x : Float, y : Float, ?winding : CanvasWindingRule = "nonzero" ) : Bool; + @:overload( function( x : Float, y : Float ) : Bool {} ) + function isPointInStroke( path : Path2D, x : Float, y : Float ) : Bool; + /** @throws DOMError */ function fillText( text : String, x : Float, y : Float, ?maxWidth : Float ) : Void; - + /** @throws DOMError */ + function strokeText( text : String, x : Float, y : Float, ?maxWidth : Float ) : Void; + /** @throws DOMError */ + function measureText( text : String ) : TextMetrics; + /** @throws DOMError */ + @:overload( function( image : haxe.extern.EitherType>, dx : Float, dy : Float ) : Void {} ) + @:overload( function( image : haxe.extern.EitherType>, dx : Float, dy : Float, dw : Float, dh : Float ) : Void {} ) + function drawImage( image : haxe.extern.EitherType>, sx : Float, sy : Float, sw : Float, sh : Float, dx : Float, dy : Float, dw : Float, dh : Float ) : Void; + /** @throws DOMError */ + function addHitRegion( ?options : HitRegionOptions ) : Void; + function removeHitRegion( id : String ) : Void; + function clearHitRegions() : Void; + /** @throws DOMError */ + @:overload( function( sw : Float, sh : Float ) : ImageData {} ) + function createImageData( imagedata : ImageData ) : ImageData; + /** @throws DOMError */ function getImageData( sx : Float, sy : Float, sw : Float, sh : Float ) : ImageData; - - function getImageDataHD( sx : Float, sy : Float, sw : Float, sh : Float ) : ImageData; - + /** @throws DOMError */ + @:overload( function( imagedata : ImageData, dx : Float, dy : Float ) : Void {} ) + function putImageData( imagedata : ImageData, dx : Float, dy : Float, dirtyX : Float, dirtyY : Float, dirtyWidth : Float, dirtyHeight : Float ) : Void; + function setLineDash( segments : Array ) : Void; function getLineDash() : Array; - - function isPointInPath( x : Float, y : Float ) : Bool; - - function lineTo( x : Float, y : Float ) : Void; - - function measureText( text : String ) : TextMetrics; - + function closePath() : Void; function moveTo( x : Float, y : Float ) : Void; - - /**
Compatibility notes
-
  • Starting in Gecko 10.0 (Firefox 10.0 / Thunderbird 10.0) -, non-finite values to any of these parameters causes the call to putImageData() to be silently ignored, rather than throwing an exception.
  • -
Throws DOMException. */ - @:overload( function( imagedata : ImageData, dx : Float, dy : Float ) :Void {} ) - function putImageData( imagedata : ImageData, dx : Float, dy : Float, dirtyX : Float, dirtyY : Float, dirtyWidth : Float, dirtyHeight : Float ) : Void; - - /** Throws DOMException. */ - @:overload( function( imagedata : ImageData, dx : Float, dy : Float ) :Void {} ) - function putImageDataHD( imagedata : ImageData, dx : Float, dy : Float, dirtyX : Float, dirtyY : Float, dirtyWidth : Float, dirtyHeight : Float ) : Void; - + function lineTo( x : Float, y : Float ) : Void; function quadraticCurveTo( cpx : Float, cpy : Float, x : Float, y : Float ) : Void; - - function rect( x : Float, y : Float, width : Float, height : Float ) : Void; - - function restore() : Void; - - function rotate( angle : Float ) : Void; - - function save() : Void; - - function scale( sx : Float, sy : Float ) : Void; - - function setAlpha( alpha : Float ) : Void; - - function setCompositeOperation( compositeOperation : String ) : Void; - - @:overload( function( color : String, ?alpha : Float ) :Void {} ) - @:overload( function( grayLevel : Float, ?alpha : Float ) :Void {} ) - @:overload( function( r : Float, g : Float, b : Float, a : Float ) :Void {} ) - function setFillColor( c : Float, m : Float, y : Float, k : Float, a : Float ) : Void; - - function setLineCap( cap : String ) : Void; - - function setLineDash( dash : Array ) : Void; - - function setLineJoin( join : String ) : Void; - - function setLineWidth( width : Float ) : Void; - - function setMiterLimit( limit : Float ) : Void; - - @:overload( function( width : Float, height : Float, blur : Float, ?color : String, ?alpha : Float ) :Void {} ) - @:overload( function( width : Float, height : Float, blur : Float, grayLevel : Float, ?alpha : Float ) :Void {} ) - @:overload( function( width : Float, height : Float, blur : Float, r : Float, g : Float, b : Float, a : Float ) :Void {} ) - function setShadow( width : Float, height : Float, blur : Float, c : Float, m : Float, y : Float, k : Float, a : Float ) : Void; - - @:overload( function( color : String, ?alpha : Float ) :Void {} ) - @:overload( function( grayLevel : Float, ?alpha : Float ) :Void {} ) - @:overload( function( r : Float, g : Float, b : Float, a : Float ) :Void {} ) - function setStrokeColor( c : Float, m : Float, y : Float, k : Float, a : Float ) : Void; - - function setTransform( m11 : Float, m12 : Float, m21 : Float, m22 : Float, dx : Float, dy : Float ) : Void; - - function stroke() : Void; - - function strokeRect( x : Float, y : Float, width : Float, height : Float, ?lineWidth : Float ) : Void; - - function strokeText( text : String, x : Float, y : Float, ?maxWidth : Float ) : Void; - - function transform( m11 : Float, m12 : Float, m21 : Float, m22 : Float, dx : Float, dy : Float ) : Void; - - function translate( tx : Float, ty : Float ) : Void; - -} + function bezierCurveTo( cp1x : Float, cp1y : Float, cp2x : Float, cp2y : Float, x : Float, y : Float ) : Void; + /** @throws DOMError */ + function arcTo( x1 : Float, y1 : Float, x2 : Float, y2 : Float, radius : Float ) : Void; + function rect( x : Float, y : Float, w : Float, h : Float ) : Void; + /** @throws DOMError */ + function arc( x : Float, y : Float, radius : Float, startAngle : Float, endAngle : Float, ?anticlockwise : Bool = false ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CanvasWindingRule.hx b/std/js/html/CanvasWindingRule.hx new file mode 100644 index 0000000000000000000000000000000000000000..892e7971f1a240eb8cb12f6e78e0610f93e4da8f --- /dev/null +++ b/std/js/html/CanvasWindingRule.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CanvasRenderingContext2D.webidl line 14:0. Do not edit! + +package js.html; + +@:enum abstract CanvasWindingRule(String) +{ + var NONZERO = "nonzero"; + var EVENODD = "evenodd"; +} \ No newline at end of file diff --git a/std/js/html/CaretPosition.hx b/std/js/html/CaretPosition.hx new file mode 100644 index 0000000000000000000000000000000000000000..b1a65e7729c2b815b40e6ef2ebd281372bf8cbb2 --- /dev/null +++ b/std/js/html/CaretPosition.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CaretPosition.webidl line 5:0. Do not edit! + +package js.html; + +@:native("CaretPosition") +extern class CaretPosition +{ + var offsetNode(default,null) : Node; + var offset(default,null) : Int; + + function getClientRect() : DOMRect; +} \ No newline at end of file diff --git a/std/js/html/CharacterData.hx b/std/js/html/CharacterData.hx index 8a23561b24710eac4b0ca0ca516457e6248ca632..65f6df8543ed7f1b3e3b2998e571f110e29a91d3 100644 --- a/std/js/html/CharacterData.hx +++ b/std/js/html/CharacterData.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,29 +20,27 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CharacterData.webidl line 13:0. Do not edit! + package js.html; -/** Text, Comment, and CDATASection all implement CharacterData, which in turn also implements Node. See Node for the remaining methods, properties, and constants.

-Documentation for this class was provided by MDN. */ @:native("CharacterData") extern class CharacterData extends Node { - /** Setter throws DOMException. */ var data : String; - var length(default,null) : Int; - + var previousElementSibling(default,null) : Element; + var nextElementSibling(default,null) : Element; + + /** @throws DOMError */ + function substringData( offset : Int, count : Int ) : String; + /** @throws DOMError */ function appendData( data : String ) : Void; - - function deleteData( offset : Int, length : Int ) : Void; - + /** @throws DOMError */ function insertData( offset : Int, data : String ) : Void; - + /** @throws DOMError */ + function deleteData( offset : Int, count : Int ) : Void; + /** @throws DOMError */ + function replaceData( offset : Int, count : Int, data : String ) : Void; function remove() : Void; - - function replaceData( offset : Int, length : Int, data : String ) : Void; - - function substringData( offset : Int, length : Int ) : String; - -} +} \ No newline at end of file diff --git a/std/js/html/ChromeFilePropertyBag.hx b/std/js/html/ChromeFilePropertyBag.hx new file mode 100644 index 0000000000000000000000000000000000000000..786aa81df52bc817d0af007a89c37f45d1949b34 --- /dev/null +++ b/std/js/html/ChromeFilePropertyBag.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/File.webidl line 35:0. Do not edit! + +package js.html; + +typedef ChromeFilePropertyBag = +{ + > FilePropertyBag, + @:optional var name : String; + @:optional var temporary : Bool; +} \ No newline at end of file diff --git a/std/js/html/ClientRect.hx b/std/js/html/ClientRect.hx index 950107c99848bf8af176dc1a98974301635e323b..0e6d432bf63ada79049ad4193515e03274676575 100644 --- a/std/js/html/ClientRect.hx +++ b/std/js/html/ClientRect.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,40 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -/** Represents a rectangular box. The type of box is specified by the method that returns such an object. It is returned by functions like element.getBoundingClientRect -.
1.0
11.0
Introduced
Gecko 1.9
-
Inherits from: nsISupports -Last changed in Gecko 1.9.1 (Firefox 3.5 / Thunderbird 3.0 / SeaMonkey 2.0) -


-Documentation for this class was provided by MDN. */ -@:native("ClientRect") -extern class ClientRect -{ - /** Y-coordinate, relative to the viewport origin, of the bottom of the rectangle box. Read only. */ - var bottom(default,null) : Float; - - /** Height of the rectangle box (This is identical to bottom minus top). Read only. */ - var height(default,null) : Float; - - /** X-coordinate, relative to the viewport origin, of the left of the rectangle box. Read only. */ - var left(default,null) : Float; - - /** X-coordinate, relative to the viewport origin, of the right of the rectangle box. Read only. */ - var right(default,null) : Float; - - /** Y-coordinate, relative to the viewport origin, of the top of the rectangle box. Read only. */ - var top(default,null) : Float; - - /** Width of the rectangle box (This is identical to right minus left). Read only. -Requires Gecko 1.9.1 */ - var width(default,null) : Float; - -} +/** @deprecated Use DOMRect instead. */ +@:deprecated("ClientRect is deprecated, use DOMRect instead") +typedef ClientRect = DOMRect; diff --git a/std/js/html/ClientRectList.hx b/std/js/html/ClientRectList.hx index 7ba5c599d41f8e838b10e634cab43dc5dc45d8b3..072cdd5716f7cec5a5a0046d2006dc40d3c04c5c 100644 --- a/std/js/html/ClientRectList.hx +++ b/std/js/html/ClientRectList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("ClientRectList") -extern class ClientRectList implements ArrayAccess -{ - var length(default,null) : Int; - - function item( index : Int ) : ClientRect; - -} +/** @deprecated Use DOMRectList instead. */ +@:deprecated("ClientRectList is deprecated, use DOMRectList instead") +typedef ClientRectList = DOMRectList; diff --git a/std/js/html/Clipboard.hx b/std/js/html/Clipboard.hx index 4f1a310d957b14b99c348ac8dc26c16c2d99b3bd..62b362066e1bd5e6d66f0dde00967cd8dbd947ba 100644 --- a/std/js/html/Clipboard.hx +++ b/std/js/html/Clipboard.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,34 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -/** This interface supports basic clipboard operations such as: setting, retrieving, emptying, matching and supporting clipboard data.
Inherits from: nsISupports -Last changed in Gecko 1.8 (Firefox 1.5 / Thunderbird 1.5 / SeaMonkey 1.0) -


-Documentation for this class was provided by MDN. */ -@:native("Clipboard") -extern class Clipboard -{ - var dropEffect : String; - - var effectAllowed : String; - - var files(default,null) : FileList; - - var items(default,null) : DataTransferItemList; - - var types(default,null) : Array; - - function clearData( ?type : String ) : Void; - - function getData( type : String ) : String; - - function setData( type : String, data : String ) : Bool; - - function setDragImage( image : ImageElement, x : Int, y : Int ) : Void; - -} +/** @deprecated Use DataTransfer instead. */ +@:deprecated("Clipboard is deprecated, use DataTransfer instead") +typedef Clipboard = DataTransfer; diff --git a/std/js/html/ClipboardEvent.hx b/std/js/html/ClipboardEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..446f2ac31d21d32beb9e333d6efff0144c5abc50 --- /dev/null +++ b/std/js/html/ClipboardEvent.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/ClipboardEvent.webidl line 14:0. Do not edit! + +package js.html; + +@:native("ClipboardEvent") +extern class ClipboardEvent extends Event +{ + var clipboardData(default,null) : DataTransfer; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : ClipboardEventInit ) : Void; +} \ No newline at end of file diff --git a/std/js/html/ClipboardEventInit.hx b/std/js/html/ClipboardEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..b1ecb7951b0b8d6827f86395f93b8ddec5b497e5 --- /dev/null +++ b/std/js/html/ClipboardEventInit.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/ClipboardEvent.webidl line 19:0. Do not edit! + +package js.html; + +typedef ClipboardEventInit = +{ + > EventInit, + @:optional var data : String; + @:optional var dataType : String; +} \ No newline at end of file diff --git a/std/js/html/CloseEvent.hx b/std/js/html/CloseEvent.hx index 1cb84c3e6b843c31951fec2f8e782af0c4d71729..ab1ed8f28486845224a455f1743501e06e4c6931 100644 --- a/std/js/html/CloseEvent.hx +++ b/std/js/html/CloseEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CloseEvent.webidl line 14:0. Do not edit! + package js.html; -/** A CloseEvent is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object's onclose attribute.

-Documentation for this class was provided by MDN. */ @:native("CloseEvent") extern class CloseEvent extends Event { - /** The WebSocket connection close code provided by the server. See Status codes for possible values. */ + var wasClean(default,null) : Bool; var code(default,null) : Int; - - /** A string indicating the reason the server closed the connection. This is specific to the particular server and sub-protocol. */ var reason(default,null) : String; - - /** Indicates whether or not the connection was cleanly closed. */ - var wasClean(default,null) : Bool; - - function new(type : String, canBubble : Bool = true, cancelable : Bool = true) : Void; - -} + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : CloseEventInit ) : Void; + /** @throws DOMError */ + function initCloseEvent( aType : String, aCanBubble : Bool, aCancelable : Bool, aWasClean : Bool, aReasonCode : Int, aReason : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CloseEventInit.hx b/std/js/html/CloseEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..e4ae96c15501b84c7ad6b48beeb4cb261f8ccd7e --- /dev/null +++ b/std/js/html/CloseEventInit.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CloseEvent.webidl line 29:0. Do not edit! + +package js.html; + +typedef CloseEventInit = +{ + > EventInit, + @:optional var code : Int; + @:optional var reason : String; + @:optional var wasClean : Bool; +} \ No newline at end of file diff --git a/std/js/html/CommandEvent.hx b/std/js/html/CommandEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..694e721ff1c83c34dca670230cd5225efbb79dec --- /dev/null +++ b/std/js/html/CommandEvent.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CommandEvent.webidl line 7:0. Do not edit! + +package js.html; + +@:native("CommandEvent") +extern class CommandEvent extends Event +{ + var command(default,null) : String; + + function initCommandEvent( type : String, canBubble : Bool, cancelable : Bool, command : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/Comment.hx b/std/js/html/Comment.hx index a035579f1875d41c3b86da582e133596f03ff83f..bd732b556c19749c2da2a0398b7753aa7bb2d133 100644 --- a/std/js/html/Comment.hx +++ b/std/js/html/Comment.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,13 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Comment.webidl line 14:0. Do not edit! + package js.html; -/**

A comment is used to add notations within markup; although it is generally not displayed, it is still available to be read in the source view (in Firefox: View -> Page Source).  These are represented in HTML and XML as content between <!-- and  --> . In XML, the character sequence "--" cannot be used within a comment.

-

A comment has no special properties or methods of its own, but inherits those of CharacterData (which inherits from Node).



-Documentation for this class was provided by MDN. */ @:native("Comment") extern class Comment extends CharacterData { -} + /** @throws DOMError */ + function new( ?data : String = "" ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CompositionEvent.hx b/std/js/html/CompositionEvent.hx index 00e9d983d5de4113102aa1d7560bd280946721ba..f4ba7fd1f5186722d45a98ec1aa2b4285e2862ec 100644 --- a/std/js/html/CompositionEvent.hx +++ b/std/js/html/CompositionEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,29 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html; +// This file is generated from mozilla/CompositionEvent.webidl line 12:0. Do not edit! -/**
An event interface for composition events
1.0
11.0
Introduced
Gecko 9.0
-
Inherits from: nsIDOMUIEvent -Last changed in Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) -
-

-

The DOM CompositionEvent represents events that occur due to the user indirectly entering text.



-Documentation for this class was provided by MDN. */ @:native("CompositionEvent") extern class CompositionEvent extends UIEvent { - /**

For compositionstart - events, this is the currently selected text that will be replaced by the string being composed. This value doesn't change even if content changes the selection range; rather, it indicates the string that was selected when composition started.

For compositionupdate -, this is the string as it stands currently as editing is ongoing.

For compositionend - events, this is the string as committed to the editor.

Read only.

*/ var data(default,null) : String; - - function initCompositionEvent( typeArg : String, canBubbleArg : Bool, cancelableArg : Bool, viewArg : DOMWindow, dataArg : String ) : Void; - -} + var locale(default,null) : String; + + /** @throws DOMError */ + function initCompositionEvent( typeArg : String, canBubbleArg : Bool, cancelableArg : Bool, viewArg : Window, dataArg : String, localeArg : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/Console.hx b/std/js/html/Console.hx index c2d82656c73e37682f2aab5f333acde5f5e8ce3d..a623ed61d2ba765fc3d223fe63f9c6e62375af4f 100644 --- a/std/js/html/Console.hx +++ b/std/js/html/Console.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,59 +20,30 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Console.webidl line 9:0. Do not edit! + package js.html; -/**

Beginning with Firefox 4, the old Error Console has been deprecated in favor of the new, improved Web Console. The Web Console is something of a heads-up display for the web, letting you view error messages and other logged information. In addition, there are methods you can call to output information to the console, making it a useful debugging aid, and you can evaluate JavaScript on the fly.

-

webconsole.png

-

The Web Console won't replace more advanced debugging tools like Firebug; what it does give you, however, is a way to let remote users of your site or web application gather and report console logs and other information to you. It also provides a lightweight way to debug content if you don't happen to have Firebug installed when something goes wrong.

-
Note: The Error Console is still available; you can re-enable it by changing the devtools.errorconsole.enabled preference to true and restarting the browser.


-Documentation for this class was provided by MDN. */ @:native("Console") extern class Console { - var memory(default,null) : MemoryInfo; - - var profiles(default,null) : Array; - - function assert( condition : Bool , ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function clear(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function count(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function debug(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function dir(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function dirxml(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function error(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function group(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function groupCollapsed(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function groupEnd() : Void; - - function info(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function log(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function markTimeline(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function profile( title : String ) : Void; - - function profileEnd( title : String ) : Void; - - function time( title : String ) : Void; - - function timeEnd( title : String , ?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function timeStamp(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function trace(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - - function warn(?p1 : Dynamic, ?p2 : Dynamic, ?p3 : Dynamic, ?p4 : Dynamic, ?p5 : Dynamic) : Void; - -} + function log( data : haxe.extern.Rest ) : Void; + function info( data : haxe.extern.Rest ) : Void; + function warn( data : haxe.extern.Rest ) : Void; + function error( data : haxe.extern.Rest ) : Void; + function exception( data : haxe.extern.Rest ) : Void; + function debug( data : haxe.extern.Rest ) : Void; + function table( data : haxe.extern.Rest ) : Void; + function trace() : Void; + function dir( data : haxe.extern.Rest ) : Void; + function group( data : haxe.extern.Rest ) : Void; + function groupCollapsed( data : haxe.extern.Rest ) : Void; + function groupEnd( data : haxe.extern.Rest ) : Void; + function time( ?time : Dynamic ) : Void; + function timeEnd( ?time : Dynamic ) : Void; + function profile( data : haxe.extern.Rest ) : Void; + function profileEnd( data : haxe.extern.Rest ) : Void; + function assert( condition : Bool, data : haxe.extern.Rest ) : Void; + function count( data : haxe.extern.Rest ) : Void; + function clear() : Void; +} \ No newline at end of file diff --git a/std/js/html/ContentElement.hx b/std/js/html/ContentElement.hx index 3e98ef3f11a874e4ffa42cbdc1dcf80c3c3f1c55..c9e7050d6446058c36b4c55266ac3651e4d4f6c5 100644 --- a/std/js/html/ContentElement.hx +++ b/std/js/html/ContentElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLContentElement.webidl line 14:0. Do not edit! + package js.html; @:native("HTMLContentElement") extern class ContentElement extends Element { - var resetStyleInheritance : Bool; - var select : String; - + function getDistributedNodes() : NodeList; - -} +} \ No newline at end of file diff --git a/std/js/html/ConvertCoordinateOptions.hx b/std/js/html/ConvertCoordinateOptions.hx new file mode 100644 index 0000000000000000000000000000000000000000..be181908f5ff6536bb9dc9c9fbdcbd7c8aec7555 --- /dev/null +++ b/std/js/html/ConvertCoordinateOptions.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/GeometryUtils.webidl line 19:0. Do not edit! + +package js.html; + +typedef ConvertCoordinateOptions = +{ + @:optional var fromBox : Dynamic/*MISSING CSSBoxType*/; + @:optional var toBox : Dynamic/*MISSING CSSBoxType*/; +} \ No newline at end of file diff --git a/std/js/html/Coordinates.hx b/std/js/html/Coordinates.hx index 7e7d7ab746e68f62ebcc65d0c1a1db555debf531..a90f642d2a7d98fc8128e38730e0dd7c99416725 100644 --- a/std/js/html/Coordinates.hx +++ b/std/js/html/Coordinates.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,24 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Coordinates.webidl line 14:0. Do not edit! + package js.html; @:native("Coordinates") extern class Coordinates { - var accuracy(default,null) : Float; - + var latitude(default,null) : Float; + var longitude(default,null) : Float; var altitude(default,null) : Float; - + var accuracy(default,null) : Float; var altitudeAccuracy(default,null) : Float; - var heading(default,null) : Float; - - var latitude(default,null) : Float; - - var longitude(default,null) : Float; - var speed(default,null) : Float; - -} + +} \ No newline at end of file diff --git a/std/js/html/Counter.hx b/std/js/html/Counter.hx deleted file mode 100644 index 031963865ad0edace1e970ee9e6ca52c7952b8e1..0000000000000000000000000000000000000000 --- a/std/js/html/Counter.hx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C)2005-2013 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. - */ - -// This file is generated, do not edit! -package js.html; - -/** CSS counters are an implementation of Automatic counters and numbering in CSS 2.1. The value of a counter is manipulated through the use of counter-reset - and counter-increment - and is displayed on a page using the counter() or counters() function of the content property.

-Documentation for this class was provided by MDN. */ -@:native("Counter") -extern class Counter -{ - var identifier(default,null) : String; - - var listStyle(default,null) : String; - - var separator(default,null) : String; - -} diff --git a/std/js/html/CreateFileOptions.hx b/std/js/html/CreateFileOptions.hx new file mode 100644 index 0000000000000000000000000000000000000000..dbf2ebfc25538ed7e6aab02c9c43aa828de0b6ce --- /dev/null +++ b/std/js/html/CreateFileOptions.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Directory.webidl line 95:0. Do not edit! + +package js.html; + +typedef CreateFileOptions = +{ + @:optional var data : haxe.extern.EitherType>>; + @:optional var ifExists : Dynamic/*MISSING CreateIfExistsMode*/; +} \ No newline at end of file diff --git a/std/js/html/Crypto.hx b/std/js/html/Crypto.hx index 863f77471c1cdf39fa52d4a1c2b4ee8f9ee7ddb6..62a151b954aa3d187d19e3b84dbe9ec5816dadd6 100644 --- a/std/js/html/Crypto.hx +++ b/std/js/html/Crypto.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Crypto.webidl line 18:0. Do not edit! + package js.html; -/** Non-standard

-Documentation for this class was provided by MDN. */ @:native("Crypto") extern class Crypto { - function getRandomValues( array : ArrayBufferView ) : Void; - -} + var subtle(default,null) : SubtleCrypto; + + /** @throws DOMError */ + function getRandomValues( array : ArrayBufferView ) : ArrayBufferView; +} \ No newline at end of file diff --git a/std/js/html/CryptoKey.hx b/std/js/html/CryptoKey.hx new file mode 100644 index 0000000000000000000000000000000000000000..58dca6f675304c48cf3aadda91e0792594d159dd --- /dev/null +++ b/std/js/html/CryptoKey.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/SubtleCrypto.webidl line 142:0. Do not edit! + +package js.html; + +@:native("CryptoKey") +extern class CryptoKey +{ + var type(default,null) : String; + var extractable(default,null) : Bool; + var algorithm(default,null) : Dynamic; + var usages(default,null) : Array; + +} \ No newline at end of file diff --git a/std/js/html/CustomEvent.hx b/std/js/html/CustomEvent.hx index a2db6d796208cdc6bc78ea7ea7287004765d4d13..f86667d36b63ce259a92d2f734dd391bf68be71e 100644 --- a/std/js/html/CustomEvent.hx +++ b/std/js/html/CustomEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,21 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/CustomEvent.webidl line 14:0. Do not edit! + package js.html; -/** The DOM CustomEvent are events initialized by an application for any purpose. It's represented by the nsIDOMCustomEvent - interface, which extends the nsIDOMEvent - interface.

-Documentation for this class was provided by MDN. */ @:native("CustomEvent") extern class CustomEvent extends Event { - /** The data passed when initializing the event. */ var detail(default,null) : Dynamic; - - function new(type : String, canBubble : Bool = true, cancelable : Bool = true) : Void; - - function initCustomEvent( typeArg : String, canBubbleArg : Bool, cancelableArg : Bool, detailArg : Dynamic ) : Void; - -} + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : CustomEventInit ) : Void; + /** @throws DOMError */ + function initCustomEvent( type : String, canBubble : Bool, cancelable : Bool, detail : Dynamic ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CustomEventInit.hx b/std/js/html/CustomEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..2cc3549d7dc68b723aafe1b14155c8bc79f24e0e --- /dev/null +++ b/std/js/html/CustomEventInit.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/CustomEvent.webidl line 26:0. Do not edit! + +package js.html; + +typedef CustomEventInit = +{ + > EventInit, + @:optional var detail : Dynamic; +} \ No newline at end of file diff --git a/std/js/html/DListElement.hx b/std/js/html/DListElement.hx index 54f12b86c9750cca232adcc75dd3c5740dc7c4f3..6c4e52a9c709411e5e91449ce86ae93ab94b597d 100644 --- a/std/js/html/DListElement.hx +++ b/std/js/html/DListElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLDListElement.webidl line 16:0. Do not edit! + package js.html; -/** DOM definition list elements expose the HTMLDListElement (or HTML 4 HTMLDListElement) interface, which provides special properties (beyond the regular element object interface they also have available to them by inheritance) for manipulating definition list elements. In -HTML5, this interface inherits from HTMLElement, but defines no additional members.

-Documentation for this class was provided by MDN. */ @:native("HTMLDListElement") extern class DListElement extends Element { - /** Indicates that spacing between list items should be reduced. */ var compact : Bool; - -} + +} \ No newline at end of file diff --git a/std/js/html/DOMApplicationCache.hx b/std/js/html/DOMApplicationCache.hx index 26e738da28fbbcfba3cb55d3a856c1780dc56d94..61887d9d920beec82223751928774eff14668060 100644 --- a/std/js/html/DOMApplicationCache.hx +++ b/std/js/html/DOMApplicationCache.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,46 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("DOMApplicationCache") -extern class DOMApplicationCache extends EventTarget -{ - static inline var CHECKING : Int = 2; - - static inline var DOWNLOADING : Int = 3; - - static inline var IDLE : Int = 1; - - static inline var OBSOLETE : Int = 5; - - static inline var UNCACHED : Int = 0; - - static inline var UPDATEREADY : Int = 4; - - var oncached : EventListener; - - var onchecking : EventListener; - - var ondownloading : EventListener; - - var onerror : EventListener; - - var onnoupdate : EventListener; - - var onobsolete : EventListener; - - var onprogress : EventListener; - - var onupdateready : EventListener; - - var status(default,null) : Int; - - function abort() : Void; - - function swapCache() : Void; - - function update() : Void; - -} +/** @deprecated Use ApplicationCache instead. */ +@:deprecated("DOMApplicationCache is deprecated, use ApplicationCache instead") +typedef DOMApplicationCache = ApplicationCache; diff --git a/std/js/html/DOMCoreException.hx b/std/js/html/DOMCoreException.hx index 29504cfd246dec54dad7e09e4c04d44fe2867e01..e18ca36854392d1d2c3b3a833d4f895904b8dcc7 100644 --- a/std/js/html/DOMCoreException.hx +++ b/std/js/html/DOMCoreException.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,68 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("DOMException") -extern class DOMCoreException -{ - static inline var ABORT_ERR : Int = 20; - - static inline var DATA_CLONE_ERR : Int = 25; - - static inline var DOMSTRING_SIZE_ERR : Int = 2; - - static inline var HIERARCHY_REQUEST_ERR : Int = 3; - - static inline var INDEX_SIZE_ERR : Int = 1; - - static inline var INUSE_ATTRIBUTE_ERR : Int = 10; - - static inline var INVALID_ACCESS_ERR : Int = 15; - - static inline var INVALID_CHARACTER_ERR : Int = 5; - - static inline var INVALID_MODIFICATION_ERR : Int = 13; - - static inline var INVALID_NODE_TYPE_ERR : Int = 24; - - static inline var INVALID_STATE_ERR : Int = 11; - - static inline var NAMESPACE_ERR : Int = 14; - - static inline var NETWORK_ERR : Int = 19; - - static inline var NOT_FOUND_ERR : Int = 8; - - static inline var NOT_SUPPORTED_ERR : Int = 9; - - static inline var NO_DATA_ALLOWED_ERR : Int = 6; - - static inline var NO_MODIFICATION_ALLOWED_ERR : Int = 7; - - static inline var QUOTA_EXCEEDED_ERR : Int = 22; - - static inline var SECURITY_ERR : Int = 18; - - static inline var SYNTAX_ERR : Int = 12; - - static inline var TIMEOUT_ERR : Int = 23; - - static inline var TYPE_MISMATCH_ERR : Int = 17; - - static inline var URL_MISMATCH_ERR : Int = 21; - - static inline var VALIDATION_ERR : Int = 16; - - static inline var WRONG_DOCUMENT_ERR : Int = 4; - - var code(default,null) : Int; - - var message(default,null) : String; - - var name(default,null) : String; - - function toString() : String; - -} +/** @deprecated Use DOMException instead. */ +@:deprecated("DOMCoreException is deprecated, use DOMException instead") +typedef DOMCoreException = DOMException; diff --git a/std/js/html/DOMCursor.hx b/std/js/html/DOMCursor.hx new file mode 100644 index 0000000000000000000000000000000000000000..175663dfd7586523c85d1727739f44a7b66d8351 --- /dev/null +++ b/std/js/html/DOMCursor.hx @@ -0,0 +1,40 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMCursor.webidl line 6:0. Do not edit! + +package js.html; + +@:native("DOMCursor") +extern class DOMCursor extends EventTarget +{ + var done(default,null) : Bool; + var readyState(default,null) : DOMRequestReadyState; + var result(default,null) : Dynamic; + var error(default,null) : DOMError; + var onsuccess : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + + /** @throws DOMError */ + @:native("continue") + function continue_() : Void; +} \ No newline at end of file diff --git a/std/js/html/DOMElement.hx b/std/js/html/DOMElement.hx new file mode 100644 index 0000000000000000000000000000000000000000..bee3892a2c0a1cc981efacc57eb069860191f71b --- /dev/null +++ b/std/js/html/DOMElement.hx @@ -0,0 +1,224 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Element.webidl line 16:0. Do not edit! + +package js.html; + +@:native("Element") +extern class DOMElement extends Node +{ + var tagName(default,null) : String; + var id : String; + var className : String; + var classList(default,null) : DOMTokenList; + var attributes(default,null) : NamedNodeMap; + var onwheel : haxe.Constraints.Function; + var title : String; + var lang : String; + var dir : String; + var dataset(default,null) : DOMStringMap; + var itemScope : Bool; + var itemType(default,null) : DOMSettableTokenList; + var itemId : String; + var itemRef(default,null) : DOMSettableTokenList; + var itemProp(default,null) : DOMSettableTokenList; + var properties(default,null) : HTMLPropertiesCollection; + var itemValue : Dynamic; + var hidden : Bool; + var tabIndex : Int; + var accessKey : String; + var accessKeyLabel(default,null) : String; + var draggable : Bool; + var contentEditable : String; + var isContentEditable(default,null) : Bool; + var contextMenu(default,null) : MenuElement; + var spellcheck : Bool; + var style(default,null) : CSSStyleDeclaration; + var oncopy : haxe.Constraints.Function; + var oncut : haxe.Constraints.Function; + var onpaste : haxe.Constraints.Function; + var innerText : String; + var offsetParent(default,null) : Element; + var offsetTop(default,null) : Int; + var offsetLeft(default,null) : Int; + var offsetWidth(default,null) : Int; + var offsetHeight(default,null) : Int; + var scrollTop : Int; + var scrollLeft : Int; + var scrollWidth(default,null) : Int; + var scrollHeight(default,null) : Int; + var clientTop(default,null) : Int; + var clientLeft(default,null) : Int; + var clientWidth(default,null) : Int; + var clientHeight(default,null) : Int; + var scrollTopMax(default,null) : Int; + var scrollLeftMax(default,null) : Int; + var innerHTML : String; + var outerHTML : String; + var shadowRoot(default,null) : ShadowRoot; + var onabort : haxe.Constraints.Function; + var onblur : haxe.Constraints.Function; + var onfocus : haxe.Constraints.Function; + var oncanplay : haxe.Constraints.Function; + var oncanplaythrough : haxe.Constraints.Function; + var onchange : haxe.Constraints.Function; + var onclick : haxe.Constraints.Function; + var oncontextmenu : haxe.Constraints.Function; + var ondblclick : haxe.Constraints.Function; + var ondrag : haxe.Constraints.Function; + var ondragend : haxe.Constraints.Function; + var ondragenter : haxe.Constraints.Function; + var ondragleave : haxe.Constraints.Function; + var ondragover : haxe.Constraints.Function; + var ondragstart : haxe.Constraints.Function; + var ondrop : haxe.Constraints.Function; + var ondurationchange : haxe.Constraints.Function; + var onemptied : haxe.Constraints.Function; + var onended : haxe.Constraints.Function; + var oninput : haxe.Constraints.Function; + var oninvalid : haxe.Constraints.Function; + var onkeydown : haxe.Constraints.Function; + var onkeypress : haxe.Constraints.Function; + var onkeyup : haxe.Constraints.Function; + var onload : haxe.Constraints.Function; + var onloadeddata : haxe.Constraints.Function; + var onloadedmetadata : haxe.Constraints.Function; + var onloadstart : haxe.Constraints.Function; + var onmousedown : haxe.Constraints.Function; + var onmouseenter : haxe.Constraints.Function; + var onmouseleave : haxe.Constraints.Function; + var onmousemove : haxe.Constraints.Function; + var onmouseout : haxe.Constraints.Function; + var onmouseover : haxe.Constraints.Function; + var onmouseup : haxe.Constraints.Function; + var onpause : haxe.Constraints.Function; + var onplay : haxe.Constraints.Function; + var onplaying : haxe.Constraints.Function; + var onprogress : haxe.Constraints.Function; + var onratechange : haxe.Constraints.Function; + var onreset : haxe.Constraints.Function; + var onscroll : haxe.Constraints.Function; + var onseeked : haxe.Constraints.Function; + var onseeking : haxe.Constraints.Function; + var onselect : haxe.Constraints.Function; + var onshow : haxe.Constraints.Function; + var onstalled : haxe.Constraints.Function; + var onsubmit : haxe.Constraints.Function; + var onsuspend : haxe.Constraints.Function; + var ontimeupdate : haxe.Constraints.Function; + var onvolumechange : haxe.Constraints.Function; + var onwaiting : haxe.Constraints.Function; + var onpointercancel : haxe.Constraints.Function; + var onpointerdown : haxe.Constraints.Function; + var onpointerup : haxe.Constraints.Function; + var onpointermove : haxe.Constraints.Function; + var onpointerout : haxe.Constraints.Function; + var onpointerover : haxe.Constraints.Function; + var onpointerenter : haxe.Constraints.Function; + var onpointerleave : haxe.Constraints.Function; + var ongotpointercapture : haxe.Constraints.Function; + var onlostpointercapture : haxe.Constraints.Function; + var onpointerlockchange : haxe.Constraints.Function; + var onpointerlockerror : haxe.Constraints.Function; + var previousElementSibling(default,null) : Element; + var nextElementSibling(default,null) : Element; + var onerror : haxe.Constraints.Function; + var children(default,null) : HTMLCollection; + var firstElementChild(default,null) : Element; + var lastElementChild(default,null) : Element; + var childElementCount(default,null) : Int; + var ontouchstart : haxe.Constraints.Function; + var ontouchend : haxe.Constraints.Function; + var ontouchmove : haxe.Constraints.Function; + var ontouchcancel : haxe.Constraints.Function; + + function getAttribute( name : String ) : String; + function getAttributeNS( namespace_ : String, localName : String ) : String; + /** @throws DOMError */ + function setAttribute( name : String, value : String ) : Void; + /** @throws DOMError */ + function setAttributeNS( namespace_ : String, name : String, value : String ) : Void; + /** @throws DOMError */ + function removeAttribute( name : String ) : Void; + /** @throws DOMError */ + function removeAttributeNS( namespace_ : String, localName : String ) : Void; + function hasAttribute( name : String ) : Bool; + function hasAttributeNS( namespace_ : String, localName : String ) : Bool; + function hasAttributes() : Bool; + /** @throws DOMError */ + function closest( selector : String ) : Element; + /** @throws DOMError */ + function matches( selector : String ) : Bool; + function getElementsByTagName( localName : String ) : HTMLCollection; + /** @throws DOMError */ + function getElementsByTagNameNS( namespace_ : String, localName : String ) : HTMLCollection; + function getElementsByClassName( classNames : String ) : HTMLCollection; + /** @throws DOMError */ + function setPointerCapture( pointerId : Int ) : Void; + /** @throws DOMError */ + function releasePointerCapture( pointerId : Int ) : Void; + function setCapture( ?retargetToElement : Bool = false ) : Void; + function releaseCapture() : Void; + function requestPointerLock() : Void; + function getAttributeNode( name : String ) : Attr; + /** @throws DOMError */ + function setAttributeNode( newAttr : Attr ) : Attr; + /** @throws DOMError */ + function removeAttributeNode( oldAttr : Attr ) : Attr; + function getAttributeNodeNS( namespaceURI : String, localName : String ) : Attr; + /** @throws DOMError */ + function setAttributeNodeNS( newAttr : Attr ) : Attr; + function requestFullscreen() : Void; + function click() : Void; + /** @throws DOMError */ + function focus() : Void; + /** @throws DOMError */ + function blur() : Void; + function getClientRects() : DOMRectList; + function getBoundingClientRect() : DOMRect; + @:overload( function( top : Bool ) : Void {} ) + function scrollIntoView( ?options : ScrollIntoViewOptions ) : Void; + @:overload( function( x : Float, y : Float ) : Void {} ) + function scroll( ?options : ScrollToOptions ) : Void; + @:overload( function( x : Float, y : Float ) : Void {} ) + function scrollTo( ?options : ScrollToOptions ) : Void; + @:overload( function( x : Float, y : Float ) : Void {} ) + function scrollBy( ?options : ScrollToOptions ) : Void; + /** @throws DOMError */ + function insertAdjacentHTML( position : String, text : String ) : Void; + /** @throws DOMError */ + function querySelector( selectors : String ) : Element; + /** @throws DOMError */ + function querySelectorAll( selectors : String ) : NodeList; + /** @throws DOMError */ + function createShadowRoot() : ShadowRoot; + function getDestinationInsertionPoints() : NodeList; + function getAnimationPlayers() : Array; + function remove() : Void; + /** @throws DOMError */ + function convertQuadFromNode( quad : DOMQuad, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMQuad; + /** @throws DOMError */ + function convertRectFromNode( rect : DOMRectReadOnly, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMQuad; + /** @throws DOMError */ + function convertPointFromNode( point : DOMPointInit, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMPoint; +} \ No newline at end of file diff --git a/std/js/html/DOMError.hx b/std/js/html/DOMError.hx index 6eb87ee6aedcd3d522d688b14a2637268c1cff72..818a4d00631f2663003c65f4799620e38ff619a1 100644 --- a/std/js/html/DOMError.hx +++ b/std/js/html/DOMError.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMError.webidl line 15:0. Do not edit! + package js.html; @:native("DOMError") extern class DOMError { var name(default,null) : String; - -} + var message(default,null) : String; + + /** @throws DOMError */ + function new( name : String, ?message : String = "" ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DOMException.hx b/std/js/html/DOMException.hx new file mode 100644 index 0000000000000000000000000000000000000000..314b8e7734d111fd101d97845e5adbe0f1fb152b --- /dev/null +++ b/std/js/html/DOMException.hx @@ -0,0 +1,67 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMException.webidl line 78:0. Do not edit! + +package js.html; + +@:native("DOMException") +extern class DOMException +{ + static inline var INDEX_SIZE_ERR : Int = 1; + static inline var DOMSTRING_SIZE_ERR : Int = 2; + static inline var HIERARCHY_REQUEST_ERR : Int = 3; + static inline var WRONG_DOCUMENT_ERR : Int = 4; + static inline var INVALID_CHARACTER_ERR : Int = 5; + static inline var NO_DATA_ALLOWED_ERR : Int = 6; + static inline var NO_MODIFICATION_ALLOWED_ERR : Int = 7; + static inline var NOT_FOUND_ERR : Int = 8; + static inline var NOT_SUPPORTED_ERR : Int = 9; + static inline var INUSE_ATTRIBUTE_ERR : Int = 10; + static inline var INVALID_STATE_ERR : Int = 11; + static inline var SYNTAX_ERR : Int = 12; + static inline var INVALID_MODIFICATION_ERR : Int = 13; + static inline var NAMESPACE_ERR : Int = 14; + static inline var INVALID_ACCESS_ERR : Int = 15; + static inline var VALIDATION_ERR : Int = 16; + static inline var TYPE_MISMATCH_ERR : Int = 17; + static inline var SECURITY_ERR : Int = 18; + static inline var NETWORK_ERR : Int = 19; + static inline var ABORT_ERR : Int = 20; + static inline var URL_MISMATCH_ERR : Int = 21; + static inline var QUOTA_EXCEEDED_ERR : Int = 22; + static inline var TIMEOUT_ERR : Int = 23; + static inline var INVALID_NODE_TYPE_ERR : Int = 24; + static inline var DATA_CLONE_ERR : Int = 25; + + var code(default,null) : Int; + var message(default,null) : String; + var result(default,null) : Int; + var name(default,null) : String; + var filename(default,null) : String; + var lineNumber(default,null) : Int; + var columnNumber(default,null) : Int; + var inner(default,null) : Dynamic/*MISSING nsISupports*/; + var data(default,null) : Dynamic/*MISSING nsISupports*/; + var stack(default,null) : String; + +} \ No newline at end of file diff --git a/std/js/html/DOMFormData.hx b/std/js/html/DOMFormData.hx index 07696644846dd3419afaa5f02cecfae9385bfd10..6e6a8c6dfbf602e94362bfb3eb8cf2ac8d5999b3 100644 --- a/std/js/html/DOMFormData.hx +++ b/std/js/html/DOMFormData.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("FormData") -extern class DOMFormData -{ - function new(?arg0 : Dynamic) : Void; - - function append( name : String, value : String, filename : String ) : Void; - -} +/** @deprecated Use FormData instead. */ +@:deprecated("DOMFormData is deprecated, use FormData instead") +typedef DOMFormData = FormData; diff --git a/std/js/html/DOMImplementation.hx b/std/js/html/DOMImplementation.hx index 43c526c65ece47655d5b2fd29d6292c5a7488f92..45e98ee5107251e94c7aef831bb10567957db395 100644 --- a/std/js/html/DOMImplementation.hx +++ b/std/js/html/DOMImplementation.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,22 +20,18 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMImplementation.webidl line 14:0. Do not edit! + package js.html; -/** Provides methods which are not dependent on any particular DOM instances. Returned by document.implementation.

-Documentation for this class was provided by MDN. */ @:native("DOMImplementation") extern class DOMImplementation { - function createCSSStyleSheet( title : String, media : String ) : CSSStyleSheet; - - function createDocument( ?namespaceURI : String, ?qualifiedName : String, ?doctype : DocumentType ) : Document; - - function createDocumentType( ?qualifiedName : String, ?publicId : String, ?systemId : String ) : DocumentType; - - function createHTMLDocument( title : String ) : Document; - - function hasFeature( feature : String, ?version : String ) : Bool; - -} + function hasFeature( feature : String, version : String ) : Bool; + /** @throws DOMError */ + function createDocumentType( qualifiedName : String, publicId : String, systemId : String ) : DocumentType; + /** @throws DOMError */ + function createDocument( namespace_ : String, qualifiedName : String, ?doctype : DocumentType ) : HTMLDocument; + /** @throws DOMError */ + function createHTMLDocument( ?title : String ) : HTMLDocument; +} \ No newline at end of file diff --git a/std/js/html/DOMMatrix.hx b/std/js/html/DOMMatrix.hx new file mode 100644 index 0000000000000000000000000000000000000000..cf613f2bdf693c0ceb322c5170a02216f8aadf27 --- /dev/null +++ b/std/js/html/DOMMatrix.hx @@ -0,0 +1,51 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMMatrix.webidl line 89:0. Do not edit! + +package js.html; + +@:native("DOMMatrix") +extern class DOMMatrix extends DOMMatrixReadOnly +{ + /** @throws DOMError */ + @:overload( function() : Void {} ) + @:overload( function( transformList : String ) : Void {} ) + @:overload( function( other : DOMMatrixReadOnly ) : Void {} ) + @:overload( function( array32 : Float32Array ) : Void {} ) + @:overload( function( array64 : Float64Array ) : Void {} ) + function new( numberSequence : Array ) : Void; + function multiplySelf( other : DOMMatrix ) : DOMMatrix; + function preMultiplySelf( other : DOMMatrix ) : DOMMatrix; + function translateSelf( tx : Float, ty : Float, ?tz : Float = 0.0 ) : DOMMatrix; + function scaleSelf( scale : Float, ?originX : Float = 0.0, ?originY : Float = 0.0 ) : DOMMatrix; + function scale3dSelf( scale : Float, ?originX : Float = 0.0, ?originY : Float = 0.0, ?originZ : Float = 0.0 ) : DOMMatrix; + function scaleNonUniformSelf( scaleX : Float, ?scaleY : Float = 1.0, ?scaleZ : Float = 1.0, ?originX : Float = 0.0, ?originY : Float = 0.0, ?originZ : Float = 0.0 ) : DOMMatrix; + function rotateSelf( angle : Float, ?originX : Float = 0.0, ?originY : Float = 0.0 ) : DOMMatrix; + function rotateFromVectorSelf( x : Float, y : Float ) : DOMMatrix; + function rotateAxisAngleSelf( x : Float, y : Float, z : Float, angle : Float ) : DOMMatrix; + function skewXSelf( sx : Float ) : DOMMatrix; + function skewYSelf( sy : Float ) : DOMMatrix; + function invertSelf() : DOMMatrix; + /** @throws DOMError */ + function setMatrixValue( transformList : String ) : DOMMatrix; +} \ No newline at end of file diff --git a/std/js/html/DOMMatrixReadOnly.hx b/std/js/html/DOMMatrixReadOnly.hx new file mode 100644 index 0000000000000000000000000000000000000000..2d46028c5555681eef6a37491b1137bcf84eae45 --- /dev/null +++ b/std/js/html/DOMMatrixReadOnly.hx @@ -0,0 +1,73 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMMatrix.webidl line 14:0. Do not edit! + +package js.html; + +@:native("DOMMatrixReadOnly") +extern class DOMMatrixReadOnly +{ + var a(default,null) : Float; + var b(default,null) : Float; + var c(default,null) : Float; + var d(default,null) : Float; + var e(default,null) : Float; + var f(default,null) : Float; + var m11(default,null) : Float; + var m12(default,null) : Float; + var m13(default,null) : Float; + var m14(default,null) : Float; + var m21(default,null) : Float; + var m22(default,null) : Float; + var m23(default,null) : Float; + var m24(default,null) : Float; + var m31(default,null) : Float; + var m32(default,null) : Float; + var m33(default,null) : Float; + var m34(default,null) : Float; + var m41(default,null) : Float; + var m42(default,null) : Float; + var m43(default,null) : Float; + var m44(default,null) : Float; + var is2D(default,null) : Bool; + var identity(default,null) : Bool; + + function translate( tx : Float, ty : Float, ?tz : Float = 0.0 ) : DOMMatrix; + function scale( scale : Float, ?originX : Float = 0.0, ?originY : Float = 0.0 ) : DOMMatrix; + function scale3d( scale : Float, ?originX : Float = 0.0, ?originY : Float = 0.0, ?originZ : Float = 0.0 ) : DOMMatrix; + function scaleNonUniform( scaleX : Float, ?scaleY : Float = 1.0, ?scaleZ : Float = 1.0, ?originX : Float = 0.0, ?originY : Float = 0.0, ?originZ : Float = 0.0 ) : DOMMatrix; + function rotate( angle : Float, ?originX : Float = 0.0, ?originY : Float = 0.0 ) : DOMMatrix; + function rotateFromVector( x : Float, y : Float ) : DOMMatrix; + function rotateAxisAngle( x : Float, y : Float, z : Float, angle : Float ) : DOMMatrix; + function skewX( sx : Float ) : DOMMatrix; + function skewY( sy : Float ) : DOMMatrix; + function multiply( other : DOMMatrix ) : DOMMatrix; + function flipX() : DOMMatrix; + function flipY() : DOMMatrix; + function inverse() : DOMMatrix; + function transformPoint( ?point : DOMPointInit ) : DOMPoint; + /** @throws DOMError */ + function toFloat32Array() : Float32Array; + /** @throws DOMError */ + function toFloat64Array() : Float64Array; +} \ No newline at end of file diff --git a/std/js/html/DOMMimeType.hx b/std/js/html/DOMMimeType.hx index 54b98b15cc6f8140709a053ba8355b8d33614488..c58ee610dfac7e90346ffc063bae10096e9e28a6 100644 --- a/std/js/html/DOMMimeType.hx +++ b/std/js/html/DOMMimeType.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("MimeType") -extern class DOMMimeType -{ - var description(default,null) : String; - - var enabledPlugin(default,null) : DOMPlugin; - - var suffixes(default,null) : String; - - var type(default,null) : String; - -} +/** @deprecated Use MimeType instead. */ +@:deprecated("DOMMimeType is deprecated, use MimeType instead") +typedef DOMMimeType = MimeType; diff --git a/std/js/html/DOMMimeTypeArray.hx b/std/js/html/DOMMimeTypeArray.hx index 244d2db3b2781ff0f6b87ed1f9843b6c36058d70..e805872b4c145ff3fed47df117b4dfc475cc69c3 100644 --- a/std/js/html/DOMMimeTypeArray.hx +++ b/std/js/html/DOMMimeTypeArray.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("MimeTypeArray") -extern class DOMMimeTypeArray implements ArrayAccess -{ - var length(default,null) : Int; - - function item( index : Int ) : DOMMimeType; - - function namedItem( name : String ) : DOMMimeType; - -} +/** @deprecated Use MimeTypeArray instead. */ +@:deprecated("DOMMimeTypeArray is deprecated, use MimeTypeArray instead") +typedef DOMMimeTypeArray = MimeTypeArray; diff --git a/std/js/html/DOMParser.hx b/std/js/html/DOMParser.hx index c02dbb18fca8b508a520bb65082ec797b9b70404..56a81d113ee929c68d2fe2c069c4e390d6847b56 100644 --- a/std/js/html/DOMParser.hx +++ b/std/js/html/DOMParser.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMParser.webidl line 25:0. Do not edit! + package js.html; -/** This page redirects to a page that no longer exists en/Document_Object_Model_(DOM)/DOMParser.

-Documentation for this class was provided by MDN. */ @:native("DOMParser") extern class DOMParser { - function new() : Void; - - function parseFromString( str : String, contentType : String ) : Document; - -} + /** @throws DOMError */ + @:overload( function() : Void {} ) + function new( prin : Dynamic/*MISSING Principal*/, ?documentURI : Dynamic/*MISSING URI*/, ?baseURI : Dynamic/*MISSING URI*/ ) : Void; + /** @throws DOMError */ + function parseFromString( str : String, type : SupportedType ) : HTMLDocument; +} \ No newline at end of file diff --git a/std/js/html/DOMPlugin.hx b/std/js/html/DOMPlugin.hx index 0cababa205bf2198df74e483b0890dbe87fbe160..ccd57269f86566a1c7a37b0bfe81e0b7d94a3c9f 100644 --- a/std/js/html/DOMPlugin.hx +++ b/std/js/html/DOMPlugin.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,27 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -/** The Plugin interface provides information about a browser plugin.

-Documentation for this class was provided by MDN. */ -@:native("Plugin") -extern class DOMPlugin implements ArrayAccess -{ - /** A human readable description of the plugin. Read only. */ - var description(default,null) : String; - - /** The filename of the plugin file. Read only. */ - var filename(default,null) : String; - - var length(default,null) : Int; - - /** The name of the plugin. Read only. */ - var name(default,null) : String; - - function item( index : Int ) : DOMMimeType; - - function namedItem( name : String ) : DOMMimeType; - -} +/** @deprecated Use Plugin instead. */ +@:deprecated("DOMPlugin is deprecated, use Plugin instead") +typedef DOMPlugin = Plugin; diff --git a/std/js/html/DOMPluginArray.hx b/std/js/html/DOMPluginArray.hx index 9754aa724d1bd4657fd6f25956f24aa692deaf6d..64b37bcfedb9e9941e691e5e4b408641c398b531 100644 --- a/std/js/html/DOMPluginArray.hx +++ b/std/js/html/DOMPluginArray.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("PluginArray") -extern class DOMPluginArray implements ArrayAccess -{ - var length(default,null) : Int; - - function item( index : Int ) : DOMPlugin; - - function namedItem( name : String ) : DOMPlugin; - - function refresh( reload : Bool ) : Void; - -} +/** @deprecated Use PluginArray instead. */ +@:deprecated("DOMPluginArray is deprecated, use PluginArray instead") +typedef DOMPluginArray = PluginArray; diff --git a/std/js/html/DOMPoint.hx b/std/js/html/DOMPoint.hx new file mode 100644 index 0000000000000000000000000000000000000000..12699f904fca08d131e0a689320241be5b016ed5 --- /dev/null +++ b/std/js/html/DOMPoint.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMPoint.webidl line 25:0. Do not edit! + +package js.html; + +@:native("DOMPoint") +extern class DOMPoint extends DOMPointReadOnly +{ + /** @throws DOMError */ + @:overload( function( ?point : DOMPointInit ) : Void {} ) + function new( x : Float, y : Float, ?z : Float = 0.0, ?w : Float = 1.0 ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DOMPointInit.hx b/std/js/html/DOMPointInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..1dc524ed5114a2bd70157d0f679c742b91941aca --- /dev/null +++ b/std/js/html/DOMPointInit.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMPoint.webidl line 32:0. Do not edit! + +package js.html; + +typedef DOMPointInit = +{ + @:optional var w : Float; + @:optional var x : Float; + @:optional var y : Float; + @:optional var z : Float; +} \ No newline at end of file diff --git a/std/js/html/DOMPointReadOnly.hx b/std/js/html/DOMPointReadOnly.hx new file mode 100644 index 0000000000000000000000000000000000000000..91baf268999a8633254be9af2bc23201c8bf6e24 --- /dev/null +++ b/std/js/html/DOMPointReadOnly.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMPoint.webidl line 14:0. Do not edit! + +package js.html; + +@:native("DOMPointReadOnly") +extern class DOMPointReadOnly +{ + var x(default,null) : Float; + var y(default,null) : Float; + var z(default,null) : Float; + var w(default,null) : Float; + +} \ No newline at end of file diff --git a/std/js/html/DOMQuad.hx b/std/js/html/DOMQuad.hx new file mode 100644 index 0000000000000000000000000000000000000000..f3579691a10389f9de5d860422b6cf399740de59 --- /dev/null +++ b/std/js/html/DOMQuad.hx @@ -0,0 +1,39 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMQuad.webidl line 17:0. Do not edit! + +package js.html; + +@:native("DOMQuad") +extern class DOMQuad +{ + var p1(default,null) : DOMPoint; + var p2(default,null) : DOMPoint; + var p3(default,null) : DOMPoint; + var p4(default,null) : DOMPoint; + var bounds(default,null) : DOMRectReadOnly; + + /** @throws DOMError */ + @:overload( function( ?p1 : DOMPointInit, ?p2 : DOMPointInit, ?p3 : DOMPointInit, ?p4 : DOMPointInit ) : Void {} ) + function new( rect : DOMRectReadOnly ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DOMRect.hx b/std/js/html/DOMRect.hx new file mode 100644 index 0000000000000000000000000000000000000000..e7d098913acdc1cd5b87135e6be395f70848d0ff --- /dev/null +++ b/std/js/html/DOMRect.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMRect.webidl line 16:0. Do not edit! + +package js.html; + +@:native("DOMRect") +extern class DOMRect extends DOMRectReadOnly +{ + /** @throws DOMError */ + @:overload( function() : Void {} ) + function new( x : Float, y : Float, width : Float, height : Float ) : Void; +} \ No newline at end of file diff --git a/std/js/html/GamepadList.hx b/std/js/html/DOMRectList.hx similarity index 82% rename from std/js/html/GamepadList.hx rename to std/js/html/DOMRectList.hx index c18d501245b329e349428894811a3edce0e952b5..5341176d31966d948011ed573b507d5ed0067975 100644 --- a/std/js/html/GamepadList.hx +++ b/std/js/html/DOMRectList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,14 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMRectList.webidl line 8:0. Do not edit! + package js.html; -@:native("GamepadList") -extern class GamepadList implements ArrayAccess +@:native("DOMRectList") +extern class DOMRectList implements ArrayAccess { var length(default,null) : Int; - - function item( index : Int ) : Gamepad; - -} + + function item( index : Int ) : DOMRect; +} \ No newline at end of file diff --git a/std/js/html/DOMRectReadOnly.hx b/std/js/html/DOMRectReadOnly.hx new file mode 100644 index 0000000000000000000000000000000000000000..b6c35ed236251d7dfd3086b606427d1ca459d73d --- /dev/null +++ b/std/js/html/DOMRectReadOnly.hx @@ -0,0 +1,39 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMRect.webidl line 23:0. Do not edit! + +package js.html; + +@:native("DOMRectReadOnly") +extern class DOMRectReadOnly +{ + var x(default,null) : Float; + var y(default,null) : Float; + var width(default,null) : Float; + var height(default,null) : Float; + var top(default,null) : Float; + var right(default,null) : Float; + var bottom(default,null) : Float; + var left(default,null) : Float; + +} \ No newline at end of file diff --git a/std/js/html/DOMRequest.hx b/std/js/html/DOMRequest.hx new file mode 100644 index 0000000000000000000000000000000000000000..fc58ce1effb583308300551c6d3ab9672d544cb6 --- /dev/null +++ b/std/js/html/DOMRequest.hx @@ -0,0 +1,37 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMRequest.webidl line 19:0. Do not edit! + +package js.html; + +@:native("DOMRequest") +extern class DOMRequest extends EventTarget +{ + var readyState(default,null) : DOMRequestReadyState; + var result(default,null) : Dynamic; + var error(default,null) : DOMError; + var onsuccess : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + + function then( ?fulfillCallback : haxe.Constraints.Function, ?rejectCallback : haxe.Constraints.Function ) : Promise; +} \ No newline at end of file diff --git a/std/js/html/DOMRequestReadyState.hx b/std/js/html/DOMRequestReadyState.hx new file mode 100644 index 0000000000000000000000000000000000000000..fabe2429015baccac0929176cb4b0aca07d52c1c --- /dev/null +++ b/std/js/html/DOMRequestReadyState.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMRequest.webidl line 6:0. Do not edit! + +package js.html; + +@:enum abstract DOMRequestReadyState(String) +{ + var PENDING = "pending"; + var DONE = "done"; +} \ No newline at end of file diff --git a/std/js/html/DOMSelection.hx b/std/js/html/DOMSelection.hx index 4f9aafe592eaeceb8b0e156ca2f5c8539b14a3a7..a42b4c0264834a06c12dad7f78d69cb9203c58a9 100644 --- a/std/js/html/DOMSelection.hx +++ b/std/js/html/DOMSelection.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,90 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -/**

Selection is the class of the object returned by window.getSelection() - and other methods. It represents the text selection in the greater page, possibly spanning multiple elements, when the user drags over static text and other parts of the page. For information about text selection in an individual text editing element, see Input -, TextArea - and document.activeElement - which typically return the parent object returned from window.getSelection() -.

-

A selection object represents the ranges - that the user has selected. Typically, it holds only one range, accessed as follows:

- -
var selObj = window.getSelection();
-var range  = selObj.getRangeAt(0);
- -
  • selObj is a Selection object
  • range is a Range object
  • -
-

Calling the Selection/toString() - method returns the text contained in the selection, e.g

- -
var selObj = window.getSelection();
-window.alert(selObj);
- -

Note that using a selection object as the argument to window.alert will call the object's toString method.



-Documentation for this class was provided by MDN. */ -@:native("Selection") -extern class DOMSelection -{ - /** Returns the node in which the selection begins. */ - var anchorNode(default,null) : Node; - - /** Returns the number of characters that the selection's anchor is offset within the anchorNode. */ - var anchorOffset(default,null) : Int; - - var baseNode(default,null) : Node; - - var baseOffset(default,null) : Int; - - var extentNode(default,null) : Node; - - var extentOffset(default,null) : Int; - - /** Returns the node in which the selection ends. */ - var focusNode(default,null) : Node; - - /** Returns the number of characters that the selection's focus is offset within the focusNode. */ - var focusOffset(default,null) : Int; - - /** Returns a Boolean indicating whether the selection's start and end points are at the same position. */ - var isCollapsed(default,null) : Bool; - - /** Returns the number of ranges in the selection. */ - var rangeCount(default,null) : Int; - - var type(default,null) : String; - - function addRange( range : Range ) : Void; - - function collapse( node : Node, index : Int ) : Void; - - function collapseToEnd() : Void; - - function collapseToStart() : Void; - - function containsNode( node : Node, allowPartial : Bool ) : Bool; - - function deleteFromDocument() : Void; - - function empty() : Void; - - function extend( node : Node, offset : Int ) : Void; - - function getRangeAt( index : Int ) : Range; - - function modify( alter : String, direction : String, granularity : String ) : Void; - - function removeAllRanges() : Void; - - function selectAllChildren( node : Node ) : Void; - - function setBaseAndExtent( baseNode : Node, baseOffset : Int, extentNode : Node, extentOffset : Int ) : Void; - - function setPosition( node : Node, offset : Int ) : Void; - - function toString() : String; - -} +/** @deprecated Use Selection instead. */ +@:deprecated("DOMSelection is deprecated, use Selection instead") +typedef DOMSelection = Selection; diff --git a/std/js/html/DOMSettableTokenList.hx b/std/js/html/DOMSettableTokenList.hx index 88cc202a4626fe0b73ec18a057b7bb542cc5c51f..032b371aa6a7db7c778e45ec4769bbf6188c8b66 100644 --- a/std/js/html/DOMSettableTokenList.hx +++ b/std/js/html/DOMSettableTokenList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMSettableTokenList.webidl line 13:0. Do not edit! + package js.html; @:native("DOMSettableTokenList") extern class DOMSettableTokenList extends DOMTokenList { var value : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/DOMStringList.hx b/std/js/html/DOMStringList.hx index 1354ec8069bd55bf8324a05819860108102e7846..6ee5d141069e83b48b43ffef7140c6de3d89fccf 100644 --- a/std/js/html/DOMStringList.hx +++ b/std/js/html/DOMStringList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMStringList.webidl line 13:0. Do not edit! + package js.html; @:native("DOMStringList") extern class DOMStringList implements ArrayAccess { var length(default,null) : Int; - - function contains( string : String ) : Bool; - + function item( index : Int ) : String; - -} + function contains( string : String ) : Bool; +} \ No newline at end of file diff --git a/std/js/html/DOMStringMap.hx b/std/js/html/DOMStringMap.hx index 0d8958bd9c8668d28d72558746f613632a8bec8c..55cfcc4a9d378dfb83ab30ee057d7c92222d4a3b 100644 --- a/std/js/html/DOMStringMap.hx +++ b/std/js/html/DOMStringMap.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,10 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMStringMap.webidl line 15:0. Do not edit! + package js.html; @:native("DOMStringMap") -extern class DOMStringMap +extern class DOMStringMap implements Dynamic { -} +} \ No newline at end of file diff --git a/std/js/html/DOMTokenList.hx b/std/js/html/DOMTokenList.hx index 720773b1b56786a3e13d15e8eab4cc2f4860bc97..a6d4808f6f5301504b735ff100bf031709c1b672 100644 --- a/std/js/html/DOMTokenList.hx +++ b/std/js/html/DOMTokenList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,27 +20,22 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DOMTokenList.webidl line 13:0. Do not edit! + package js.html; -/** This type represents a set of space-separated tokens. Commonly returned by HTMLElement.classList -, HTMLLinkElement.relList, HTMLAnchorElement.relList or HTMLAreaElement.relList. It is indexed beginning with 0 as with JavaScript arrays. DOMTokenList is always case-sensitive.

-Documentation for this class was provided by MDN. */ @:native("DOMTokenList") extern class DOMTokenList implements ArrayAccess { var length(default,null) : Int; - - function add( tokens : String ) : Void; - - function contains( token : String ) : Bool; - + function item( index : Int ) : String; - - function remove( tokens : String ) : Void; - - function toString() : String; - + /** @throws DOMError */ + function contains( token : String ) : Bool; + /** @throws DOMError */ + function add( tokens : haxe.extern.Rest ) : Void; + /** @throws DOMError */ + function remove( tokens : haxe.extern.Rest ) : Void; + /** @throws DOMError */ function toggle( token : String, ?force : Bool ) : Bool; - -} +} \ No newline at end of file diff --git a/std/js/html/DOMTransaction.hx b/std/js/html/DOMTransaction.hx new file mode 100644 index 0000000000000000000000000000000000000000..ff18e747a3b8461b60e3c5b33849a7306abb9662 --- /dev/null +++ b/std/js/html/DOMTransaction.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMTransaction.webidl line 15:9. Do not edit! + +package js.html; + +@:native("DOMTransaction") +extern class DOMTransaction +{ + var label(default,null) : String; + var executeAutomatic(default,null) : Void -> Void; + var execute(default,null) : Void -> Void; + var undo(default,null) : Void -> Void; + var redo(default,null) : Void -> Void; + +} \ No newline at end of file diff --git a/std/js/html/DOMTransactionEvent.hx b/std/js/html/DOMTransactionEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..cfd11ff842a6b25b25ce7e86a9b12537bf58325d --- /dev/null +++ b/std/js/html/DOMTransactionEvent.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMTransactionEvent.webidl line 8:0. Do not edit! + +package js.html; + +@:native("DOMTransactionEvent") +extern class DOMTransactionEvent extends Event +{ + var transactions(default,null) : Dynamic; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : DOMTransactionEventInit ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DOMTransactionEventInit.hx b/std/js/html/DOMTransactionEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..15c63813411527b06c73da764f6bd9a4b755fc17 --- /dev/null +++ b/std/js/html/DOMTransactionEventInit.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DOMTransactionEvent.webidl line 13:0. Do not edit! + +package js.html; + +typedef DOMTransactionEventInit = +{ + > EventInit, + @:optional var transactions : Dynamic; +} \ No newline at end of file diff --git a/std/js/html/DOMURL.hx b/std/js/html/DOMURL.hx index e37ec0975bfa904cbb2afd07ceaae52ab9ba058d..ffad05c1cf88bf11899e1ae441a574553e1d15e4 100644 --- a/std/js/html/DOMURL.hx +++ b/std/js/html/DOMURL.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -@:native("URL") -extern class DOMURL -{ - function new() : Void; - - @:overload( function( source : MediaSource ) :String {} ) - @:overload( function( stream : js.html.rtc.MediaStream ) :String {} ) - static function createObjectURL( blob : Blob ) : String; - - static function revokeObjectURL( url : String ) : Void; - -} +/** @deprecated Use URL instead. */ +@:deprecated("DOMURL is deprecated, use URL instead") +typedef DOMURL = URL; diff --git a/std/js/html/DOMWindow.hx b/std/js/html/DOMWindow.hx index d892b22a672ae03042cdaf44589b79158f104798..b87ce198711c4eb5ddfc2d2702d2cb955fef3d77 100644 --- a/std/js/html/DOMWindow.hx +++ b/std/js/html/DOMWindow.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,425 +20,8 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! package js.html; -/**

This section provides a brief reference for all of the methods, properties, and events available through the DOM window object. The window object implements the Window interface, which in turn inherits from the AbstractView interface. Some additional global functions, namespaces objects, and constructors, not typically associated with the window, but available on it, are listed in the JavaScript Reference.

-

The window object represents the window itself. The document property of a window points to the DOM document loaded in that window. A window for a given document can be obtained using the document.defaultView - property.

-

In a tabbed browser, such as Firefox, each tab contains its own window object (and if you're writing an extension, the browser window itself is a separate window too - see Working with windows in chrome code for more information). That is, the window object is not shared between tabs in the same window. Some methods, namely window.resizeTo - and window.resizeBy - apply to the whole window and not to the specific tab the window object belongs to. Generally, anything that can't reasonably pertain to a tab pertains to the window instead.



-Documentation for this class was provided by MDN. */ -@:native("Window") -extern class DOMWindow extends EventTarget -{ - static inline var PERSISTENT : Int = 1; - - static inline var TEMPORARY : Int = 0; - - /** An nsIDOMOfflineResourceList - object providing access to the offline resources for the window. */ - var applicationCache(default,null) : DOMApplicationCache; - - var clientInformation(default,null) : Navigator; - - /**
This property indicates whether the current window is closed or not.
window.Components
The entry point to many XPCOM features. Some properties, e.g. classes, are only available to sufficiently privileged code.
*/ - var closed(default,null) : Bool; - - var console(default,null) : Console; - - /** Returns the browser crypto object. */ - var crypto(default,null) : Crypto; - - /** Gets/sets the status bar text for the given window. */ - var defaultStatus : String; - - var defaultstatus : String; - - var devicePixelRatio(default,null) : Float; - - /** Returns a reference to the document that the window contains. */ - var document(default,null) : Document; - - var event(default,null) : Event; - - /** Returns the element in which the window is embedded, or null if the window is not embedded. */ - var frameElement(default,null) : Element; - - /** Returns an array of the subframes in the current window. */ - var frames(default,null) : DOMWindow; - - /** Returns a reference to the history object. */ - var history(default,null) : History; - - var indexedDB(default,null) : js.html.idb.Factory; - - /** Gets the height of the content area of the browser window including, if rendered, the horizontal scrollbar. */ - var innerHeight(default,null) : Int; - - /** Gets the width of the content area of the browser window including, if rendered, the vertical scrollbar. */ - var innerWidth(default,null) : Int; - - /** Returns the number of frames in the window. See also window.frames -. */ - var length(default,null) : Int; - - /** Returns a reference to the local storage object used to store data that may only be accessed by the origin that created it. Getter throws DOMException. */ - var localStorage(default,null) : Storage; - - /** Gets/sets the location, or current URL, of the window object. */ - var location : Location; - - /** Returns the locationbar object, whose visibility can be toggled in the window. */ - var locationbar(default,null) : BarInfo; - - /** Returns the menubar object, whose visibility can be toggled in the window. */ - var menubar(default,null) : BarInfo; - - /** Gets/sets the name of the window. */ - var name : String; - - /** Returns a reference to the navigator object. */ - var navigator(default,null) : Navigator; - - var notifications(default,null) : NotificationCenter; - - var offscreenBuffering(default,null) : Bool; - - /** An event handler property for abort events on the window. */ - var onabort : EventListener; - - var onanimationend : EventListener; - - var onanimationiteration : EventListener; - - var onanimationstart : EventListener; - - /** An event handler property for before-unload events on the window. */ - var onbeforeunload : EventListener; - - /** An event handler property for blur events on the window. */ - var onblur : EventListener; - - var oncanplay : EventListener; - - var oncanplaythrough : EventListener; - - /** An event handler property for change events on the window. */ - var onchange : EventListener; - - /** An event handler property for click events on the window. */ - var onclick : EventListener; - - /** An event handler property for right-click events on the window. */ - var oncontextmenu : EventListener; - - var ondblclick : EventListener; - - var ondevicemotion : EventListener; - - var ondeviceorientation : EventListener; - - var ondrag : EventListener; - - var ondragend : EventListener; - - var ondragenter : EventListener; - - var ondragleave : EventListener; - - var ondragover : EventListener; - - var ondragstart : EventListener; - - var ondrop : EventListener; - - var ondurationchange : EventListener; - - var onemptied : EventListener; - - var onended : EventListener; - - /** An event handler property for errors raised on the window. */ - var onerror : EventListener; - - /** An event handler property for focus events on the window. */ - var onfocus : EventListener; - - /** An event handler property for hash change events on the window; called when the part of the URL after the hash mark ("#") changes. */ - var onhashchange : EventListener; - - var oninput : EventListener; - - var oninvalid : EventListener; - - /** An event handler property for keydown events on the window. */ - var onkeydown : EventListener; - - /** An event handler property for keypress events on the window. */ - var onkeypress : EventListener; - - /** An event handler property for keyup events on the window. */ - var onkeyup : EventListener; - - /** An event handler property for window loading. */ - var onload : EventListener; - - var onloadeddata : EventListener; - - var onloadedmetadata : EventListener; - - var onloadstart : EventListener; - - var onmessage : EventListener; - - /** An event handler property for mousedown events on the window. */ - var onmousedown : EventListener; - - /** An event handler property for mousemove events on the window. */ - var onmousemove : EventListener; - - /** An event handler property for mouseout events on the window. */ - var onmouseout : EventListener; - - /** An event handler property for mouseover events on the window. */ - var onmouseover : EventListener; - - /** An event handler property for mouseup events on the window. */ - var onmouseup : EventListener; - - var onmousewheel : EventListener; - - var onoffline : EventListener; - - var ononline : EventListener; - - /** An event handler property for pagehide events on the window. */ - var onpagehide : EventListener; - - /** An event handler property for pageshow events on the window. */ - var onpageshow : EventListener; - - var onpause : EventListener; - - var onplay : EventListener; - - var onplaying : EventListener; - - /** An event handler property for popstate events, which are fired when navigating to a session history entry representing a state object. */ - var onpopstate : EventListener; - - var onprogress : EventListener; - - var onratechange : EventListener; - - /** An event handler property for reset events on the window. */ - var onreset : EventListener; - - /** An event handler property for window resizing. */ - var onresize : EventListener; - - /** An event handler property for window scrolling. */ - var onscroll : EventListener; - - var onsearch : EventListener; - - var onseeked : EventListener; - - var onseeking : EventListener; - - /** An event handler property for window selection. */ - var onselect : EventListener; - - var onstalled : EventListener; - - var onstorage : EventListener; - - /** An event handler property for submits on window forms. */ - var onsubmit : EventListener; - - var onsuspend : EventListener; - - var ontimeupdate : EventListener; - - var ontouchcancel : EventListener; - - var ontouchend : EventListener; - - var ontouchmove : EventListener; - - var ontouchstart : EventListener; - - var ontransitionend : EventListener; - - /** An event handler property for unload events on the window. */ - var onunload : EventListener; - - var onvolumechange : EventListener; - - var onwaiting : EventListener; - - /** Returns a reference to the window that opened this current window. */ - var opener(default,null) : DOMWindow; - - /** Gets the height of the outside of the browser window. */ - var outerHeight(default,null) : Int; - - /** Gets the width of the outside of the browser window. */ - var outerWidth(default,null) : Int; - - var pagePopupController(default,null) : PagePopupController; - - /** An alias for window.scrollX -. */ - var pageXOffset(default,null) : Int; - - /** An alias for window.scrollY */ - var pageYOffset(default,null) : Int; - - /** Returns a reference to the parent of the current window or subframe. */ - var parent(default,null) : DOMWindow; - - var performance(default,null) : Performance; - - /** Returns the personalbar object, whose visibility can be toggled in the window. */ - var personalbar(default,null) : BarInfo; - - /** Returns a reference to the screen object associated with the window. */ - var screen(default,null) : Screen; - - var screenLeft(default,null) : Int; - - var screenTop(default,null) : Int; - - /** Returns the horizontal distance of the left border of the user's browser from the left side of the screen. */ - var screenX(default,null) : Int; - - /** Returns the vertical distance of the top border of the user's browser from the top side of the screen. */ - var screenY(default,null) : Int; - - /** Returns the number of pixels that the document has already been scrolled horizontally. */ - var scrollX(default,null) : Int; - - /** Returns the number of pixels that the document has already been scrolled vertically. */ - var scrollY(default,null) : Int; - - /** Returns the scrollbars object, whose visibility can be toggled in the window. */ - var scrollbars(default,null) : BarInfo; - - /** Returns an object reference to the window object itself. */ - var self(default,null) : DOMWindow; - - /** A storage object for storing data within a single page session. Getter throws DOMException. */ - var sessionStorage(default,null) : Storage; - - /** Gets/sets the text in the statusbar at the bottom of the browser. */ - var status : String; - - /** Returns the statusbar object, whose visibility can be toggled in the window. */ - var statusbar(default,null) : BarInfo; - - var storageInfo(default,null) : StorageInfo; - - var styleMedia(default,null) : StyleMedia; - - /** Returns the toolbar object, whose visibility can be toggled in the window. */ - var toolbar(default,null) : BarInfo; - - /**
Returns a reference to the topmost window in the window hierarchy. This property is read only.
window.URL - -Requires Gecko 2.0 -
A DOM URL object, which provides the window.URL.createObjectURL() - and window.URL.revokeObjectURL() - methods.
*/ - var top(default,null) : DOMWindow; - - /**
Returns a reference to the current window.
window[0], window[1], etc.
Returns a reference to the window object in the frames. See window.frames - for more details.
*/ - var window(default,null) : DOMWindow; - - function alert( message : String ) : Void; - - function atob( ?string : String ) : String; - - function blur() : Void; - - function btoa( ?string : String ) : String; - - @:overload( function( id : Int ) :Void {} ) - function cancelAnimationFrame( id : Int ) : Void; - - function cancelRequestAnimationFrame( id : Int ) : Void; - - function captureEvents() : Void; - - function clearInterval( handle : Int ) : Void; - - function clearTimeout( handle : Int ) : Void; - - function close() : Void; - - function confirm( message : String ) : Bool; - - function convertPointFromNodeToPage( node : Node, p : Point ) : Point; - - function convertPointFromPageToNode( node : Node, p : Point ) : Point; - - function find( string : String, caseSensitive : Bool, backwards : Bool, wrap : Bool, wholeWord : Bool, searchInFrames : Bool, showDialog : Bool ) : Bool; - - function focus() : Void; - - function getComputedStyle( element : Element, ?pseudoElement : String ) : CSSStyleDeclaration; - - function getMatchedCSSRules( element : Element, ?pseudoElement : String ) : CSSRuleList; - - function getSelection() : DOMSelection; - - function matchMedia( query : String ) : MediaQueryList; - - function moveBy( x : Float, y : Float ) : Void; - - function moveTo( x : Float, y : Float ) : Void; - - function open( url : String, name : String, ?options : String ) : DOMWindow; - - function openDatabase( name : String, version : String, displayName : String, estimatedSize : Int, ?creationCallback : js.html.sql.DatabaseCallback ) : js.html.sql.Database; - - /** Provides a secure means for one window to send a string of data to another window, which need not be within the same domain as the first, in a secure manner. Throws DOMException. */ - @:overload( function( message : Dynamic, targetOrigin : String ) :Void {} ) - function postMessage( message : Dynamic, targetOrigin : String, messagePorts : Array ) : Void; - - function print() : Void; - - function prompt( message : String, ?defaultValue : String ) : String; - - function releaseEvents() : Void; - - @:overload( function( callback_ : RequestAnimationFrameCallback ) :Int {} ) - function requestAnimationFrame( callback_ : RequestAnimationFrameCallback ) : Int; - - function requestFileSystem( type : Int, size : Int, successCallback : js.html.fs.FileSystemCallback, ?errorCallback : js.html.fs.ErrorCallback ) : Void; - - function resizeBy( x : Float, y : Float ) : Void; - - function resizeTo( width : Float, height : Float ) : Void; - - function resolveLocalFileSystemURL( url : String, successCallback : js.html.fs.EntryCallback, ?errorCallback : js.html.fs.ErrorCallback ) : Void; - - function scroll( x : Int, y : Int ) : Void; - - function scrollBy( x : Int, y : Int ) : Void; - - function scrollTo( x : Int, y : Int ) : Void; - - function setInterval( handler : Void->Void, timeout : Int ) : Int; - - function setTimeout( handler : Void->Void, timeout : Int ) : Int; - - function showModalDialog( url : String, ?dialogArgs : Dynamic, ?featureArgs : String ) : Dynamic; - - function stop() : Void; - -} +/** @deprecated Use Window instead. */ +@:deprecated("DOMWindow is deprecated, use Window instead") +typedef DOMWindow = Window; diff --git a/std/js/html/DataElement.hx b/std/js/html/DataElement.hx new file mode 100644 index 0000000000000000000000000000000000000000..59473ee21005f28aa1c2dce4ecceb09640471723 --- /dev/null +++ b/std/js/html/DataElement.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/HTMLDataElement.webidl line 10:0. Do not edit! + +package js.html; + +@:native("HTMLDataElement") +extern class DataElement extends Element +{ + var value : String; + +} \ No newline at end of file diff --git a/std/js/html/DataListElement.hx b/std/js/html/DataListElement.hx index 982d61d94d437102b94eafe8e30e963917b2ad3c..d75cc05143a8279af316e21bd32a8ef2ce1f476e 100644 --- a/std/js/html/DataListElement.hx +++ b/std/js/html/DataListElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLDataListElement.webidl line 14:0. Do not edit! + package js.html; -/** DOM Datalist objects expose the HTMLDataListElement interface, which provides special properties (beyond the element object interface they also have available to them by inheritance) to manipulate <datalist> - elements and their content.

-Documentation for this class was provided by MDN. */ @:native("HTMLDataListElement") extern class DataListElement extends Element { - /** A collection of the contained option elements. */ var options(default,null) : HTMLCollection; - -} + +} \ No newline at end of file diff --git a/std/js/html/DataTransfer.hx b/std/js/html/DataTransfer.hx new file mode 100644 index 0000000000000000000000000000000000000000..addf094c562f3df59130408aa2d37771193b4706 --- /dev/null +++ b/std/js/html/DataTransfer.hx @@ -0,0 +1,47 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DataTransfer.webidl line 11:0. Do not edit! + +package js.html; + +@:native("DataTransfer") +extern class DataTransfer +{ + var dropEffect : String; + var effectAllowed : String; + var types(default,null) : DOMStringList; + var files(default,null) : FileList; + + /** @throws DOMError */ + function new( eventType : String, isExternal : Bool ) : Void; + /** @throws DOMError */ + function setDragImage( image : Element, x : Int, y : Int ) : Void; + /** @throws DOMError */ + function getData( format : String ) : String; + /** @throws DOMError */ + function setData( format : String, data : String ) : Void; + /** @throws DOMError */ + function clearData( ?format : String ) : Void; + /** @throws DOMError */ + function addElement( element : Element ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DataView.hx b/std/js/html/DataView.hx index 089b27e6d2a2c09a824ad703ec24eb21dc5472bf..f4ff2936c745cdd9a15c40117dad402d41a2f91e 100644 --- a/std/js/html/DataView.hx +++ b/std/js/html/DataView.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,96 +20,29 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html; +// This file is generated from typedarray.webidl line 217:0. Do not edit! -/**
DRAFT -
This page is not complete.
-
+package js.html; -

-
Note: DataView is not yet implemented in Gecko. It is implemented in Chrome 9.
-

An ArrayBuffer is a useful object for representing an arbitrary chunk of data. In many cases, such data will be read from disk or from the network, and will not follow the alignment restrictions that are imposed on the Typed Array Views described earlier. In addition, the data will often be heterogeneous in nature and have a defined byte order.

-

The DataView view provides a low-level interface for reading such data from and writing it to an ArrayBuffer.



-Documentation for this class was provided by MDN. */ @:native("DataView") extern class DataView extends ArrayBufferView { - /** DataView DataView(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long byteLength);

Returns a new DataView object using the passed ArrayBuffer for its storage.

-
DataView DataView(
-  ArrayBuffer buffer,
-  optional unsigned long byteOffset,
-  optional unsigned long byteLength
-);
-
-
Parameters
-
buffer
An existing ArrayBuffer to use as the storage for the new DataView object.
byteOffset -Optional -
The offset, in bytes, to the first byte in the specified buffer for the new view to reference. If not specified, the view of the buffer will start with the first byte.
byteLength -Optional -
The number of elements in the byte array. If unspecified, length of the view will match the buffer's length.
-
-
Return value
-

A new DataView object representing the specified data buffer.

-
Exceptions thrown
-
INDEX_SIZE_ERR
The byteOffset and byteLength result in the specified view extending past the end of the buffer.
-
-
*/ - function new(?arg0 : Dynamic, ?arg1 : Dynamic, ?arg2 : Dynamic) : Void; - - function getFloat32( byteOffset : Int, ?littleEndian : Bool ) : Float; - - function getFloat64( byteOffset : Int, ?littleEndian : Bool ) : Float; - - function getInt16( byteOffset : Int, ?littleEndian : Bool ) : Int; - - function getInt32( byteOffset : Int, ?littleEndian : Bool ) : Int; - - /**

Gets a signed 8-bit integer at the specified byte offset from the start of the view.

- -
Parameters
-
offset
The offset, in byte, from the start of the view where to read the data.
-
-
Exceptions thrown
-
INDEX_SIZE_ERR
The byteOffset is set such as it would read beyond the end of the view
-
-
Throws DOMException. */ - @:overload( function() :Dynamic {} ) + /** @throws DOMError */ + function new( buffer : ArrayBuffer, ?byteOffset : Int, ?byteLength : Int ) : Void; function getInt8( byteOffset : Int ) : Int; - + function getUint8( byteOffset : Int ) : Int; + function getInt16( byteOffset : Int, ?littleEndian : Bool ) : Int; function getUint16( byteOffset : Int, ?littleEndian : Bool ) : Int; - + function getInt32( byteOffset : Int, ?littleEndian : Bool ) : Int; function getUint32( byteOffset : Int, ?littleEndian : Bool ) : Int; - - /**

Gets an unsigned 8-bit integer at the specified byte offset from the start of the view.

- -
Parameters
-
offset
The offset, in byte, from the start of the view where to read the data.
-
-
INDEX_SIZE_ERR
The byteOffset is set such as it would read beyond the end of the view
-
-
Throws DOMException. */ - @:overload( function() :Dynamic {} ) - function getUint8( byteOffset : Int ) : Int; - - function setFloat32( byteOffset : Int, value : Float, ?littleEndian : Bool ) : Void; - - function setFloat64( byteOffset : Int, value : Float, ?littleEndian : Bool ) : Void; - - function setInt16( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; - - function setInt32( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; - - /** Throws DOMException. */ - @:overload( function() :Void {} ) + function getFloat32( byteOffset : Int, ?littleEndian : Bool ) : Float; + function getFloat64( byteOffset : Int, ?littleEndian : Bool ) : Float; function setInt8( byteOffset : Int, value : Int ) : Void; - + function setUint8( byteOffset : Int, value : Int ) : Void; + function setInt16( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; function setUint16( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; - + function setInt32( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; function setUint32( byteOffset : Int, value : Int, ?littleEndian : Bool ) : Void; - - /** Throws DOMException. */ - @:overload( function() :Void {} ) - function setUint8( byteOffset : Int, value : Int ) : Void; - -} + function setFloat32( byteOffset : Int, value : Float, ?littleEndian : Bool ) : Void; + function setFloat64( byteOffset : Int, value : Float, ?littleEndian : Bool ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DedicatedWorkerContext.hx b/std/js/html/DedicatedWorkerContext.hx deleted file mode 100644 index 52363b092ec20de92182d672aef00b3ada0a5225..0000000000000000000000000000000000000000 --- a/std/js/html/DedicatedWorkerContext.hx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C)2005-2013 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. - */ - -// This file is generated, do not edit! -package js.html; - -@:native("DedicatedWorkerContext") -extern class DedicatedWorkerContext extends WorkerContext -{ - var onmessage : EventListener; - - function postMessage( message : Dynamic, ?messagePorts : Array ) : Void; - -} diff --git a/std/js/html/DedicatedWorkerGlobalScope.hx b/std/js/html/DedicatedWorkerGlobalScope.hx new file mode 100644 index 0000000000000000000000000000000000000000..78494ff4266ea4db53e1e6f6f1434a6c1129bd70 --- /dev/null +++ b/std/js/html/DedicatedWorkerGlobalScope.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DedicatedWorkerGlobalScope.webidl line 17:0. Do not edit! + +package js.html; + +@:native("DedicatedWorkerGlobalScope") +extern class DedicatedWorkerGlobalScope extends WorkerGlobalScope +{ + var onmessage : haxe.Constraints.Function; + + /** @throws DOMError */ + function postMessage( message : Dynamic, ?transfer : Array ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DesktopNotification.hx b/std/js/html/DesktopNotification.hx new file mode 100644 index 0000000000000000000000000000000000000000..1acdfc3e0d8c150c007de6393214a9d5df4486e9 --- /dev/null +++ b/std/js/html/DesktopNotification.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DesktopNotification.webidl line 18:0. Do not edit! + +package js.html; + +@:native("DesktopNotification") +extern class DesktopNotification extends EventTarget +{ + var onclick : haxe.Constraints.Function; + var onclose : haxe.Constraints.Function; + + /** @throws DOMError */ + function show() : Void; +} \ No newline at end of file diff --git a/std/js/html/DesktopNotificationCenter.hx b/std/js/html/DesktopNotificationCenter.hx new file mode 100644 index 0000000000000000000000000000000000000000..561b5792b9d5752b0bd510b90a8969af39cacdc7 --- /dev/null +++ b/std/js/html/DesktopNotificationCenter.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DesktopNotification.webidl line 10:0. Do not edit! + +package js.html; + +@:native("DesktopNotificationCenter") +extern class DesktopNotificationCenter +{ + function createNotification( title : String, description : String, ?iconURL : String = "" ) : DesktopNotification; +} \ No newline at end of file diff --git a/std/js/html/DetailsElement.hx b/std/js/html/DetailsElement.hx deleted file mode 100644 index 540acd469ac247299524c3742f77b5a0f818c20a..0000000000000000000000000000000000000000 --- a/std/js/html/DetailsElement.hx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C)2005-2013 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. - */ - -// This file is generated, do not edit! -package js.html; - -/** The HTML details element (<details>) is used as a disclosure widget from which the user the retrieve additional information.

-Documentation for this class was provided by MDN. */ -@:native("HTMLDetailsElement") -extern class DetailsElement extends Element -{ - /** This Boolean attribute indicates whether the details will be shown to the user on page load. If omitted the details will be hidden. */ - var open : Bool; - -} diff --git a/std/js/html/DeviceAcceleration.hx b/std/js/html/DeviceAcceleration.hx index 30e9fa86453d3d122adf9cd648883ff55c7d6ac0..b98c70a83946138ab117ee0b9b0df3a3e65d7d06 100644 --- a/std/js/html/DeviceAcceleration.hx +++ b/std/js/html/DeviceAcceleration.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DeviceMotionEvent.webidl line 8:0. Do not edit! + package js.html; @:native("DeviceAcceleration") extern class DeviceAcceleration { var x(default,null) : Float; - var y(default,null) : Float; - var z(default,null) : Float; - -} + +} \ No newline at end of file diff --git a/std/js/html/DeviceAccelerationInit.hx b/std/js/html/DeviceAccelerationInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..13737325ea358122d6e641a2da3c964cb0802a78 --- /dev/null +++ b/std/js/html/DeviceAccelerationInit.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DeviceMotionEvent.webidl line 29:0. Do not edit! + +package js.html; + +typedef DeviceAccelerationInit = +{ + @:optional var x : Float; + @:optional var y : Float; + @:optional var z : Float; +} \ No newline at end of file diff --git a/std/js/html/DeviceMotionEvent.hx b/std/js/html/DeviceMotionEvent.hx index c5aab505514475a0ddbb97315815878f699b84ab..1074f70f121cd47f3851dc27a066fc811062a677 100644 --- a/std/js/html/DeviceMotionEvent.hx +++ b/std/js/html/DeviceMotionEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,26 +20,20 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DeviceMotionEvent.webidl line 22:0. Do not edit! + package js.html; -/** A DeviceMotionEvent object describes an event that indicates the amount of physical motion of the device that has occurred, and is fired at a set interval (rather than in response to motion). It provides information about the rate of rotation, as well as acceleration along all three axes.

-Documentation for this class was provided by MDN. */ @:native("DeviceMotionEvent") extern class DeviceMotionEvent extends Event { - /** The acceleration of the device. This value has taken into account the effect of gravity and removed it from the figures. This value may not exist if the hardware doesn't know how to remove gravity from the acceleration data. Read only. */ var acceleration(default,null) : DeviceAcceleration; - - /** The acceleration of the device. This value includes the effect of gravity, and may be the only value available on devices that don't have a gyroscope to allow them to properly remove gravity from the data. Read only. */ var accelerationIncludingGravity(default,null) : DeviceAcceleration; - - /** The interval, in milliseconds, at which the DeviceMotionEvent is fired. The next event will be fired in approximately this amount of time. */ - var interval(default,null) : Float; - - /** The rates of rotation of the device about all three axes. Read only. */ var rotationRate(default,null) : DeviceRotationRate; - - function initDeviceMotionEvent( type : String, bubbles : Bool, cancelable : Bool, acceleration : DeviceAcceleration, accelerationIncludingGravity : DeviceAcceleration, rotationRate : DeviceRotationRate, interval : Float ) : Void; - -} + var interval(default,null) : Float; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : DeviceMotionEventInit ) : Void; + /** @throws DOMError */ + function initDeviceMotionEvent( type : String, canBubble : Bool, cancelable : Bool, acceleration : DeviceAccelerationInit, accelerationIncludingGravity : DeviceAccelerationInit, rotationRate : DeviceRotationRateInit, interval : Float ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DeviceMotionEventInit.hx b/std/js/html/DeviceMotionEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..2e3dae2326a134567a130edc088b11ee5f763927 --- /dev/null +++ b/std/js/html/DeviceMotionEventInit.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DeviceMotionEvent.webidl line 41:0. Do not edit! + +package js.html; + +typedef DeviceMotionEventInit = +{ + > EventInit, + @:optional var acceleration : DeviceAccelerationInit; + @:optional var accelerationIncludingGravity : DeviceAccelerationInit; + @:optional var interval : Float; + @:optional var rotationRate : DeviceRotationRateInit; +} \ No newline at end of file diff --git a/std/js/html/DeviceOrientationEvent.hx b/std/js/html/DeviceOrientationEvent.hx index 850b1d1870727d57d8dac3b642774be02174ff3e..3b3d6ea7cda9d4b756fd88884882fe1d865b7ff1 100644 --- a/std/js/html/DeviceOrientationEvent.hx +++ b/std/js/html/DeviceOrientationEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,28 +20,20 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DeviceOrientationEvent.webidl line 8:0. Do not edit! + package js.html; -/** A DeviceOrientationEvent object describes an event that provides information about the current orientation of the device as compared to the Earth coordinate frame. See Orientation and motion data explained for details.

-Documentation for this class was provided by MDN. */ @:native("DeviceOrientationEvent") extern class DeviceOrientationEvent extends Event { - /** This attribute's value is true if the orientation is provided as a difference between the device coordinate frame and the Earth coordinate frame; if the device can't detect the Earth coordinate frame, this value is false. Read only. */ - var absolute(default,null) : Bool; - - /** The current orientation of the device around the Z axis; that is, how far the device is rotated around a line perpendicular to the device. Read only. */ var alpha(default,null) : Float; - - /** The current orientation of the device around the X axis; that is, how far the device is tipped forward or backward. Read only. */ var beta(default,null) : Float; - - /**
The current orientation of the device around the Y axis; that is, how far the device is turned left or right. Read only.
-
-
Note: If the browser is not able to provide notification information, all values are 0.
*/ var gamma(default,null) : Float; - - function initDeviceOrientationEvent( type : String, bubbles : Bool, cancelable : Bool, alpha : Float, beta : Float, gamma : Float, absolute : Bool ) : Void; - -} + var absolute(default,null) : Bool; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : DeviceOrientationEventInit ) : Void; + /** @throws DOMError */ + function initDeviceOrientationEvent( type : String, canBubble : Bool, cancelable : Bool, alpha : Float, beta : Float, gamma : Float, absolute : Bool ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DeviceOrientationEventInit.hx b/std/js/html/DeviceOrientationEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..0bbec8a4ae6a44dc69436c9a7f250a63af6b1ad0 --- /dev/null +++ b/std/js/html/DeviceOrientationEventInit.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DeviceOrientationEvent.webidl line 26:0. Do not edit! + +package js.html; + +typedef DeviceOrientationEventInit = +{ + > EventInit, + @:optional var absolute : Bool; + @:optional var alpha : Float; + @:optional var beta : Float; + @:optional var gamma : Float; +} \ No newline at end of file diff --git a/std/js/html/DeviceRotationRate.hx b/std/js/html/DeviceRotationRate.hx index 2728267c4e54983e24c98e62ef125fa8e0dc255c..5fd59468de68ce1d66dfafda92fc07c012011f72 100644 --- a/std/js/html/DeviceRotationRate.hx +++ b/std/js/html/DeviceRotationRate.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DeviceMotionEvent.webidl line 15:0. Do not edit! + package js.html; @:native("DeviceRotationRate") extern class DeviceRotationRate { var alpha(default,null) : Float; - var beta(default,null) : Float; - var gamma(default,null) : Float; - -} + +} \ No newline at end of file diff --git a/std/js/html/DeviceRotationRateInit.hx b/std/js/html/DeviceRotationRateInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..722437eeaf2da4d41f9bdbad4d7175d05dd84073 --- /dev/null +++ b/std/js/html/DeviceRotationRateInit.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DeviceMotionEvent.webidl line 35:0. Do not edit! + +package js.html; + +typedef DeviceRotationRateInit = +{ + @:optional var alpha : Float; + @:optional var beta : Float; + @:optional var gamma : Float; +} \ No newline at end of file diff --git a/std/js/html/DirectionSetting.hx b/std/js/html/DirectionSetting.hx new file mode 100644 index 0000000000000000000000000000000000000000..0f8a79126f3201acfeeee355e68c4914936d7699 --- /dev/null +++ b/std/js/html/DirectionSetting.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/VTTCue.webidl line 20:0. Do not edit! + +package js.html; + +@:enum abstract DirectionSetting(String) +{ + var NONE = ""; + var RL = "rl"; + var LR = "lr"; +} \ No newline at end of file diff --git a/std/js/html/Directory.hx b/std/js/html/Directory.hx new file mode 100644 index 0000000000000000000000000000000000000000..e7273ec730515031c26751be351d5514ed2f5687 --- /dev/null +++ b/std/js/html/Directory.hx @@ -0,0 +1,37 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Directory.webidl line 16:0. Do not edit! + +package js.html; + +@:native("Directory") +extern class Directory +{ + var name(default,null) : String; + + function createFile( path : String, ?options : CreateFileOptions ) : Promise; + function createDirectory( path : String ) : Promise; + function get( path : String ) : Promise>; + function remove( path : haxe.extern.EitherType> ) : Promise; + function removeDeep( path : haxe.extern.EitherType> ) : Promise; +} \ No newline at end of file diff --git a/std/js/html/DirectoryElement.hx b/std/js/html/DirectoryElement.hx index 05898998988b18b014ee6e6da1d478b30492b203..9b3c2f1ba7583b8ebfbec39e84ccf03ca9b997c0 100644 --- a/std/js/html/DirectoryElement.hx +++ b/std/js/html/DirectoryElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLDirectoryElement.webidl line 15:0. Do not edit! + package js.html; -/** Obsolete

-Documentation for this class was provided by MDN. */ @:native("HTMLDirectoryElement") extern class DirectoryElement extends Element { - /** This Boolean attribute hints that the list should be rendered in a compact style. The interpretation of this attribute depends on the user agent and it doesn't work in all browsers.
Usage note: Do not use this attribute, as it has been deprecated: the <dir> - element should be styled using CSS. To give a similar effect than the compact attribute, the CSS property line-height can be used with a value of 80%.
*/ var compact : Bool; - -} + +} \ No newline at end of file diff --git a/std/js/html/DivElement.hx b/std/js/html/DivElement.hx index 5b247d7926796ae8b3e03b078c17f31915cb06a9..f83befc12abcf0d0d6835a2f69d6b663b0a37e76 100644 --- a/std/js/html/DivElement.hx +++ b/std/js/html/DivElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,17 +20,13 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLDivElement.webidl line 14:0. Do not edit! + package js.html; -/** DOM div (document division) objects expose the HTMLDivElement (or -HTML 4 HTMLDivElement) interface, which provides special properties (beyond the regular element object interface they also have available to them by inheritance) for manipulating div elements. In -HTML5, this interface inherits from HTMLElement, but defines no additional members.

-Documentation for this class was provided by MDN. */ @:native("HTMLDivElement") extern class DivElement extends Element { - /** Enumerated attribute indicating alignment of the element's contents with respect to the surrounding context. */ var align : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/Document.hx b/std/js/html/Document.hx index a0801ec53325e19d2d3f3fbd677a69b7eabb4c35..2d8af38253caf1d6026a05a61ae8385b6287e516 100644 --- a/std/js/html/Document.hx +++ b/std/js/html/Document.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,512 +20,189 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Document.webidl line 18:0. Do not edit! + package js.html; -/**

Each web page loaded in the browser has its own document object. This object serves as an entry point to the web page's content (the DOM tree, including elements such as <body> - and <table> -) and provides functionality global to the document (such as obtaining the page's URL and creating new elements in the document).

-

A document object can be obtained from various APIs:

- -

Depending on the kind of the document (e.g. HTML or XML) different APIs may be available on the document object. This theoretical availability of APIs is usually described in terms of implementing interfaces defined in the relevant W3C DOM specifications:

-
  • All document objects implement the DOM Core Document and Node interfaces, meaning that the "core" properties and methods are available for all kinds of documents.
  • In addition to the generalized DOM Core document interface, HTML documents also implement the HTMLDocument interface, which is a more specialized interface for dealing with HTML documents (e.g., document.cookie, document.alinkColor).
  • XUL documents (available to Mozilla add-on and application developers) implement their own additions to the core Document functionality.
  • -
-

Methods or properties listed here that are part of a more specialized interface have an asterisk (*) next to them and have additional information in the  Availability column.

-

Note that some APIs listed below are not available in all browsers for various reasons:

-
  • Obsolete: on its way of being removed from supporting browsers.
  • Non-standard: either an experimental feature not (yet?) agreed upon by all vendors, or a feature targeted specifically at the code running in a specific browser (e.g. Mozilla has a few DOM APIs created for its add-ons and application development).
  • Part of a completed or an emerging standard, but not (yet?) implemented in all browsers or implemented in the newest versions of the browsers.
  • -
-

Detailed browser compatibility tables are located at the pages describing each property or method.



-Documentation for this class was provided by MDN. */ @:native("Document") extern class Document extends Node { - /** Returns a string containing the URL of the current document. */ + var implementation(default,null) : DOMImplementation; var URL(default,null) : String; - - /** Returns the currently focused element */ - var activeElement(default,null) : Element; - - /** Returns or sets the color of active links in the document body. */ - var alinkColor : String; - - var all : HTMLAllCollection; - - /** Returns a list of all of the anchors in the document. */ - var anchors(default,null) : HTMLCollection; - - /** Returns an ordered list of the applets within a document. */ - var applets(default,null) : HTMLCollection; - - /** Gets/sets the background color of the current document. */ - var bgColor : String; - - /** Returns the BODY node of the current document. Setter throws DOMException. */ - var body : Element; - - /** Returns the character set being used by the document. */ - var characterSet(default,null) : String; - - var charset : String; - - /** Indicates whether the document is rendered in Quirks or Strict mode. */ + var documentURI(default,null) : String; var compatMode(default,null) : String; - - /** Returns a semicolon-separated list of the cookies for that document or sets a single cookie. Getter throws DOMException. Setter throws DOMException. */ - var cookie : String; - - var currentFullScreenElement(default,null) : Element; - - var defaultCharset(default,null) : String; - - /** Returns a reference to the window object. */ - var defaultView(default,null) : DOMWindow; - - /** Gets/sets WYSYWIG editing capability of Midas. It can only be used for HTML documents. */ - var designMode : String; - - /** Gets/sets directionality (rtl/ltr) of the document */ - var dir : String; - - /** Returns the Document Type Definition (DTD) of the current document. */ + var characterSet(default,null) : String; + var contentType(default,null) : String; var doctype(default,null) : DocumentType; - - /** Returns the Element that is a direct child of document. For HTML documents, this is normally the HTML element. */ var documentElement(default,null) : Element; - - /** Returns the document location. */ - var documentURI(default,null) : String; - - /** Returns the domain of the current document. Setter throws DOMException. */ - var domain : String; - - /** Returns a list of the embedded OBJECTS within the current document. */ - var embeds(default,null) : HTMLCollection; - - /** Gets/sets the foreground color, or text color, of the current document. */ - var fgColor : String; - - /** Returns a list of the FORM elements within the current document. */ - var forms(default,null) : HTMLCollection; - - var fullScreenKeyboardInputAllowed(default,null) : Bool; - - var fullscreenElement(default,null) : Element; - - var fullscreenEnabled(default,null) : Bool; - - /** Returns the HEAD node of the current document. */ - var head(default,null) : HeadElement; - - /** Gets/sets the height of the current document. */ - var height(default,null) : Int; - - var hidden(default,null) : Bool; - - /** Returns a list of the images in the current document. */ - var images(default,null) : HTMLCollection; - - /** Returns the DOM implementation associated with the current document. */ - var implementation(default,null) : DOMImplementation; - - /** Returns the encoding used when the document was parsed. */ var inputEncoding(default,null) : String; - - var isFullScreen(default,null) : Bool; - - /** Returns the date on which the document was last modified. */ + var fullscreenEnabled(default,null) : Bool; + var fullscreenElement(default,null) : Element; + var onfullscreenchange : haxe.Constraints.Function; + var onfullscreenerror : haxe.Constraints.Function; + var location(default,null) : Location; + var referrer(default,null) : String; var lastModified(default,null) : String; - - /** Gets/sets the color of hyperlinks in the document. */ - var linkColor : String; - - /** Returns a list of all the hyperlinks in the document. */ - var links(default,null) : HTMLCollection; - - /** Returns the URI of the current document. */ - var location : Location; - - var onabort : EventListener; - - var onbeforecopy : EventListener; - - var onbeforecut : EventListener; - - var onbeforepaste : EventListener; - - var onblur : EventListener; - - var onchange : EventListener; - - var onclick : EventListener; - - var oncontextmenu : EventListener; - - var oncopy : EventListener; - - var oncut : EventListener; - - var ondblclick : EventListener; - - var ondrag : EventListener; - - var ondragend : EventListener; - - var ondragenter : EventListener; - - var ondragleave : EventListener; - - var ondragover : EventListener; - - var ondragstart : EventListener; - - var ondrop : EventListener; - - var onerror : EventListener; - - var onfocus : EventListener; - - var onfullscreenchange : EventListener; - - var onfullscreenerror : EventListener; - - var oninput : EventListener; - - var oninvalid : EventListener; - - var onkeydown : EventListener; - - var onkeypress : EventListener; - - var onkeyup : EventListener; - - var onload : EventListener; - - var onmousedown : EventListener; - - var onmousemove : EventListener; - - var onmouseout : EventListener; - - var onmouseover : EventListener; - - var onmouseup : EventListener; - - var onmousewheel : EventListener; - - var onpaste : EventListener; - - var onpointerlockchange : EventListener; - - var onpointerlockerror : EventListener; - - /**
Returns the event handling code for the readystatechange event.
-
-

-

Gecko 9.0 note
(Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) -
-

Starting in Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) -, you can now use the syntax if ("onabort" in document) to determine whether or not a given event handler property exists. This is because event handler interfaces have been updated to be proper web IDL interfaces. See DOM event handlers for details.

-
*/ - var onreadystatechange : EventListener; - - var onreset : EventListener; - - var onscroll : EventListener; - - var onsearch : EventListener; - - var onselect : EventListener; - - var onselectionchange : EventListener; - - var onselectstart : EventListener; - - var onsubmit : EventListener; - - var ontouchcancel : EventListener; - - var ontouchend : EventListener; - - var ontouchmove : EventListener; - - var ontouchstart : EventListener; - - /** Returns a list of the available plugins. */ - var plugins(default,null) : HTMLCollection; - - var pointerLockElement(default,null) : Element; - - var preferredStylesheetSet(default,null) : String; - - /** Returns loading status of the document */ var readyState(default,null) : String; - - /** Returns the URI of the page that linked to this page. */ - var referrer(default,null) : String; - - /** Returns all the <script> - elements on the document. */ - var scripts(default,null) : HTMLCollection; - - var selectedStylesheetSet : String; - - /** Returns a list of the stylesheet objects on the current document. */ - var styleSheets(default,null) : StyleSheetList; - - /** Returns the title of the current document. */ var title : String; - - var visibilityState(default,null) : String; - - /** Gets/sets the color of visited hyperlinks. */ - var vlinkColor : String; - - /** Returns the width of the current document. */ - var width(default,null) : Int; - - /** Returns the encoding as determined by the XML declaration.
Firefox 10 and later don't implement it anymore.
*/ - var xmlEncoding(default,null) : String; - - /** Returns true if the XML declaration specifies the document is standalone (e.g., An external part of the DTD affects the document's content), else false. Setter throws DOMException. */ - var xmlStandalone : Bool; - - /** Returns the version number as specified in the XML declaration or "1.0" if the declaration is absent. Setter throws DOMException. */ - var xmlVersion : String; - - function adoptNode( source : Node ) : Node; - - function cancelFullScreen() : Void; - - function captureEvents() : Void; - - function caretRangeFromPoint( x : Int, y : Int ) : Range; - - function clear() : Void; - - function close() : Void; - - function createAttribute( name : String ) : Attr; - - function createAttributeNS( ?namespaceURI : String, ?qualifiedName : String ) : Attr; - - function createCDATASection( data : String ) : CDATASection; - - function createComment( data : String ) : Comment; - + var dir : String; + var defaultView(default,null) : Window; + var activeElement(default,null) : Element; + var onreadystatechange : haxe.Constraints.Function; + var onwheel : haxe.Constraints.Function; + var oncopy : haxe.Constraints.Function; + var oncut : haxe.Constraints.Function; + var onpaste : haxe.Constraints.Function; + var onbeforescriptexecute : haxe.Constraints.Function; + var onafterscriptexecute : haxe.Constraints.Function; + var currentScript(default,null) : Element; + var pointerLockElement(default,null) : Element; + var hidden(default,null) : Bool; + var visibilityState(default,null) : VisibilityState; + var styleSheets(default,null) : StyleSheetList; + var selectedStyleSheetSet : String; + var lastStyleSheetSet(default,null) : String; + var preferredStyleSheetSet(default,null) : String; + var styleSheetSets(default,null) : DOMStringList; + var timeline(default,null) : AnimationTimeline; + var fonts(default,null) : FontFaceSet; + var onabort : haxe.Constraints.Function; + var onblur : haxe.Constraints.Function; + var onfocus : haxe.Constraints.Function; + var oncanplay : haxe.Constraints.Function; + var oncanplaythrough : haxe.Constraints.Function; + var onchange : haxe.Constraints.Function; + var onclick : haxe.Constraints.Function; + var oncontextmenu : haxe.Constraints.Function; + var ondblclick : haxe.Constraints.Function; + var ondrag : haxe.Constraints.Function; + var ondragend : haxe.Constraints.Function; + var ondragenter : haxe.Constraints.Function; + var ondragleave : haxe.Constraints.Function; + var ondragover : haxe.Constraints.Function; + var ondragstart : haxe.Constraints.Function; + var ondrop : haxe.Constraints.Function; + var ondurationchange : haxe.Constraints.Function; + var onemptied : haxe.Constraints.Function; + var onended : haxe.Constraints.Function; + var oninput : haxe.Constraints.Function; + var oninvalid : haxe.Constraints.Function; + var onkeydown : haxe.Constraints.Function; + var onkeypress : haxe.Constraints.Function; + var onkeyup : haxe.Constraints.Function; + var onload : haxe.Constraints.Function; + var onloadeddata : haxe.Constraints.Function; + var onloadedmetadata : haxe.Constraints.Function; + var onloadstart : haxe.Constraints.Function; + var onmousedown : haxe.Constraints.Function; + var onmouseenter : haxe.Constraints.Function; + var onmouseleave : haxe.Constraints.Function; + var onmousemove : haxe.Constraints.Function; + var onmouseout : haxe.Constraints.Function; + var onmouseover : haxe.Constraints.Function; + var onmouseup : haxe.Constraints.Function; + var onpause : haxe.Constraints.Function; + var onplay : haxe.Constraints.Function; + var onplaying : haxe.Constraints.Function; + var onprogress : haxe.Constraints.Function; + var onratechange : haxe.Constraints.Function; + var onreset : haxe.Constraints.Function; + var onscroll : haxe.Constraints.Function; + var onseeked : haxe.Constraints.Function; + var onseeking : haxe.Constraints.Function; + var onselect : haxe.Constraints.Function; + var onshow : haxe.Constraints.Function; + var onstalled : haxe.Constraints.Function; + var onsubmit : haxe.Constraints.Function; + var onsuspend : haxe.Constraints.Function; + var ontimeupdate : haxe.Constraints.Function; + var onvolumechange : haxe.Constraints.Function; + var onwaiting : haxe.Constraints.Function; + var onpointercancel : haxe.Constraints.Function; + var onpointerdown : haxe.Constraints.Function; + var onpointerup : haxe.Constraints.Function; + var onpointermove : haxe.Constraints.Function; + var onpointerout : haxe.Constraints.Function; + var onpointerover : haxe.Constraints.Function; + var onpointerenter : haxe.Constraints.Function; + var onpointerleave : haxe.Constraints.Function; + var ongotpointercapture : haxe.Constraints.Function; + var onlostpointercapture : haxe.Constraints.Function; + var onpointerlockchange : haxe.Constraints.Function; + var onpointerlockerror : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + var children(default,null) : HTMLCollection; + var firstElementChild(default,null) : Element; + var lastElementChild(default,null) : Element; + var childElementCount(default,null) : Int; + var ontouchstart : haxe.Constraints.Function; + var ontouchend : haxe.Constraints.Function; + var ontouchmove : haxe.Constraints.Function; + var ontouchcancel : haxe.Constraints.Function; + + /** @throws DOMError */ + function new() : Void; + function getElementsByTagName( localName : String ) : HTMLCollection; + /** @throws DOMError */ + function getElementsByTagNameNS( namespace_ : String, localName : String ) : HTMLCollection; + function getElementsByClassName( classNames : String ) : HTMLCollection; + function getElementById( elementId : String ) : Element; + /** @throws DOMError */ + @:overload( function( localName : String ) : Element {} ) + function createElement( localName : String, typeExtension : String ) : Element; + /** @throws DOMError */ + @:overload( function( namespace_ : String, qualifiedName : String ) : Element {} ) + function createElementNS( namespace_ : String, qualifiedName : String, typeExtension : String ) : Element; function createDocumentFragment() : DocumentFragment; - - function createElement( ?tagName : String ) : Element; - - function createElementNS( ?namespaceURI : String, ?qualifiedName : String ) : Element; - - function createEntityReference( name : String ) : EntityReference; - - function createEvent( eventType : String ) : Event; - - function createExpression( expression : String, resolver : XPathNSResolver ) : XPathExpression; - - function createNSResolver( nodeResolver : Node ) : XPathNSResolver; - - function createNodeIterator( root : Node, whatToShow : Int, filter : NodeFilter, expandEntityReferences : Bool ) : NodeIterator; - + function createTextNode( data : String ) : Text; + function createComment( data : String ) : Comment; + /** @throws DOMError */ function createProcessingInstruction( target : String, data : String ) : ProcessingInstruction; - + /** @throws DOMError */ + function importNode( node : Node, ?deep : Bool = false ) : Node; + /** @throws DOMError */ + function adoptNode( node : Node ) : Node; + /** @throws DOMError */ + function createEvent( interface_ : String ) : Event; + /** @throws DOMError */ function createRange() : Range; - - function createTextNode( data : String ) : Text; - - function createTouch( window : DOMWindow, target : EventTarget, identifier : Int, pageX : Int, pageY : Int, screenX : Int, screenY : Int, radiusX : Int, radiusY : Int, rotationAngle : Float, force : Float ) : Touch; - - function createTouchList() : TouchList; - - function createTreeWalker( root : Node, whatToShow : Int, filter : NodeFilter, expandEntityReferences : Bool ) : TreeWalker; - - function elementFromPoint( x : Int, y : Int ) : Element; - - function evaluate( expression : String, contextNode : Node, resolver : XPathNSResolver, type : Int, inResult : XPathResult ) : XPathResult; - - function execCommand( command : String, userInterface : Bool, ?value : String ) : Bool; - + /** @throws DOMError */ + function createNodeIterator( root : Node, ?whatToShow : Int = cast 4294967295, ?filter : NodeFilter ) : NodeIterator; + /** @throws DOMError */ + function createTreeWalker( root : Node, ?whatToShow : Int = cast 4294967295, ?filter : NodeFilter ) : TreeWalker; + /** @throws DOMError */ + function createCDATASection( data : String ) : CDATASection; + /** @throws DOMError */ + function createAttribute( name : String ) : Attr; + /** @throws DOMError */ + function createAttributeNS( namespace_ : String, name : String ) : Attr; function exitFullscreen() : Void; - - function exitPointerLock() : Void; - - function getCSSCanvasContext( contextId : String, name : String, width : Int, height : Int ) : CanvasRenderingContext; - - function getElementById( elementId : String ) : Element; - - function getElementsByClassName( tagname : String ) : NodeList; - - function getElementsByName( elementName : String ) : NodeList; - - function getElementsByTagName( tagname : String ) : NodeList; - - function getElementsByTagNameNS( ?namespaceURI : String, localName : String ) : NodeList; - - function getOverrideStyle( element : Element, pseudoElement : String ) : CSSStyleDeclaration; - - function getSelection() : DOMSelection; - + /** @throws DOMError */ function hasFocus() : Bool; - - function importNode( importedNode : Node, ?deep : Bool ) : Node; - - function open() : Void; - - function queryCommandEnabled( command : String ) : Bool; - - function queryCommandIndeterm( command : String ) : Bool; - - function queryCommandState( command : String ) : Bool; - - function queryCommandSupported( command : String ) : Bool; - - function queryCommandValue( command : String ) : String; - + function releaseCapture() : Void; + function exitPointerLock() : Void; + /** @throws DOMError */ + function registerElement( name : String, ?options : ElementRegistrationOptions ) : Dynamic; + function enableStyleSheetsForSet( name : String ) : Void; + function elementFromPoint( x : Float, y : Float ) : Element; + function caretPositionFromPoint( x : Float, y : Float ) : CaretPosition; + /** @throws DOMError */ function querySelector( selectors : String ) : Element; - + /** @throws DOMError */ function querySelectorAll( selectors : String ) : NodeList; - - function releaseEvents() : Void; - - function write( text : String ) : Void; - - function writeln( text : String ) : Void; - - /** A typed shortcut for createElement("td"). */ - public inline function createTableCellElement() : TableCellElement { return cast createElement("td"); } - /** A typed shortcut for createElement("hr"). */ - public inline function createHRElement() : HRElement { return cast createElement("hr"); } - /** A typed shortcut for createElement("marquee"). */ - public inline function createMarqueeElement() : MarqueeElement { return cast createElement("marquee"); } - /** A typed shortcut for createElement("basefont"). */ - public inline function createBaseFontElement() : BaseFontElement { return cast createElement("basefont"); } - /** A typed shortcut for createElement("select"). */ - public inline function createSelectElement() : SelectElement { return cast createElement("select"); } - /** A typed shortcut for createElement("map"). */ - public inline function createMapElement() : MapElement { return cast createElement("map"); } - /** A typed shortcut for createElement("form"). */ - public inline function createFormElement() : FormElement { return cast createElement("form"); } - /** A typed shortcut for createElement("option"). */ - public inline function createOptionElement() : OptionElement { return cast createElement("option"); } - /** A typed shortcut for createElement("label"). */ - public inline function createLabelElement() : LabelElement { return cast createElement("label"); } - /** A typed shortcut for createElement("meta"). */ - public inline function createMetaElement() : MetaElement { return cast createElement("meta"); } - /** A typed shortcut for createElement("img"). */ - public inline function createImageElement() : ImageElement { return cast createElement("img"); } - /** A typed shortcut for createElement("dl"). */ - public inline function createDListElement() : DListElement { return cast createElement("dl"); } - /** A typed shortcut for createElement("frame"). */ - public inline function createFrameElement() : FrameElement { return cast createElement("frame"); } - /** A typed shortcut for createElement("mod"). */ - public inline function createModElement() : ModElement { return cast createElement("mod"); } - /** A typed shortcut for createElement("ul"). */ - public inline function createUListElement() : UListElement { return cast createElement("ul"); } - /** A typed shortcut for createElement("output"). */ - public inline function createOutputElement() : OutputElement { return cast createElement("output"); } - /** A typed shortcut for createElement("ol"). */ - public inline function createOListElement() : OListElement { return cast createElement("ol"); } - /** A typed shortcut for createElement("shadow"). */ - public inline function createShadowElement() : ShadowElement { return cast createElement("shadow"); } - /** A typed shortcut for createElement("li"). */ - public inline function createLIElement() : LIElement { return cast createElement("li"); } - /** A typed shortcut for createElement("datalist"). */ - public inline function createDataListElement() : DataListElement { return cast createElement("datalist"); } - /** A typed shortcut for createElement("param"). */ - public inline function createParamElement() : ParamElement { return cast createElement("param"); } - /** A typed shortcut for createElement("font"). */ - public inline function createFontElement() : FontElement { return cast createElement("font"); } - /** A typed shortcut for createElement("track"). */ - public inline function createTrackElement() : TrackElement { return cast createElement("track"); } - /** A typed shortcut for createElement("applet"). */ - public inline function createAppletElement() : AppletElement { return cast createElement("applet"); } - /** A typed shortcut for createElement("area"). */ - public inline function createAreaElement() : AreaElement { return cast createElement("area"); } - /** A typed shortcut for createElement("link"). */ - public inline function createLinkElement() : LinkElement { return cast createElement("link"); } - /** A typed shortcut for createElement("div"). */ - public inline function createDivElement() : DivElement { return cast createElement("div"); } - /** A typed shortcut for createElement("title"). */ - public inline function createTitleElement() : TitleElement { return cast createElement("title"); } - /** A typed shortcut for createElement("style"). */ - public inline function createStyleElement() : StyleElement { return cast createElement("style"); } - /** A typed shortcut for createElement("progress"). */ - public inline function createProgressElement() : ProgressElement { return cast createElement("progress"); } - /** A typed shortcut for createElement("button"). */ - public inline function createButtonElement() : ButtonElement { return cast createElement("button"); } - /** A typed shortcut for createElement("fieldset"). */ - public inline function createFieldSetElement() : FieldSetElement { return cast createElement("fieldset"); } - /** A typed shortcut for createElement("a"). */ - public inline function createAnchorElement() : AnchorElement { return cast createElement("a"); } - /** A typed shortcut for createElement("iframe"). */ - public inline function createIFrameElement() : IFrameElement { return cast createElement("iframe"); } - /** A typed shortcut for createElement("span"). */ - public inline function createSpanElement() : SpanElement { return cast createElement("span"); } - /** A typed shortcut for createElement("details"). */ - public inline function createDetailsElement() : DetailsElement { return cast createElement("details"); } - /** A typed shortcut for createElement("body"). */ - public inline function createBodyElement() : BodyElement { return cast createElement("body"); } - /** A typed shortcut for createElement("input"). */ - public inline function createInputElement() : InputElement { return cast createElement("input"); } - /** A typed shortcut for createElement("embed"). */ - public inline function createEmbedElement() : EmbedElement { return cast createElement("embed"); } - /** A typed shortcut for createElement("meter"). */ - public inline function createMeterElement() : MeterElement { return cast createElement("meter"); } - /** A typed shortcut for createElement("pre"). */ - public inline function createPreElement() : PreElement { return cast createElement("pre"); } - /** A typed shortcut for createElement("thead"). */ - public inline function createTableSectionElement() : TableSectionElement { return cast createElement("thead"); } - /** A typed shortcut for createElement("head"). */ - public inline function createHeadElement() : HeadElement { return cast createElement("head"); } - /** A typed shortcut for createElement("base"). */ - public inline function createBaseElement() : BaseElement { return cast createElement("base"); } - /** A typed shortcut for createElement("optgroup"). */ - public inline function createOptGroupElement() : OptGroupElement { return cast createElement("optgroup"); } - /** A typed shortcut for createElement("quote"). */ - public inline function createQuoteElement() : QuoteElement { return cast createElement("quote"); } - /** A typed shortcut for createElement("audio"). */ - public inline function createAudioElement() : AudioElement { return cast createElement("audio"); } - /** A typed shortcut for createElement("video"). */ - public inline function createVideoElement() : VideoElement { return cast createElement("video"); } - /** A typed shortcut for createElement("legend"). */ - public inline function createLegendElement() : LegendElement { return cast createElement("legend"); } - /** A typed shortcut for createElement("menu"). */ - public inline function createMenuElement() : MenuElement { return cast createElement("menu"); } - /** A typed shortcut for createElement("frameset"). */ - public inline function createFrameSetElement() : FrameSetElement { return cast createElement("frameset"); } - /** A typed shortcut for createElement("canvas"). */ - public inline function createCanvasElement() : CanvasElement { return cast createElement("canvas"); } - /** A typed shortcut for createElement("keygen"). */ - public inline function createKeygenElement() : KeygenElement { return cast createElement("keygen"); } - /** A typed shortcut for createElement("col"). */ - public inline function createTableColElement() : TableColElement { return cast createElement("col"); } - /** A typed shortcut for createElement("dir"). */ - public inline function createDirectoryElement() : DirectoryElement { return cast createElement("dir"); } - /** A typed shortcut for createElement("table"). */ - public inline function createTableElement() : TableElement { return cast createElement("table"); } - /** A typed shortcut for createElement("tr"). */ - public inline function createTableRowElement() : TableRowElement { return cast createElement("tr"); } - /** A typed shortcut for createElement("script"). */ - public inline function createScriptElement() : ScriptElement { return cast createElement("script"); } - /** A typed shortcut for createElement("source"). */ - public inline function createSourceElement() : SourceElement { return cast createElement("source"); } - /** A typed shortcut for createElement("p"). */ - public inline function createParagraphElement() : ParagraphElement { return cast createElement("p"); } - /** A typed shortcut for createElement("content"). */ - public inline function createContentElement() : ContentElement { return cast createElement("content"); } - /** A typed shortcut for createElement("br"). */ - public inline function createBRElement() : BRElement { return cast createElement("br"); } - /** A typed shortcut for createElement("html"). */ - public inline function createHtmlElement() : HtmlElement { return cast createElement("html"); } - /** A typed shortcut for createElement("textarea"). */ - public inline function createTextAreaElement() : TextAreaElement { return cast createElement("textarea"); } - /** A typed shortcut for createElement("media"). */ - public inline function createMediaElement() : MediaElement { return cast createElement("media"); } - /** A typed shortcut for createElement("object"). */ - public inline function createObjectElement() : ObjectElement { return cast createElement("object"); } - /** A typed shortcut for createElement("caption"). */ - public inline function createTableCaptionElement() : TableCaptionElement { return cast createElement("caption"); } -} + function createTouch( ?view : Window, ?target : EventTarget, ?identifier : Int = 0, ?pageX : Int = 0, ?pageY : Int = 0, ?screenX : Int = 0, ?screenY : Int = 0, ?clientX : Int = 0, ?clientY : Int = 0, ?radiusX : Int = 0, ?radiusY : Int = 0, ?rotationAngle : Float = 0.0, ?force : Float = 0.0 ) : Touch; + @:overload( function( touch : Touch, touches : haxe.extern.Rest ) : TouchList {} ) + @:overload( function() : TouchList {} ) + function createTouchList( touches : Array ) : TouchList; + /** @throws DOMError */ + function convertQuadFromNode( quad : DOMQuad, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMQuad; + /** @throws DOMError */ + function convertRectFromNode( rect : DOMRectReadOnly, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMQuad; + /** @throws DOMError */ + function convertPointFromNode( point : DOMPointInit, from : haxe.extern.EitherType>, ?options : ConvertCoordinateOptions ) : DOMPoint; + /** @throws DOMError */ + function createExpression( expression : String, resolver : XPathNSResolver ) : XPathExpression; + function createNSResolver( nodeResolver : Node ) : Node; + /** @throws DOMError */ + function evaluate( expression : String, contextNode : Node, resolver : XPathNSResolver, type : Int, result : Dynamic ) : XPathResult; +} \ No newline at end of file diff --git a/std/js/html/DocumentFragment.hx b/std/js/html/DocumentFragment.hx index fc4d3fd0c14d86b3be033b86c7985fe8367a7734..82aad0da76c0ec7a942e127da32a64e1116f6b2a 100644 --- a/std/js/html/DocumentFragment.hx +++ b/std/js/html/DocumentFragment.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,19 +20,23 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DocumentFragment.webidl line 15:0. Do not edit! + package js.html; -/**

DocumentFragment has no properties or methods of its own, but inherits from Node.

-

A DocumentFragment is a minimal document object that has no parent. It is used as a light-weight version of document to store well-formed or potentially non-well-formed fragments of XML.

-

See Node for a listing of its properties, constants and methods.

-

Various other methods can take a document fragment as an argument (e.g., any Node interface methods such as appendChild and insertBefore), in which case the children of the fragment are appended or inserted, not the fragment itself.



-Documentation for this class was provided by MDN. */ @:native("DocumentFragment") extern class DocumentFragment extends Node { + var children(default,null) : HTMLCollection; + var firstElementChild(default,null) : Element; + var lastElementChild(default,null) : Element; + var childElementCount(default,null) : Int; + + /** @throws DOMError */ + function new() : Void; + function getElementById( elementId : String ) : Element; + /** @throws DOMError */ function querySelector( selectors : String ) : Element; - + /** @throws DOMError */ function querySelectorAll( selectors : String ) : NodeList; - -} +} \ No newline at end of file diff --git a/std/js/html/DocumentType.hx b/std/js/html/DocumentType.hx index ed9e32571e303124d5673bf45e9a110bcdd093ed..a2757828d0b40993a4777393fea6f8707e3447dc 100644 --- a/std/js/html/DocumentType.hx +++ b/std/js/html/DocumentType.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,27 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DocumentType.webidl line 13:0. Do not edit! + package js.html; -/**

NOTE: This interface is not fully supported in Mozilla at present, including for indicating internalSubset information which Gecko generally does otherwise support.

-

DocumentType inherits Node's properties, methods, and constants as well as the following properties of its own:



-Documentation for this class was provided by MDN. */ @:native("DocumentType") extern class DocumentType extends Node { - var entities(default,null) : NamedNodeMap; - - var internalSubset(default,null) : String; - var name(default,null) : String; - - var notations(default,null) : NamedNodeMap; - var publicId(default,null) : String; - var systemId(default,null) : String; - + var internalSubset(default,null) : String; + function remove() : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/NotificationCenter.hx b/std/js/html/DragEvent.hx similarity index 67% rename from std/js/html/NotificationCenter.hx rename to std/js/html/DragEvent.hx index 0567010404bdcf9d2de7613129b4b10696b69cba..49e177fd88547dcad3a4cae5b32794cd773e77c9 100644 --- a/std/js/html/NotificationCenter.hx +++ b/std/js/html/DragEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DragEvent.webidl line 7:0. Do not edit! + package js.html; -@:native("NotificationCenter") -extern class NotificationCenter +@:native("DragEvent") +extern class DragEvent extends MouseEvent { - function checkPermission() : Int; - - function createHTMLNotification( url : String ) : Notification; - - function createNotification( iconUrl : String, title : String, body : String ) : Notification; - - function requestPermission( callback_ : VoidCallback ) : Void; - -} + var dataTransfer(default,null) : DataTransfer; + + /** @throws DOMError */ + function initDragEvent( type : String, canBubble : Bool, cancelable : Bool, aView : Window, aDetail : Int, aScreenX : Int, aScreenY : Int, aClientX : Int, aClientY : Int, aCtrlKey : Bool, aAltKey : Bool, aShiftKey : Bool, aMetaKey : Bool, aButton : Int, aRelatedTarget : EventTarget, aDataTransfer : DataTransfer ) : Void; +} \ No newline at end of file diff --git a/std/js/html/DummyInterface.hx b/std/js/html/DummyInterface.hx new file mode 100644 index 0000000000000000000000000000000000000000..904790474ebd1ec5b23cafa4bc11cd21a1b5095a --- /dev/null +++ b/std/js/html/DummyInterface.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/DummyBinding.webidl line 10:0. Do not edit! + +package js.html; + +@:native("DummyInterface") +extern class DummyInterface +{ + function lifecycleCallbacks( ?arg : LifecycleCallbacks ) : Void; +} \ No newline at end of file diff --git a/std/js/html/CanvasRenderingContext.hx b/std/js/html/DummyInterfaceWorkers.hx similarity index 84% rename from std/js/html/CanvasRenderingContext.hx rename to std/js/html/DummyInterfaceWorkers.hx index 52a45e53ebd5780ce2a3708a94f59437f76d3bcf..aef05206178c5d4c6eadf9f2541767837680f2a3 100644 --- a/std/js/html/CanvasRenderingContext.hx +++ b/std/js/html/DummyInterfaceWorkers.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/DummyBinding.webidl line 14:0. Do not edit! + package js.html; -@:native("CanvasRenderingContext") -extern class CanvasRenderingContext +@:native("DummyInterfaceWorkers") +extern class DummyInterfaceWorkers { - var canvas(default,null) : CanvasElement; - -} +} \ No newline at end of file diff --git a/std/js/html/Element.hx b/std/js/html/Element.hx index 3b267ba1093a44d4594f67a3807d334f9dd4cde2..910229d8aecb07ce224f886eccaf2f61f1d414a0 100644 --- a/std/js/html/Element.hx +++ b/std/js/html/Element.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,372 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLElement.webidl line 15:0. Do not edit! + package js.html; -/**

This chapter provides a brief reference for the general methods, properties, and events available to most HTML and XML elements in the Gecko DOM.

-

Various W3C specifications apply to elements:

- -

The articles listed here span the above and include links to the appropriate W3C DOM specification.

-

While these interfaces are generally shared by most HTML and XML elements, there are more specialized interfaces for particular objects listed in the DOM HTML Specification. Note, however, that these HTML interfaces are "only for [HTML 4.01] and [XHTML 1.0] documents and are not guaranteed to work with any future version of XHTML." The HTML 5 draft does state it aims for backwards compatibility with these HTML interfaces but says of them that "some features that were formerly deprecated, poorly supported, rarely used or considered unnecessary have been removed." One can avoid the potential conflict by moving entirely to DOM XML attribute methods such as getAttribute().

-

Html -, Head -, Link -, Title -, Meta -, Base -, IsIndex -, Style -, Body -, Form -, Select -, OptGroup -, Option, Input -, TextArea -, Button -, Label -, FieldSet -, Legend -, UList -, OList -, DList -, Directory -, Menu -, LI -, Div -, Paragraph -, Heading -, Quote -, Pre -, BR -, BaseFont -, Font -, HR -, Mod -, Anchor -, Image -, Object -, Param -, Applet -, Map -, Area -, Script -, Table -, TableCaption -, TableCol -, TableSection -, TableRow -, TableCell -, FrameSet -, Frame -, IFrame -



-Documentation for this class was provided by MDN. */ -@:native("Element") -extern class Element extends Node +@:native("HTMLElement") +extern class Element extends DOMElement { - static inline var ALLOW_KEYBOARD_INPUT : Int = 1; - - var accessKey : String; - - /** The number of child nodes that are elements. */ - var childElementCount(default,null) : Int; - - /** A live nsIDOMNodeList - of the current child elements. */ - var children(default,null) : HTMLCollection; - - /** Token list of class attribute */ - var classList(default,null) : DOMTokenList; - - /** Gets/sets the class of the element. */ - var className : String; - - /** The inner height of an element. */ - var clientHeight(default,null) : Int; - - /** The width of the left border of an element. */ - var clientLeft(default,null) : Int; - - /** The width of the top border of an element. */ - var clientTop(default,null) : Int; - - /** The inner width of an element. */ - var clientWidth(default,null) : Int; - - /** Gets/sets whether or not the element is editable. Setter throws DOMException. */ - var contentEditable : String; - - /** Allows access to read and write custom data attributes on the element. */ - var dataset(default,null) : DOMStringMap; - - /** Gets/sets the directionality of the element. */ - var dir : String; - - var draggable : Bool; - - var dropzone : String; - - /** The first direct child element of an element, or null if the element has no child elements. */ - var firstElementChild(default,null) : Element; - - var hidden : Bool; - - /** Gets/sets the id of the element. */ - var id : String; - - /** Gets/sets the markup of the element's content. Setter throws DOMException. */ - var innerHTML : String; - - /** Setter throws DOMException. */ - var innerText : String; - - /** Indicates whether or not the content of the element can be edited. Read only. */ - var isContentEditable(default,null) : Bool; - - /** Gets/sets the language of an element's attributes, text, and element contents. */ - var lang : String; - - /** The last direct child element of an element, or null if the element has no child elements. */ - var lastElementChild(default,null) : Element; - - /** The element immediately following the given one in the tree, or null if there's no sibling node. */ - var nextElementSibling(default,null) : Element; - - /** The height of an element, relative to the layout. */ - var offsetHeight(default,null) : Int; - - /** The distance from this element's left border to its offsetParent's left border. */ - var offsetLeft(default,null) : Int; - - /** The element from which all offset calculations are currently computed. */ - var offsetParent(default,null) : Element; - - /** The distance from this element's top border to its offsetParent's top border. */ - var offsetTop(default,null) : Int; - - /** The width of an element, relative to the layout. */ - var offsetWidth(default,null) : Int; - - var onabort : EventListener; - - var onbeforecopy : EventListener; - - var onbeforecut : EventListener; - - var onbeforepaste : EventListener; - - /** Returns the event handling code for the blur event. */ - var onblur : EventListener; - - /** Returns the event handling code for the change event. */ - var onchange : EventListener; - - /** Returns the event handling code for the click event. */ - var onclick : EventListener; - - /** Returns the event handling code for the contextmenu event. */ - var oncontextmenu : EventListener; - - /** Returns the event handling code for the copy event. */ - var oncopy : EventListener; - - /** Returns the event handling code for the cut event. */ - var oncut : EventListener; - - /** Returns the event handling code for the dblclick event. */ - var ondblclick : EventListener; - - var ondrag : EventListener; - - var ondragend : EventListener; - - var ondragenter : EventListener; - - var ondragleave : EventListener; - - var ondragover : EventListener; - - var ondragstart : EventListener; - - var ondrop : EventListener; - - var onerror : EventListener; - - /** Returns the event handling code for the focus event. */ - var onfocus : EventListener; - - var onfullscreenchange : EventListener; - - var onfullscreenerror : EventListener; - - var oninput : EventListener; - - var oninvalid : EventListener; - - /** Returns the event handling code for the keydown event. */ - var onkeydown : EventListener; - - /** Returns the event handling code for the keypress event. */ - var onkeypress : EventListener; - - /** Returns the event handling code for the keyup event. */ - var onkeyup : EventListener; - - var onload : EventListener; - - /** Returns the event handling code for the mousedown event. */ - var onmousedown : EventListener; - - /** Returns the event handling code for the mousemove event. */ - var onmousemove : EventListener; - - /** Returns the event handling code for the mouseout event. */ - var onmouseout : EventListener; - - /** Returns the event handling code for the mouseover event. */ - var onmouseover : EventListener; - - /** Returns the event handling code for the mouseup event. */ - var onmouseup : EventListener; - - var onmousewheel : EventListener; - - /** Returns the event handling code for the paste event. */ - var onpaste : EventListener; - - var onreset : EventListener; - - /** Returns the event handling code for the scroll event. */ - var onscroll : EventListener; - - var onsearch : EventListener; - - var onselect : EventListener; - - var onselectstart : EventListener; - - var onsubmit : EventListener; - - var ontouchcancel : EventListener; - - var ontouchend : EventListener; - - var ontouchmove : EventListener; - - var ontouchstart : EventListener; - - /** Gets the markup of the element including its content. When used as a setter, replaces the element with nodes parsed from the given string. Setter throws DOMException. */ - var outerHTML : String; - - /** Setter throws DOMException. */ - var outerText : String; - - /** The element immediately preceding the given one in the tree, or null if there is no sibling element. */ - var previousElementSibling(default,null) : Element; - - var pseudo : String; - - /** The scroll view height of an element. */ - var scrollHeight(default,null) : Int; - - /** Gets/sets the left scroll offset of an element. */ - var scrollLeft : Int; - - /** Gets/sets the top scroll offset of an element. */ - var scrollTop : Int; - - /** The scroll view width of an element. */ - var scrollWidth(default,null) : Int; - - /** Controls spell-checking (present on all HTML elements) */ - var spellcheck : Bool; - - /** An object representing the declarations of an element's style attributes. */ - var style(default,null) : CSSStyleDeclaration; - - /** Gets/sets the position of the element in the tabbing order. */ - var tabIndex : Int; - - /** The name of the tag for the given element. */ - var tagName(default,null) : String; - - /** A string that appears in a popup box when mouse is over the element. */ - var title : String; - - var translate : Bool; - - function blur() : Void; - - function click() : Void; - - function focus() : Void; - - function getAttribute( name : String ) : String; - - function getAttributeNS( ?namespaceURI : String, localName : String ) : String; - - function getAttributeNode( name : String ) : Attr; - - function getAttributeNodeNS( ?namespaceURI : String, localName : String ) : Attr; - - function getBoundingClientRect() : ClientRect; - - function getClientRects() : ClientRectList; - - function getElementsByClassName( name : String ) : NodeList; - - function getElementsByTagName( name : String ) : NodeList; - - function getElementsByTagNameNS( ?namespaceURI : String, localName : String ) : NodeList; - - function hasAttribute( name : String ) : Bool; - - function hasAttributeNS( ?namespaceURI : String, localName : String ) : Bool; - - function insertAdjacentElement( where : String, element : Element ) : Element; - - function insertAdjacentHTML( where : String, html : String ) : Void; - - function insertAdjacentText( where : String, text : String ) : Void; - - function matchesSelector( selectors : String ) : Bool; - - function querySelector( selectors : String ) : Element; - - function querySelectorAll( selectors : String ) : NodeList; - - function remove() : Void; - - function removeAttribute( name : String ) : Void; - - function removeAttributeNS( namespaceURI : String, localName : String ) : Void; - - function removeAttributeNode( oldAttr : Attr ) : Attr; - - function requestFullScreen( flags : Int ) : Void; - - function requestFullscreen() : Void; - - function requestPointerLock() : Void; - - function scrollByLines( lines : Int ) : Void; - - function scrollByPages( pages : Int ) : Void; - - function scrollIntoView( ?alignWithTop : Bool ) : Void; - - function scrollIntoViewIfNeeded( ?centerIfNeeded : Bool ) : Void; - - function setAttribute( name : String, value : String ) : Void; - - function setAttributeNS( ?namespaceURI : String, qualifiedName : String, value : String ) : Void; - - function setAttributeNode( newAttr : Attr ) : Attr; - - function setAttributeNodeNS( newAttr : Attr ) : Attr; - -} +} \ No newline at end of file diff --git a/std/js/html/ElementRegistrationOptions.hx b/std/js/html/ElementRegistrationOptions.hx new file mode 100644 index 0000000000000000000000000000000000000000..a415bfa1dced82072c29c2d6b6e06930a52c2507 --- /dev/null +++ b/std/js/html/ElementRegistrationOptions.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/WebComponents.webidl line 25:0. Do not edit! + +package js.html; + +typedef ElementRegistrationOptions = +{ + @:native("extends") + @:optional var extends_ : String; + @:optional var prototype : Dynamic; +} \ No newline at end of file diff --git a/std/js/html/EmbedElement.hx b/std/js/html/EmbedElement.hx index 4495b10de567e88aa3fd1ffb216ee8896890e923..74c871bbc70844329fa38edcee851dc0e45c2629 100644 --- a/std/js/html/EmbedElement.hx +++ b/std/js/html/EmbedElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,42 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLEmbedElement.webidl line 17:0. Do not edit! + package js.html; -/** Note: This topic describes the HTMLEmbedElement interface as defined in the HTML5 standard. It does not address earlier, non-standardized version of the interface.

-Documentation for this class was provided by MDN. */ @:native("HTMLEmbedElement") extern class EmbedElement extends Element { - var align : String; - - /** Reflects the - -height - HTML attribute, containing the displayed height of the resource. */ - var height : String; - - var name : String; - - /** Reflects the - -src - HTML attribute, containing the address of the resource. */ var src : String; - - /** Reflects the - -type - HTML attribute, containing the type of the resource. */ var type : String; - - /** Reflects the - -width - HTML attribute, containing the displayed width of the resource. */ var width : String; - - function getSVGDocument() : js.html.svg.Document; - -} + var height : String; + var align : String; + var name : String; + + function getSVGDocument() : HTMLDocument; +} \ No newline at end of file diff --git a/std/js/html/EntityReference.hx b/std/js/html/EntityReference.hx deleted file mode 100644 index 22be6de76300f8c8fac4dd79d1dda7b18fe1e27d..0000000000000000000000000000000000000000 --- a/std/js/html/EntityReference.hx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C)2005-2013 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. - */ - -// This file is generated, do not edit! -package js.html; - -/**

NOTE: This is not implemented in Mozilla

-

Read-only reference to an entity reference in the DOM tree. Has no properties or methods of its own but inherits from Node.



-Documentation for this class was provided by MDN. */ -@:native("EntityReference") -extern class EntityReference extends Node -{ -} diff --git a/std/js/html/ErrorEvent.hx b/std/js/html/ErrorEvent.hx index 40927cf0f82b81a6bd7c345dc7219f5baafae4c3..a45691563c3769fbb48618f415e6fdcb7875cfcd 100644 --- a/std/js/html/ErrorEvent.hx +++ b/std/js/html/ErrorEvent.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/ErrorEvent.webidl line 8:0. Do not edit! + package js.html; @:native("ErrorEvent") extern class ErrorEvent extends Event { + var message(default,null) : String; var filename(default,null) : String; - var lineno(default,null) : Int; - - var message(default,null) : String; - - function new(type : String, canBubble : Bool = true, cancelable : Bool = true) : Void; - -} + var colno(default,null) : Int; + var error(default,null) : Dynamic; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : ErrorEventInit ) : Void; +} \ No newline at end of file diff --git a/std/js/html/ErrorEventInit.hx b/std/js/html/ErrorEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..4dc08a6a01f69dc3a5221d0a6261c3f7ccfb2698 --- /dev/null +++ b/std/js/html/ErrorEventInit.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/ErrorEvent.webidl line 17:0. Do not edit! + +package js.html; + +typedef ErrorEventInit = +{ + > EventInit, + @:optional var colno : Int; + @:optional var error : Dynamic; + @:optional var filename : String; + @:optional var lineno : Int; + @:optional var message : String; +} \ No newline at end of file diff --git a/std/js/html/Event.hx b/std/js/html/Event.hx index 54411f1f83bd22b74329f2820f288bf0b0131ea1..d12ea0886178de5b7db8a10a4dbc1a707fa92b0d 100644 --- a/std/js/html/Event.hx +++ b/std/js/html/Event.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,97 +20,40 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Event.webidl line 15:0. Do not edit! + package js.html; -/**

This chapter describes the DOM Event Model. The Event interface itself is described, as well as the interfaces for event registration on nodes in the DOM, and event listeners, and several longer examples that show how the various event interfaces relate to one another.

-

There is an excellent diagram that clearly explains the three phases of event flow through the DOM in the DOM Level 3 Events draft.



-Documentation for this class was provided by MDN. */ @:native("Event") extern class Event { + static inline var NONE : Int = 0; + static inline var CAPTURING_PHASE : Int = 1; static inline var AT_TARGET : Int = 2; - - static inline var BLUR : Int = 8192; - static inline var BUBBLING_PHASE : Int = 3; - - static inline var CAPTURING_PHASE : Int = 1; - - static inline var CHANGE : Int = 32768; - - static inline var CLICK : Int = 64; - - static inline var DBLCLICK : Int = 128; - - static inline var DRAGDROP : Int = 2048; - - static inline var FOCUS : Int = 4096; - - static inline var KEYDOWN : Int = 256; - - static inline var KEYPRESS : Int = 1024; - - static inline var KEYUP : Int = 512; - - static inline var MOUSEDOWN : Int = 1; - - static inline var MOUSEDRAG : Int = 32; - - static inline var MOUSEMOVE : Int = 16; - - static inline var MOUSEOUT : Int = 8; - - static inline var MOUSEOVER : Int = 4; - - static inline var MOUSEUP : Int = 2; - - static inline var NONE : Int = 0; - - static inline var SELECT : Int = 16384; - - /** A boolean indicating whether the event bubbles up through the DOM or not. */ + static inline var ALT_MASK : Int = 1; + static inline var CONTROL_MASK : Int = 2; + static inline var SHIFT_MASK : Int = 4; + static inline var META_MASK : Int = 8; + + var type(default,null) : String; + var target(default,null) : EventTarget; + var currentTarget(default,null) : EventTarget; + var eventPhase(default,null) : Int; var bubbles(default,null) : Bool; - - /** A boolean indicating whether the bubbling of the event has been canceled or not. */ - var cancelBubble : Bool; - - /** A boolean indicating whether the event is cancelable. */ var cancelable(default,null) : Bool; - - var clipboardData(default,null) : Clipboard; - - /** A reference to the currently registered target for the event. */ - var currentTarget(default,null) : EventTarget; - - /** Indicates whether or not event.preventDefault() - has been called on the event. */ var defaultPrevented(default,null) : Bool; - - /** Indicates which phase of the event flow is being processed. */ - var eventPhase(default,null) : Int; - - var returnValue : Bool; - - var srcElement(default,null) : EventTarget; - - /** A reference to the target to which the event was originally dispatched. */ - var target(default,null) : EventTarget; - - /** The time that the event was created. */ - var timeStamp(default,null) : Int; - - /** The name of the event (case-insensitive). */ - var type(default,null) : String; - - function new(type : String, canBubble : Bool = true, cancelable : Bool = true) : Void; - - function initEvent( eventTypeArg : String, canBubbleArg : Bool, cancelableArg : Bool ) : Void; - - function preventDefault() : Void; - - function stopImmediatePropagation() : Void; - + var isTrusted(default,null) : Bool; + var timeStamp(default,null) : Float; + var originalTarget(default,null) : EventTarget; + var explicitOriginalTarget(default,null) : EventTarget; + + /** @throws DOMError */ + function new( type : String, ?eventInitDict : EventInit ) : Void; function stopPropagation() : Void; - -} + function stopImmediatePropagation() : Void; + function preventDefault() : Void; + /** @throws DOMError */ + function initEvent( type : String, bubbles : Bool, cancelable : Bool ) : Void; + function getPreventDefault() : Bool; +} \ No newline at end of file diff --git a/std/js/html/EventInit.hx b/std/js/html/EventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..175f7479ef61c0b1b6887846169403ab208303a0 --- /dev/null +++ b/std/js/html/EventInit.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Event.webidl line 65:0. Do not edit! + +package js.html; + +typedef EventInit = +{ + @:optional var bubbles : Bool; + @:optional var cancelable : Bool; +} \ No newline at end of file diff --git a/std/js/html/EventListener.hx b/std/js/html/EventListener.hx index c43de82b5498b9848a28ef5245dac9dc24941eb1..a6d30e6fdafafbc815180fdbf5007f62fe99a028 100644 --- a/std/js/html/EventListener.hx +++ b/std/js/html/EventListener.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,7 +20,12 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from events.webidl line 14:0. Do not edit! + package js.html; -typedef EventListener = Dynamic -> Void; \ No newline at end of file +@:native("EventListener") +extern class EventListener +{ + function handleEvent( event : Event ) : Void; +} \ No newline at end of file diff --git a/std/js/html/EventSource.hx b/std/js/html/EventSource.hx index 5048d1c744ae814b49150bb14f2e99ba57e99312..c46ef5bfca3347003fa4da4d5db8aca6b72ddbac 100644 --- a/std/js/html/EventSource.hx +++ b/std/js/html/EventSource.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,43 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/EventSource.webidl line 16:0. Do not edit! + package js.html; -/**

The EventSource interface is used to manage server-sent events. You can set the onmessage attribute to a JavaScript function to receive non-typed messages (that is, messages with no event field). You can also call addEventListener() to listen for events just like any other event source.

-

See Using server-sent events for further details.



-Documentation for this class was provided by MDN. */ @:native("EventSource") extern class EventSource extends EventTarget { - /** The connection is not being established, has been closed or there was a fatal error. */ - static inline var CLOSED : Int = 2; - - /** The connection is being established. */ static inline var CONNECTING : Int = 0; - - /** The connection is open and dispatching events. */ static inline var OPEN : Int = 1; - - var URL(default,null) : String; - - /** A JavaScript function to call when an error occurs. */ - var onerror : EventListener; - - /** A JavaScript function to call when an a message without an event field arrives. */ - var onmessage : EventListener; - - /** A JavaScript function to call when the connection has opened. */ - var onopen : EventListener; - - /** The state of the connection, must be one of CONNECTING, OPEN, or CLOSED. Read only. */ - var readyState(default,null) : Int; - - /** Read only. */ + static inline var CLOSED : Int = 2; + var url(default,null) : String; - - function new() : Void; - + var withCredentials(default,null) : Bool; + var readyState(default,null) : Int; + var onopen : haxe.Constraints.Function; + var onmessage : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + + /** @throws DOMError */ + function new( url : String, ?eventSourceInitDict : EventSourceInit ) : Void; function close() : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/EventSourceInit.hx b/std/js/html/EventSourceInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..44675c497670c7af3dd6b4e5ef6d7d7ba3fb6567 --- /dev/null +++ b/std/js/html/EventSourceInit.hx @@ -0,0 +1,30 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/EventSource.webidl line 35:0. Do not edit! + +package js.html; + +typedef EventSourceInit = +{ + @:optional var withCredentials : Bool; +} \ No newline at end of file diff --git a/std/js/html/EventTarget.hx b/std/js/html/EventTarget.hx index f48c628583c6141bdcee4dfd10cef162ec6fd1b9..db540ea9e5bd7d043956e52a95034dbdbf0d31d7 100644 --- a/std/js/html/EventTarget.hx +++ b/std/js/html/EventTarget.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,19 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/EventTarget.webidl line 14:0. Do not edit! + package js.html; -/** An EventTarget is a DOM interface implemented by objects that can receive DOM events and have listeners for them. The most common EventTargets are DOM elements, although other objects can be EventTargets too, for example document, window, XMLHttpRequest, and others. -

-Documentation for this class was provided by MDN. */ @:native("EventTarget") extern class EventTarget { - function addEventListener( type : String, listener : EventListener, ?useCapture : Bool ) : Void; - + /** @throws DOMError */ + @:overload( function( type : String, listener : EventListener, ?capture : Bool = false, ?wantsUntrusted : Bool ) : Void {} ) + function addEventListener( type : String, listener : haxe.Constraints.Function, ?capture : Bool = false ) : Void; + /** @throws DOMError */ + @:overload( function( type : String, listener : EventListener, ?capture : Bool = false ) : Void {} ) + function removeEventListener( type : String, listener : haxe.Constraints.Function, ?capture : Bool = false ) : Void; + /** @throws DOMError */ function dispatchEvent( event : Event ) : Bool; - - function removeEventListener( type : String, listener : EventListener, ?useCapture : Bool ) : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/svg/Exception.hx b/std/js/html/Exception.hx similarity index 71% rename from std/js/html/svg/Exception.hx rename to std/js/html/Exception.hx index e135f03399f06fceaf3796d57819c282bee738e7..1f1d7d25f104d610406279d3989f745f51aea0be 100644 --- a/std/js/html/svg/Exception.hx +++ b/std/js/html/Exception.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,24 +20,21 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html.svg; +// This file is generated from mozilla/DOMException.webidl line 67:0. Do not edit! -@:native("SVGException") +package js.html; + +@:native("Exception") extern class Exception { - static inline var SVG_INVALID_VALUE_ERR : Int = 1; - - static inline var SVG_MATRIX_NOT_INVERTABLE : Int = 2; - - static inline var SVG_WRONG_TYPE_ERR : Int = 0; - - var code(default,null) : Int; - var message(default,null) : String; - + var result(default,null) : Int; var name(default,null) : String; - - function toString() : String; - -} + var filename(default,null) : String; + var lineNumber(default,null) : Int; + var columnNumber(default,null) : Int; + var inner(default,null) : Dynamic/*MISSING nsISupports*/; + var data(default,null) : Dynamic/*MISSING nsISupports*/; + var stack(default,null) : String; + +} \ No newline at end of file diff --git a/std/js/html/PagePopupController.hx b/std/js/html/External.hx similarity index 72% rename from std/js/html/PagePopupController.hx rename to std/js/html/External.hx index f92b6bf3a020227ce5aa3fd313f592ffd2016948..be776ca82a2837f12daf12bdd8cf9c6112416ff3 100644 --- a/std/js/html/PagePopupController.hx +++ b/std/js/html/External.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/External.webidl line 8:0. Do not edit! + package js.html; -@:native("PagePopupController") -extern class PagePopupController +@:native("External") +extern class External { - function formatMonth( year : Int, zeroBaseMonth : Int ) : String; - - function localizeNumberString( numberString : String ) : String; - - function setValueAndClosePopup( numberValue : Int, stringValue : String ) : Void; - -} + function AddSearchProvider( aDescriptionURL : String ) : Void; + function IsSearchProviderInstalled( aSearchURL : String ) : Int; + function addSearchEngine( engineURL : String, iconURL : String, suggestedTitle : String, suggestedCategory : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/FieldSetElement.hx b/std/js/html/FieldSetElement.hx index bb700a1a8bfe32df9e0ca808cb186eeeaa21a930..64c7c900cc383b3b2be87caff73e378bf6a0eaaf 100644 --- a/std/js/html/FieldSetElement.hx +++ b/std/js/html/FieldSetElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,49 +20,22 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLFieldSetElement.webidl line 14:0. Do not edit! + package js.html; -/** DOM fieldset elements expose the HTMLFieldSetElement  ( -HTML 4 HTMLFieldSetElement) interface, which provides special properties and methods (beyond the regular element object interface they also have available to them by inheritance) for manipulating the layout and presentation of field-set elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLFieldSetElement") extern class FieldSetElement extends Element { - /** Reflects the - -disabled - HTML attribute, indicating whether the user can interact with the control. */ var disabled : Bool; - - /** The elements belonging to this field set. */ - var elements(default,null) : HTMLCollection; - - /** The containing form element, if this element is in a form. Otherwise, the element the name content attribute points to -HTML5. (null in -HTML 4.) */ var form(default,null) : FormElement; - - /** Reflects the - -name - HTML attribute, containing the name of the field set, used for submitting the form. */ var name : String; - - /** Must be the string fieldset. */ var type(default,null) : String; - - /** A localized message that describes the validation constraints that the element does not satisfy (if any). This is the empty string if the element  is not a candidate for constraint validation (willValidate is false), or it satisfies its constraints. */ - var validationMessage(default,null) : String; - - /** The validity states that this element is in. */ - var validity(default,null) : ValidityState; - - /** Always false because fieldset objects are never candidates for constraint validation. */ + var elements(default,null) : HTMLCollection; var willValidate(default,null) : Bool; - + var validity(default,null) : ValidityState; + var validationMessage(default,null) : String; + function checkValidity() : Bool; - function setCustomValidity( error : String ) : Void; - -} +} \ No newline at end of file diff --git a/std/js/html/File.hx b/std/js/html/File.hx index c17c43f4c1b8136cb725a17e611f6ddd23a0875b..ac1433cf70276fbacb2056a0e71a9791580f883f 100644 --- a/std/js/html/File.hx +++ b/std/js/html/File.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,33 +20,20 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/File.webidl line 18:0. Do not edit! + package js.html; -/**

The File object provides information about -- and access to the contents of -- files. These are generally retrieved from a FileList - object returned as a result of a user selecting files using the input element, or from a drag and drop operation's DataTransfer object.

-
-

-

Gecko 2.0 note
(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) -
-

-

Starting in Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) -, the File object inherits from the Blob - interface, which provides methods and properties providing further information about the file.

-
-

The file reference can be saved when the form is submitted while the user is offline, so that the data can be retrieved and uploaded when the Internet connection is restored.

-
Note: The File object as implemented by Gecko offers several non-standard methods for reading the contents of the file. These should not be used, as they will prevent your web application from being used in other browsers, as well as in future versions of Gecko, which will likely remove these methods.


-Documentation for this class was provided by MDN. */ @:native("File") extern class File extends Blob { - var lastModifiedDate(default,null) : Date; - - /** The name of the file referenced by the File object. Read only. -Requires Gecko 1.9.2 */ var name(default,null) : String; - - var relativePath(default,null) : String; - -} + var lastModified(default,null) : Int; + var lastModifiedDate(default,null) : Date; + + /** @throws DOMError */ + @:overload( function( fileBits : Array>>>, fileName : String, ?options : FilePropertyBag ) : Void {} ) + @:overload( function( fileBits : Blob, ?options : ChromeFilePropertyBag ) : Void {} ) + @:overload( function( fileBits : Dynamic/*MISSING nsIFile*/, ?options : ChromeFilePropertyBag ) : Void {} ) + function new( fileBits : String, ?options : ChromeFilePropertyBag ) : Void; +} \ No newline at end of file diff --git a/std/js/html/FileList.hx b/std/js/html/FileList.hx index 729fdace54756337bf2d4fda3bb0746350911870..c5d0fa6918361357c31bc9a139dde4669d5e0c83 100644 --- a/std/js/html/FileList.hx +++ b/std/js/html/FileList.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,20 +20,14 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! -package js.html; +// This file is generated from mozilla/FileList.webidl line 13:0. Do not edit! -/**

An object of this type is returned by the files property of the HTML input element; this lets you access the list of files selected with the <input type="file"> element. It's also used for a list of files dropped into web content when using the drag and drop API; see the DataTransfer object for details on this usage.

-

+package js.html; -

Gecko 1.9.2 note

Prior to Gecko 1.9.2, the input element only supported a single file being selected at a time, meaning that the FileList would contain only one file. Starting with Gecko 1.9.2, if the input element's multiple attribute is true, the FileList may contain multiple files.



-Documentation for this class was provided by MDN. */ @:native("FileList") extern class FileList implements ArrayAccess { - /** A read-only value indicating the number of files in the list. */ var length(default,null) : Int; - + function item( index : Int ) : File; - -} +} \ No newline at end of file diff --git a/std/cs/system/io/FileMode.hx b/std/js/html/FileMode.hx similarity index 82% rename from std/cs/system/io/FileMode.hx rename to std/js/html/FileMode.hx index dba77f74470804ad3043b555691467b49babf326..f155194467027a12f28c0dccc04537af37a04c9a 100644 --- a/std/cs/system/io/FileMode.hx +++ b/std/js/html/FileMode.hx @@ -1,32 +1,31 @@ -/* - * Copyright (C)2005-2012 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 cs.system.io; - -@:native('System.IO.FileMode') extern enum FileMode -{ - CreateNew; - Create; - Open; - OpenOrCreate; - Truncate; - Append; +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FileMode.webidl line 5:0. Do not edit! + +package js.html; + +@:enum abstract FileMode(String) +{ + var READONLY = "readonly"; + var READWRITE = "readwrite"; } \ No newline at end of file diff --git a/std/js/html/FilePropertyBag.hx b/std/js/html/FilePropertyBag.hx new file mode 100644 index 0000000000000000000000000000000000000000..1bf53d50f5a2bd2730a5a08bff7f8f7ff21bc494 --- /dev/null +++ b/std/js/html/FilePropertyBag.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/File.webidl line 28:0. Do not edit! + +package js.html; + +typedef FilePropertyBag = +{ + @:optional var lastModified : Int; + @:optional var type : String; +} \ No newline at end of file diff --git a/std/js/html/FileReader.hx b/std/js/html/FileReader.hx index 168f7ff151e1fba211c222c35f9ac1ccba62f3d8..f61213e0b60b2f8b14f57962f9d0f8dcd5ddc42f 100644 --- a/std/js/html/FileReader.hx +++ b/std/js/html/FileReader.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,68 +20,37 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/FileReader.webidl line 14:0. Do not edit! + package js.html; -/**

The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File - or Blob - objects to specify the file or data to read. File objects may be obtained in one of two ways: from a FileList - object returned as a result of a user selecting files using the <input> - element, or from a drag and drop operation's DataTransfer object.

-

To create a FileReader, simply do the following:

-
var reader = new FileReader();
-
-

See Using files from web applications for details and examples.



-Documentation for this class was provided by MDN. */ @:native("FileReader") extern class FileReader extends EventTarget { - /** The entire read request has been completed. */ - static inline var DONE : Int = 2; - - /** No data has been loaded yet. */ static inline var EMPTY : Int = 0; - - /** Data is currently being loaded. */ static inline var LOADING : Int = 1; - - /** The error that occurred while reading the file. Read only. */ - var error(default,null) : js.html.fs.FileError; - - /** Called when the read operation is aborted. */ - var onabort : EventListener; - - /** Called when an error occurs. */ - var onerror : EventListener; - - /** Called when the read operation is successfully completed. */ - var onload : EventListener; - - /** Called when the read is completed, whether successful or not. This is called after either onload or onerror. */ - var onloadend : EventListener; - - /** Called when reading the data is about to begin. */ - var onloadstart : EventListener; - - /** Called periodically while the data is being read. */ - var onprogress : EventListener; - - /** Indicates the state of the FileReader. This will be one of the State constants. Read only. */ + static inline var DONE : Int = 2; + var readyState(default,null) : Int; - - /** The file's contents. This property is only valid after the read operation is complete, and the format of the data depends on which of the methods was used to initiate the read operation. Read only. */ var result(default,null) : Dynamic; - + var error(default,null) : DOMError; + var onloadstart : haxe.Constraints.Function; + var onprogress : haxe.Constraints.Function; + var onload : haxe.Constraints.Function; + var onabort : haxe.Constraints.Function; + var onerror : haxe.Constraints.Function; + var onloadend : haxe.Constraints.Function; + + /** @throws DOMError */ function new() : Void; - - function abort() : Void; - + /** @throws DOMError */ function readAsArrayBuffer( blob : Blob ) : Void; - - function readAsBinaryString( blob : Blob ) : Void; - + /** @throws DOMError */ + function readAsText( blob : Blob, ?label : String = "" ) : Void; + /** @throws DOMError */ function readAsDataURL( blob : Blob ) : Void; - - function readAsText( blob : Blob, ?encoding : String ) : Void; - -} + /** @throws DOMError */ + function abort() : Void; + /** @throws DOMError */ + function readAsBinaryString( filedata : Blob ) : Void; +} \ No newline at end of file diff --git a/std/js/html/FileReaderSync.hx b/std/js/html/FileReaderSync.hx index 3e57429e626c0c2ed669de6cf1a936e855b9fbdb..db5b9ff5338f63a69773def716be024e836a2466 100644 --- a/std/js/html/FileReaderSync.hx +++ b/std/js/html/FileReaderSync.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,21 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/FileReaderSync.webidl line 15:0. Do not edit! + package js.html; -/**

The FileReaderSync interface allows to read File or Blob objects in a synchronous way.

-

This interface is only available in workers as it enables synchronous I/O that could potentially block.



-Documentation for this class was provided by MDN. */ @:native("FileReaderSync") extern class FileReaderSync { + /** @throws DOMError */ function new() : Void; - + /** @throws DOMError */ function readAsArrayBuffer( blob : Blob ) : ArrayBuffer; - + /** @throws DOMError */ function readAsBinaryString( blob : Blob ) : String; - - function readAsDataURL( blob : Blob ) : String; - + /** @throws DOMError */ function readAsText( blob : Blob, ?encoding : String ) : String; - -} + /** @throws DOMError */ + function readAsDataURL( blob : Blob ) : String; +} \ No newline at end of file diff --git a/std/js/html/Float32Array.hx b/std/js/html/Float32Array.hx index 537e5cc7a1abb47a98f607aed07a78dc87b74924..e4a9d1f3ef0c9a5dbc88406a10e500a9ddb999da 100644 --- a/std/js/html/Float32Array.hx +++ b/std/js/html/Float32Array.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,65 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from typedarray.webidl line 179:0. Do not edit! + package js.html; -/**

The Float32Array type represents an array of 32-bit floating point numbers (corresponding to the C float data type).

-

Once established, you can reference elements in the array using the object's methods, or using standard array index syntax (that is, using bracket notation).



-Documentation for this class was provided by MDN. */ @:native("Float32Array") extern class Float32Array extends ArrayBufferView implements ArrayAccess { - /** The size, in bytes, of each array element. */ static inline var BYTES_PER_ELEMENT : Int = 4; - - /** The number of entries in the array. Read only. */ + var length(default,null) : Int; - - /**
Note: In these methods, TypedArray represents any of the typed array object types.
- -
Float32Array Float32Array(unsigned long length);
Float32Array Float32Array(TypedArray array);
Float32Array Float32Array(sequence<type> array);
Float32Array Float32Array(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length);

Returns a new Float32Array object.

-
Float32Array Float32Array(
-  unsigned long length
-);
-
-Float32Array Float32Array(
-  TypedArray array
-);
-
-Float32Array Float32Array(
-  sequence<type> array
-);
-
-Float32Array Float32Array(
-  ArrayBuffer buffer,
-  optional unsigned long byteOffset,
-  optional unsigned long length
-);
-
-
Parameters
-
length
The number of elements in the byte array. If unspecified, length of the array view will match the buffer's length.
array
An object of any of the typed array types (such as Uint8Array), or a sequence of objects of a particular type, to copy into a new ArrayBuffer. Each value in the source array is converted to a 32-bit floating point number before being copied into the new array.
buffer
An existing ArrayBuffer to use as the storage for the new Float32Array object.
byteOffset
The offset, in bytes, to the first byte in the specified buffer for the new view to reference. If not specified, the Float32Array's view of the buffer will start with the first byte.
-
-
Return value
-

A new Float32Array object representing the specified data buffer.

-
*/ - @:overload( function(length : Int) : Void {} ) - @:overload( function(array : Array) : Void {} ) - @:overload( function(array : Float32Array) : Void {} ) - function new(buffer : ArrayBuffer, ?byteOffset : Int, ?length : Int) : Void; - - /**

Sets multiple values in the typed array, reading input values from a specified array.

- -
Parameters
-
array
An array from which to copy values. All values from the source array are copied into the target array, unless the length of the source array plus the offset exceeds the length of the target array, in which case an exception is thrown. If the source array is a typed array, the two arrays may share the same underlying ArrayBuffer; the browser will intelligently copy the source range of the buffer to the destination range.
offset -Optional -
The offset into the target array at which to begin writing values from the source array. If you omit this value, 0 is assumed (that is, the source array will overwrite values in the target array starting at index 0).
-
-
*/ - @:overload( function() :Void {} ) - @:overload( function( array : Float32Array, ?offset : Int ) :Void {} ) - function set( array : Array, ?offset : Int ) : Void; - - function subarray( start : Int, ?end : Int ) : Float32Array; - -} + + /** @throws DOMError */ + @:overload( function( length : Int ) : Void {} ) + @:overload( function( array : Float32Array ) : Void {} ) + @:overload( function( array : Array ) : Void {} ) + function new( buffer : ArrayBuffer, ?byteOffset : Int, ?length : Int ) : Void; + function get( index : Int ) : Float; + @:overload( function( index : Int, value : Float ) : Void {} ) + @:overload( function( array : Float32Array, ?offset : Int ) : Void {} ) + function set( array : Array, ?offset : Int ) : Void; + function subarray( start : Int, end : Int ) : Float32Array; +} \ No newline at end of file diff --git a/std/js/html/Float64Array.hx b/std/js/html/Float64Array.hx index d7e566a3c6782d399c1edcf69f89ef10e7478a2b..bdaa6471c777bd1e4a2d9851927453bd85b91085 100644 --- a/std/js/html/Float64Array.hx +++ b/std/js/html/Float64Array.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,65 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from typedarray.webidl line 199:0. Do not edit! + package js.html; -/**

The Float64Array type represents an array of 64-bit floating point numbers (corresponding to the C double data type).

-

Once established, you can reference elements in the array using the object's methods, or using standard array index syntax (that is, using bracket notation).



-Documentation for this class was provided by MDN. */ @:native("Float64Array") extern class Float64Array extends ArrayBufferView implements ArrayAccess { - /** The size, in bytes, of each array element. */ static inline var BYTES_PER_ELEMENT : Int = 8; - - /** The number of entries in the array. Read only. */ + var length(default,null) : Int; - - /**
Note: In these methods, TypedArray represents any of the typed array object types.
- -
Float64Array Float64Array(unsigned long length);
Float64Array Float64Array(TypedArray array);
Float64Array Float64Array(sequence<type> array);
Float64Array Float64Array(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length);

Returns a new Float64Array object.

-
Float64Array Float64Array(
-  unsigned long length
-);
-
-Float64Array Float64Array(
-  TypedArray array
-);
-
-Float64Array Float64Array(
-  sequence<type> array
-);
-
-Float64Array Float64Array(
-  ArrayBuffer buffer,
-  optional unsigned long byteOffset,
-  optional unsigned long length
-);
-
-
Parameters
-
length
The number of elements in the byte array. If unspecified, length of the array view will match the buffer's length.
array
An object of any of the typed array types (such as Uint8Array), or a sequence of objects of a particular type, to copy into a new ArrayBuffer. Each value in the source array is converted to a 64-bit floating point number before being copied into the new array.
buffer
An existing ArrayBuffer to use as the storage for the new Float64Array object.
byteOffset
The offset, in bytes, to the first byte in the specified buffer for the new view to reference. If not specified, the Float64Array's view of the buffer will start with the first byte.
-
-
Return value
-

A new Float64Array object representing the specified data buffer.

-
*/ - @:overload( function(length : Int) : Void {} ) - @:overload( function(array : Array) : Void {} ) - @:overload( function(array : Float64Array) : Void {} ) - function new(buffer : ArrayBuffer, ?byteOffset : Int, ?length : Int) : Void; - - /**

Sets multiple values in the typed array, reading input values from a specified array.

- -
Parameters
-
array
An array from which to copy values. All values from the source array are copied into the target array, unless the length of the source array plus the offset exceeds the length of the target array, in which case an exception is thrown. If the source array is a typed array, the two arrays may share the same underlying ArrayBuffer; the browser will intelligently copy the source range of the buffer to the destination range.
offset -Optional -
The offset into the target array at which to begin writing values from the source array. If you omit this value, 0 is assumed (that is, the source array will overwrite values in the target array starting at index 0).
-
-
*/ - @:overload( function() :Void {} ) - @:overload( function( array : Float64Array, ?offset : Int ) :Void {} ) - function set( array : Array, ?offset : Int ) : Void; - - function subarray( start : Int, ?end : Int ) : Float64Array; - -} + + /** @throws DOMError */ + @:overload( function( length : Int ) : Void {} ) + @:overload( function( array : Float64Array ) : Void {} ) + @:overload( function( array : Array ) : Void {} ) + function new( buffer : ArrayBuffer, ?byteOffset : Int, ?length : Int ) : Void; + function get( index : Int ) : Float; + @:overload( function( index : Int, value : Float ) : Void {} ) + @:overload( function( array : Float64Array, ?offset : Int ) : Void {} ) + function set( array : Array, ?offset : Int ) : Void; + function subarray( start : Int, end : Int ) : Float64Array; +} \ No newline at end of file diff --git a/std/js/html/FocusEvent.hx b/std/js/html/FocusEvent.hx new file mode 100644 index 0000000000000000000000000000000000000000..00816de234829aca9edaa89c0f1fb75363e51714 --- /dev/null +++ b/std/js/html/FocusEvent.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FocusEvent.webidl line 14:0. Do not edit! + +package js.html; + +@:native("FocusEvent") +extern class FocusEvent extends UIEvent +{ + var relatedTarget(default,null) : EventTarget; + + /** @throws DOMError */ + function new( typeArg : String, ?focusEventInitDict : FocusEventInit ) : Void; +} \ No newline at end of file diff --git a/std/js/html/FocusEventInit.hx b/std/js/html/FocusEventInit.hx new file mode 100644 index 0000000000000000000000000000000000000000..1d50a5493d7ac77758fe0a2add2a5e731fd043cb --- /dev/null +++ b/std/js/html/FocusEventInit.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FocusEvent.webidl line 19:0. Do not edit! + +package js.html; + +typedef FocusEventInit = +{ + > UIEventInit, + @:optional var relatedTarget : EventTarget; +} \ No newline at end of file diff --git a/std/js/html/FontElement.hx b/std/js/html/FontElement.hx index a2ff3136798927507e45089862f4fc9b3f77cbc9..08104b7b172f2ccc0a0138f6b1d3d80b097db70f 100644 --- a/std/js/html/FontElement.hx +++ b/std/js/html/FontElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,25 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLFontElement.webidl line 14:0. Do not edit! + package js.html; -/** Obsolete

-Documentation for this class was provided by MDN. */ @:native("HTMLFontElement") extern class FontElement extends Element { - /** This attribute sets the text color using either a named color or a color specified in the hexadecimal #RRGGBB format. */ var color : String; - - /** This attribute contains a comma-sperated list of one or more font names. The document text in the default style is rendered in the first font face that the client's browser supports. If no font listed is installed on the local system, the browser typically defaults to the proportional or fixed-width font for that system. */ var face : String; - - /** This attribute specifies the font size as either a numeric or relative value. Numeric values range from 1 to 7 with 1 being the smallest and 3 the default. It can be defined using a relative value, like +2 or -3, which set it relative to the value of the - -size - attribute of the <basefont> - element, or relative to 3, the default value, if none does exist. */ var size : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/FontFace.hx b/std/js/html/FontFace.hx new file mode 100644 index 0000000000000000000000000000000000000000..82bff96ae2103a7172537eead39c8e0b3338cbaf --- /dev/null +++ b/std/js/html/FontFace.hx @@ -0,0 +1,44 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FontFace.webidl line 32:0. Do not edit! + +package js.html; + +@:native("FontFace") +extern class FontFace +{ + var family : String; + var style : String; + var weight : String; + var stretch : String; + var unicodeRange : String; + var variant : String; + var featureSettings : String; + var status(default,null) : FontFaceLoadStatus; + var loaded(default,null) : Promise; + + /** @throws DOMError */ + function new( family : String, source : haxe.extern.EitherType>, ?descriptors : FontFaceDescriptors ) : Void; + /** @throws DOMError */ + function load() : Promise; +} \ No newline at end of file diff --git a/std/js/html/FontFaceDescriptors.hx b/std/js/html/FontFaceDescriptors.hx new file mode 100644 index 0000000000000000000000000000000000000000..d99979c3026bd1409f353005e892a2621bd6d7cc --- /dev/null +++ b/std/js/html/FontFaceDescriptors.hx @@ -0,0 +1,35 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FontFace.webidl line 15:0. Do not edit! + +package js.html; + +typedef FontFaceDescriptors = +{ + @:optional var featureSettings : String; + @:optional var stretch : String; + @:optional var style : String; + @:optional var unicodeRange : String; + @:optional var variant : String; + @:optional var weight : String; +} \ No newline at end of file diff --git a/std/js/html/FontFaceLoadStatus.hx b/std/js/html/FontFaceLoadStatus.hx new file mode 100644 index 0000000000000000000000000000000000000000..0a0199b431a83b8c26a9ed42da127f0e93cec43c --- /dev/null +++ b/std/js/html/FontFaceLoadStatus.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FontFace.webidl line 24:0. Do not edit! + +package js.html; + +@:enum abstract FontFaceLoadStatus(String) +{ + var UNLOADED = "unloaded"; + var LOADING = "loading"; + var LOADED = "loaded"; + var ERROR = "error"; +} \ No newline at end of file diff --git a/std/js/html/StorageInfo.hx b/std/js/html/FontFaceSet.hx similarity index 59% rename from std/js/html/StorageInfo.hx rename to std/js/html/FontFaceSet.hx index 0b5aa32f6afa1fba8866426d6d1dddc3e78ece66..087b1967e4019b32d2fad21bf8706fefdaacb058 100644 --- a/std/js/html/StorageInfo.hx +++ b/std/js/html/FontFaceSet.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,27 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/FontFaceSet.webidl line 18:0. Do not edit! + package js.html; -@:native("StorageInfo") -extern class StorageInfo +@:native("FontFaceSet") +extern class FontFaceSet extends EventTarget implements ArrayAccess { - static inline var PERSISTENT : Int = 1; - - static inline var TEMPORARY : Int = 0; - - function queryUsageAndQuota( storageType : Int, ?usageCallback : StorageInfoUsageCallback, ?errorCallback : StorageInfoErrorCallback ) : Void; - - function requestQuota( storageType : Int, newQuotaInBytes : Int, ?quotaCallback : StorageInfoQuotaCallback, ?errorCallback : StorageInfoErrorCallback ) : Void; - -} + var onloading : haxe.Constraints.Function; + var onloadingdone : haxe.Constraints.Function; + var onloadingerror : haxe.Constraints.Function; + var ready(default,null) : Promise; + var status(default,null) : FontFaceSetLoadStatus; + var length(default,null) : Int; + + /** @throws DOMError */ + function add( font : FontFace ) : Void; + function has( font : FontFace ) : Bool; + /** @throws DOMError */ + @:native("delete") + function delete_( font : FontFace ) : Bool; + function clear() : Void; + /** @throws DOMError */ + function load( font : String, ?text : String = " " ) : Promise>; +} \ No newline at end of file diff --git a/std/js/html/FontFaceSetLoadStatus.hx b/std/js/html/FontFaceSetLoadStatus.hx new file mode 100644 index 0000000000000000000000000000000000000000..d395ad7fdfaab28eae97fdcf0068ac0297fb784e --- /dev/null +++ b/std/js/html/FontFaceSetLoadStatus.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FontFaceSet.webidl line 13:0. Do not edit! + +package js.html; + +@:enum abstract FontFaceSetLoadStatus(String) +{ + var LOADING = "loading"; + var LOADED = "loaded"; +} \ No newline at end of file diff --git a/std/js/html/FormData.hx b/std/js/html/FormData.hx new file mode 100644 index 0000000000000000000000000000000000000000..292f52f32137a41dbe5b00039f351aef44c061f1 --- /dev/null +++ b/std/js/html/FormData.hx @@ -0,0 +1,34 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/FormData.webidl line 11:0. Do not edit! + +package js.html; + +@:native("FormData") +extern class FormData +{ + /** @throws DOMError */ + function new( ?form : FormElement ) : Void; + @:overload( function( name : String, value : Blob, ?filename : String ) : Void {} ) + function append( name : String, value : String ) : Void; +} \ No newline at end of file diff --git a/std/js/html/FormElement.hx b/std/js/html/FormElement.hx index a1c9c86d703a549897e86154c6d7b38769124fde..68002c2e2e40dda280a1ef0a55f3293e2991f112 100644 --- a/std/js/html/FormElement.hx +++ b/std/js/html/FormElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,76 +20,27 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLFormElement.webidl line 15:0. Do not edit! + package js.html; -/**

FORM elements share all of the properties and methods of other HTML elements described in the element section.

-

This interface provides methods to create and modify FORM elements using the DOM.



-Documentation for this class was provided by MDN. */ @:native("HTMLFormElement") -extern class FormElement extends Element +extern class FormElement extends Element implements ArrayAccess { - /** Reflects the - -accept-charset - HTML attribute, containing a list of character encodings that the server accepts. */ var acceptCharset : String; - - /** Reflects the - -action - HTML attribute, containing the URI of a program that processes the information submitted by the form. */ var action : String; - - /** Reflects the - -autocomplete - HTML attribute, containing a string that indicates whether the controls in this form can have their values automatically populated by the browser. */ var autocomplete : String; - - /** All the form controls belonging to this form element. */ - var elements(default,null) : HTMLCollection; - - /** Synonym for enctype. */ - var encoding : String; - - /** Reflects the - -enctype - HTML attribute, indicating the type of content that is used to transmit the form to the server. Only specified values can be set. */ var enctype : String; - - /** The number of controls in the form. */ - var length(default,null) : Int; - - /** Reflects the - -method - HTML attribute, indicating the HTTP method used to submit the form. Only specified values can be set. */ + var encoding : String; var method : String; - - /** Reflects the - -name - HTML attribute, containing the name of the form. */ var name : String; - - /** Reflects the - -novalidate - HTML attribute, indicating that the form should not be validated. */ var noValidate : Bool; - - /** Reflects the - -target - HTML attribute, indicating where to display the results received from submitting the form. */ var target : String; - - function checkValidity() : Bool; - - function reset() : Void; - + var elements(default,null) : HTMLCollection; + var length(default,null) : Int; + + /** @throws DOMError */ function submit() : Void; - -} + function reset() : Void; + function checkValidity() : Bool; +} \ No newline at end of file diff --git a/std/js/html/FrameElement.hx b/std/js/html/FrameElement.hx index c50eba2ce78818287b97539ae63deee736d6fc6a..c4a06e8d33349c3ede3335d0c05e064261ce373e 100644 --- a/std/js/html/FrameElement.hx +++ b/std/js/html/FrameElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,46 +20,22 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLFrameElement.webidl line 14:0. Do not edit! + package js.html; -/**

<frame> is an HTML element which defines a particular area in which another HTML document can be displayed. A frame should be used within a <frameset> -.

-

Using the <frame> element is not encouraged because of certain disadvantages such as performance problems and lack of accessibility for users with screen readers. Instead of the <frame> element, <iframe> - may be preferred.



-Documentation for this class was provided by MDN. */ @:native("HTMLFrameElement") extern class FrameElement extends Element { - var contentDocument(default,null) : Document; - - var contentWindow(default,null) : DOMWindow; - + var name : String; + var scrolling : String; + var src : String; var frameBorder : String; - - var height(default,null) : Int; - - var location : String; - var longDesc : String; - + var noResize : Bool; + var contentDocument(default,null) : HTMLDocument; + var contentWindow(default,null) : Window; var marginHeight : String; - var marginWidth : String; - - /** This attribute is used to labeling frames. Without labeling all links will open in the frame that they are in. */ - var name : String; - - var noResize : Bool; - - /** This attribute defines existence of scrollbar. If this attribute is not used, browser put a scrollbar when necessary. There are two choices; "yes" for showing a scrollbar even when it is not necessary and "no" for do not showing a scrollbar even when it is necessary. */ - var scrolling : String; - - /** This attribute is specify document which will be displayed by frame. */ - var src : String; - - var width(default,null) : Int; - - function getSVGDocument() : js.html.svg.Document; - -} + +} \ No newline at end of file diff --git a/std/js/html/FrameSetElement.hx b/std/js/html/FrameSetElement.hx index e8a6e243fbb030b9e4886d05accc977513005d3a..2567d6683aa9108fd02e1302247fe16c094f07f6 100644 --- a/std/js/html/FrameSetElement.hx +++ b/std/js/html/FrameSetElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,35 +20,27 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLFrameSetElement.webidl line 14:0. Do not edit! + package js.html; -/** <frameset> is an HTML element which is used to contain <frame> - elements.

-Documentation for this class was provided by MDN. */ @:native("HTMLFrameSetElement") extern class FrameSetElement extends Element { var cols : String; - - var onbeforeunload : EventListener; - - var onhashchange : EventListener; - - var onmessage : EventListener; - - var onoffline : EventListener; - - var ononline : EventListener; - - var onpopstate : EventListener; - - var onresize : EventListener; - - var onstorage : EventListener; - - var onunload : EventListener; - var rows : String; - -} + var onafterprint : haxe.Constraints.Function; + var onbeforeprint : haxe.Constraints.Function; + var onbeforeunload : Event -> String; + var onhashchange : haxe.Constraints.Function; + var onlanguagechange : haxe.Constraints.Function; + var onmessage : haxe.Constraints.Function; + var onoffline : haxe.Constraints.Function; + var ononline : haxe.Constraints.Function; + var onpagehide : haxe.Constraints.Function; + var onpageshow : haxe.Constraints.Function; + var onpopstate : haxe.Constraints.Function; + var onresize : haxe.Constraints.Function; + var onunload : haxe.Constraints.Function; + +} \ No newline at end of file diff --git a/std/js/html/Gamepad.hx b/std/js/html/Gamepad.hx index 7599015e4565d2b1a749f3274125bff8e55dd6dc..4eea2372769b408c357608843e1c17012eb0c941 100644 --- a/std/js/html/Gamepad.hx +++ b/std/js/html/Gamepad.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,20 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Gamepad.webidl line 18:0. Do not edit! + package js.html; @:native("Gamepad") extern class Gamepad { - var axes(default,null) : Array; - - var buttons(default,null) : Array; - var id(default,null) : String; - var index(default,null) : Int; - - var timestamp(default,null) : Int; - -} + var mapping(default,null) : GamepadMappingType; + var connected(default,null) : Bool; + var buttons(default,null) : Array; + var axes(default,null) : Array; + var timestamp(default,null) : Float; + +} \ No newline at end of file diff --git a/std/js/html/GamepadButton.hx b/std/js/html/GamepadButton.hx new file mode 100644 index 0000000000000000000000000000000000000000..ee5a38052acb233d1f112e88a43388269b426016 --- /dev/null +++ b/std/js/html/GamepadButton.hx @@ -0,0 +1,33 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Gamepad.webidl line 7:0. Do not edit! + +package js.html; + +@:native("GamepadButton") +extern class GamepadButton +{ + var pressed(default,null) : Bool; + var value(default,null) : Float; + +} \ No newline at end of file diff --git a/std/js/html/GamepadMappingType.hx b/std/js/html/GamepadMappingType.hx new file mode 100644 index 0000000000000000000000000000000000000000..bb54f4265e4f23ec59423dfe1df1e7564c67e225 --- /dev/null +++ b/std/js/html/GamepadMappingType.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/Gamepad.webidl line 12:0. Do not edit! + +package js.html; + +@:enum abstract GamepadMappingType(String) +{ + var NONE = ""; + var STANDARD = "standard"; +} \ No newline at end of file diff --git a/std/js/html/Geolocation.hx b/std/js/html/Geolocation.hx index 9bc46bc6040bef4d0e41ab5418e1f4d245923d5b..6b2f6c1d6dd9ea8690cfebc4fc9def30117ca775 100644 --- a/std/js/html/Geolocation.hx +++ b/std/js/html/Geolocation.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,16 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Geolocation.webidl line 20:0. Do not edit! + package js.html; @:native("Geolocation") extern class Geolocation { + /** @throws DOMError */ + function getCurrentPosition( successCallback : Position -> Void, ?errorCallback : PositionError -> Void, ?options : PositionOptions ) : Void; + /** @throws DOMError */ + function watchPosition( successCallback : Position -> Void, ?errorCallback : PositionError -> Void, ?options : PositionOptions ) : Int; function clearWatch( watchId : Int ) : Void; - - function getCurrentPosition( successCallback : PositionCallback, ?errorCallback : PositionErrorCallback, ?options : Dynamic ) : Void; - - function watchPosition( successCallback : PositionCallback, ?errorCallback : PositionErrorCallback, ?options : Dynamic ) : Int; - -} +} \ No newline at end of file diff --git a/std/js/html/AbstractWorker.hx b/std/js/html/GetNotificationOptions.hx similarity index 85% rename from std/js/html/AbstractWorker.hx rename to std/js/html/GetNotificationOptions.hx index 3538d4d60ddcef891d53aa754db9ee83c2048470..acf2757fa0adf3ef6be08719702cc7b37c8d4293 100644 --- a/std/js/html/AbstractWorker.hx +++ b/std/js/html/GetNotificationOptions.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,12 +20,11 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/Notification.webidl line 68:0. Do not edit! + package js.html; -@:native("AbstractWorker") -extern class AbstractWorker extends EventTarget +typedef GetNotificationOptions = { - var onerror : EventListener; - -} + @:optional var tag : String; +} \ No newline at end of file diff --git a/std/js/html/GetUserMediaRequest.hx b/std/js/html/GetUserMediaRequest.hx new file mode 100644 index 0000000000000000000000000000000000000000..1c1d64b400d68040f98db45bf50e610e42abafd9 --- /dev/null +++ b/std/js/html/GetUserMediaRequest.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/GetUserMediaRequest.webidl line 10:0. Do not edit! + +package js.html; + +@:native("GetUserMediaRequest") +extern class GetUserMediaRequest +{ + var windowID(default,null) : Int; + var innerWindowID(default,null) : Int; + var callID(default,null) : String; + var isSecure(default,null) : Bool; + + function getConstraints() : MediaStreamConstraints; +} \ No newline at end of file diff --git a/std/js/html/HRElement.hx b/std/js/html/HRElement.hx index ba9a1556f491ba682642da3ae9b36c34955d6a53..459bcdd2a9fedfe04bb8eb9d9b7269ed1845e562 100644 --- a/std/js/html/HRElement.hx +++ b/std/js/html/HRElement.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,23 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLHRElement.webidl line 15:0. Do not edit! + package js.html; -/** DOM hr elements expose the HTMLHRElement (or HTML 4 HTMLHRElement) interface, which provides special properties (beyond the regular element object interface they also have available to them by inheritance) for manipulating hr elements. In HTML 5, this interface inherits from HTMLElement, but defines no additional members.

-Documentation for this class was provided by MDN. */ @:native("HTMLHRElement") extern class HRElement extends Element { - /** Enumerated attribute indicating alignment of the rule with respect to the surrounding context. */ var align : String; - + var color : String; var noShade : Bool; - - /** The height of the rule. */ var size : String; - - /** The width of the rule on the page. */ var width : String; - -} + +} \ No newline at end of file diff --git a/std/js/html/HTMLAllCollection.hx b/std/js/html/HTMLAllCollection.hx index 8d4e224c3e0a11ce274c14d55cf532f59f00b3fc..2990f2804cf69fa41a54eb75aa35beae04d00d2c 100644 --- a/std/js/html/HTMLAllCollection.hx +++ b/std/js/html/HTMLAllCollection.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,18 +20,16 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLAllCollection.webidl line 6:0. Do not edit! + package js.html; @:native("HTMLAllCollection") extern class HTMLAllCollection implements ArrayAccess { var length(default,null) : Int; - - function item( index : Int ) : Node; - - function namedItem( name : String ) : Node; - - function tags( name : String ) : NodeList; - -} + + @:overload( function( index : Int ) : Node {} ) + function item( name : String ) : haxe.extern.EitherType; + function namedItem( name : String ) : haxe.extern.EitherType; +} \ No newline at end of file diff --git a/std/js/html/HTMLCollection.hx b/std/js/html/HTMLCollection.hx index e2a705c54b817486958290d49e54b6036becce55..8f5057bcdb0c0da660e8246def461ae7657c0e08 100644 --- a/std/js/html/HTMLCollection.hx +++ b/std/js/html/HTMLCollection.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2005-2013 Haxe Foundation + * Copyright (C)2005-2015 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -20,21 +20,15 @@ * DEALINGS IN THE SOFTWARE. */ -// This file is generated, do not edit! +// This file is generated from mozilla/HTMLCollection.webidl line 13:0. Do not edit! + package js.html; -/**

HTMLCollection is an interface representing a generic collection of elements (in document order) and offers methods and properties for traversing the list.

-
Note: This interface is called HTMLCollection for historical reasons (before DOM4, collections implementing this interface could only have HTML elements as their items).
-

HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.



-Documentation for this class was provided by MDN. */ @:native("HTMLCollection") -extern class HTMLCollection implements ArrayAccess +extern class HTMLCollection implements ArrayAccess { - /** The number of items in the collection. Read only. */ var length(default,null) : Int; - - function item( index : Int ) : Node; - - function namedItem( name : String ) : Node; - -} + + function item( index : Int ) : Element; + function namedItem( name : String ) : Element; +} \ No newline at end of file diff --git a/std/js/html/HTMLDocument.hx b/std/js/html/HTMLDocument.hx new file mode 100644 index 0000000000000000000000000000000000000000..50ae5e931d6fe5da1a7aade7553ebc82127690d3 --- /dev/null +++ b/std/js/html/HTMLDocument.hx @@ -0,0 +1,206 @@ +/* + * Copyright (C)2005-2015 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. + */ + +// This file is generated from mozilla/HTMLDocument.webidl line 8:0. Do not edit! + +package js.html; + +@:native("HTMLDocument") +extern class HTMLDocument extends Document +{ + var domain : String; + var cookie : String; + var body : Element; + var head(default,null) : HeadElement; + var images(default,null) : HTMLCollection; + var embeds(default,null) : HTMLCollection; + var plugins(default,null) : HTMLCollection; + var links(default,null) : HTMLCollection; + var forms(default,null) : HTMLCollection; + var scripts(default,null) : HTMLCollection; + var designMode : String; + var fgColor : String; + var linkColor : String; + var vlinkColor : String; + var alinkColor : String; + var bgColor : String; + var anchors(default,null) : HTMLCollection; + var applets(default,null) : HTMLCollection; + var all(default,null) : HTMLAllCollection; + + function getElementsByName( elementName : String ) : NodeList; + function getItems( ?typeNames : String = "" ) : NodeList; + /** @throws DOMError */ + @:overload( function( ?type : String = "text/html", ?replace : String = "" ) : HTMLDocument {} ) + function open( url : String, name : String, features : String, ?replace : Bool = false ) : Window; + /** @throws DOMError */ + function close() : Void; + /** @throws DOMError */ + function write( text : haxe.extern.Rest ) : Void; + /** @throws DOMError */ + function writeln( text : haxe.extern.Rest ) : Void; + /** @throws DOMError */ + function execCommand( commandId : String, ?showUI : Bool = false, ?value : String = "" ) : Bool; + /** @throws DOMError */ + function queryCommandEnabled( commandId : String ) : Bool; + /** @throws DOMError */ + function queryCommandIndeterm( commandId : String ) : Bool; + /** @throws DOMError */ + function queryCommandState( commandId : String ) : Bool; + function queryCommandSupported( commandId : String ) : Bool; + /** @throws DOMError */ + function queryCommandValue( commandId : String ) : String; + function clear() : Void; + /** @throws DOMError */ + function getSelection() : Selection; + function captureEvents() : Void; + function releaseEvents() : Void; + /** Shorthand for creating an HTML element. */ + inline function createTableCellElement() : TableCellElement { return cast createElement("td"); } + /** Shorthand for creating an HTML
element. */ + inline function createHRElement() : HRElement { return cast createElement("hr"); } + /** Shorthand for creating an HTML element. */ + inline function createInputElement() : InputElement { return cast createElement("input"); } + /** Shorthand for creating an HTML element. */ + inline function createEmbedElement() : EmbedElement { return cast createElement("embed"); } + /** Shorthand for creating an HTML element. */ + inline function createMeterElement() : MeterElement { return cast createElement("meter"); } + /** Shorthand for creating an HTML element. */ + inline function createPictureElement() : PictureElement { return cast createElement("picture"); } + /** Shorthand for creating an HTML
 element. */
+	inline function createPreElement() : PreElement { return cast createElement("pre"); }
+	/** Shorthand for creating an HTML  element. */
+	inline function createTableSectionElement() : TableSectionElement { return cast createElement("thead"); }
+	/** Shorthand for creating an HTML  element. */
+	inline function createHeadElement() : HeadElement { return cast createElement("head"); }
+	/** Shorthand for creating an HTML  element. */
+	inline function createBaseElement() : BaseElement { return cast createElement("base"); }
+	/** Shorthand for creating an HTML  element. */
+	inline function createOptGroupElement() : OptGroupElement { return cast createElement("optgroup"); }
+	/** Shorthand for creating an HTML  element. */
+	inline function createQuoteElement() : QuoteElement { return cast createElement("quote"); }
+	/** Shorthand for creating an HTML